1 /*
2 * Copyright (C) 2018 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 #include <cutils/ashmem.h>
18 #include <sys/mman.h>
19 #include "allocator.h"
20
21 union Params {
22 struct {
23 uint32_t capacity;
24 } data;
25 uint8_t array[0];
Params()26 Params() : data{0} {}
Params(uint32_t size)27 Params(uint32_t size)
28 : data{size} {}
29 };
30
31
32 namespace {
33
34 struct HandleAshmem : public native_handle_t {
HandleAshmem__anon510085e30211::HandleAshmem35 HandleAshmem(int ashmemFd, size_t size)
36 : native_handle_t(cHeader),
37 mFds{ ashmemFd },
38 mInts{ int (size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } {}
39
ashmemFd__anon510085e30211::HandleAshmem40 int ashmemFd() const { return mFds.mAshmem; }
size__anon510085e30211::HandleAshmem41 size_t size() const {
42 return size_t(unsigned(mInts.mSizeLo))
43 | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
44 }
45
46 static bool isValid(const native_handle_t * const o);
47
48 protected:
49 struct {
50 int mAshmem;
51 } mFds;
52 struct {
53 int mSizeLo;
54 int mSizeHi;
55 int mMagic;
56 } mInts;
57
58 private:
59 enum {
60 kMagic = 'ahm\x00',
61 numFds = sizeof(mFds) / sizeof(int),
62 numInts = sizeof(mInts) / sizeof(int),
63 version = sizeof(native_handle_t)
64 };
65 const static native_handle_t cHeader;
66 };
67
68 const native_handle_t HandleAshmem::cHeader = {
69 HandleAshmem::version,
70 HandleAshmem::numFds,
71 HandleAshmem::numInts,
72 {}
73 };
74
isValid(const native_handle_t * const o)75 bool HandleAshmem::isValid(const native_handle_t * const o) {
76 if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
77 return false;
78 }
79 const HandleAshmem *other = static_cast<const HandleAshmem*>(o);
80 return other->mInts.mMagic == kMagic;
81 }
82
83 class AllocationAshmem {
84 private:
AllocationAshmem(int ashmemFd,size_t capacity,bool res)85 AllocationAshmem(int ashmemFd, size_t capacity, bool res)
86 : mHandle(ashmemFd, capacity),
87 mInit(res) {}
88
89 public:
Alloc(size_t size)90 static AllocationAshmem *Alloc(size_t size) {
91 constexpr static const char *kAllocationTag = "bufferpool_test";
92 int ashmemFd = ashmem_create_region(kAllocationTag, size);
93 return new AllocationAshmem(ashmemFd, size, ashmemFd >= 0);
94 }
95
~AllocationAshmem()96 ~AllocationAshmem() {
97 if (mInit) {
98 native_handle_close(&mHandle);
99 }
100 }
101
handle()102 const HandleAshmem *handle() {
103 return &mHandle;
104 }
105
106 private:
107 HandleAshmem mHandle;
108 bool mInit;
109 // TODO: mapping and map fd
110 };
111
112 struct AllocationDtor {
AllocationDtor__anon510085e30211::AllocationDtor113 AllocationDtor(const std::shared_ptr<AllocationAshmem> &alloc)
114 : mAlloc(alloc) {}
115
operator ()__anon510085e30211::AllocationDtor116 void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
117
118 const std::shared_ptr<AllocationAshmem> mAlloc;
119 };
120
121 }
122
123
allocate(const std::vector<uint8_t> & params,std::shared_ptr<BufferPoolAllocation> * alloc,size_t * allocSize)124 ResultStatus TestBufferPoolAllocator::allocate(
125 const std::vector<uint8_t> ¶ms,
126 std::shared_ptr<BufferPoolAllocation> *alloc,
127 size_t *allocSize) {
128 Params ashmemParams;
129 memcpy(&ashmemParams, params.data(), std::min(sizeof(Params), params.size()));
130
131 std::shared_ptr<AllocationAshmem> ashmemAlloc =
132 std::shared_ptr<AllocationAshmem>(
133 AllocationAshmem::Alloc(ashmemParams.data.capacity));
134 if (ashmemAlloc) {
135 BufferPoolAllocation *ptr = new BufferPoolAllocation(ashmemAlloc->handle());
136 if (ptr) {
137 *alloc = std::shared_ptr<BufferPoolAllocation>(ptr, AllocationDtor(ashmemAlloc));
138 if (*alloc) {
139 *allocSize = ashmemParams.data.capacity;
140 return ResultStatus::OK;
141 }
142 delete ptr;
143 return ResultStatus::NO_MEMORY;
144 }
145 }
146 return ResultStatus::CRITICAL_ERROR;
147 }
148
compatible(const std::vector<uint8_t> & newParams,const std::vector<uint8_t> & oldParams)149 bool TestBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
150 const std::vector<uint8_t> &oldParams) {
151 size_t newSize = newParams.size();
152 size_t oldSize = oldParams.size();
153 if (newSize == oldSize) {
154 for (size_t i = 0; i < newSize; ++i) {
155 if (newParams[i] != oldParams[i]) {
156 return false;
157 }
158 }
159 return true;
160 }
161 return false;
162 }
163
Fill(const native_handle_t * handle,const unsigned char val)164 bool TestBufferPoolAllocator::Fill(const native_handle_t *handle, const unsigned char val) {
165 if (!HandleAshmem::isValid(handle)) {
166 return false;
167 }
168 const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
169 unsigned char *ptr = (unsigned char *)mmap(
170 NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
171
172 if (ptr != MAP_FAILED) {
173 for (size_t i = 0; i < o->size(); ++i) {
174 ptr[i] = val;
175 }
176 munmap(ptr, o->size());
177 return true;
178 }
179 return false;
180 }
181
Verify(const native_handle_t * handle,const unsigned char val)182 bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsigned char val) {
183 if (!HandleAshmem::isValid(handle)) {
184 return false;
185 }
186 const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
187 unsigned char *ptr = (unsigned char *)mmap(
188 NULL, o->size(), PROT_READ, MAP_SHARED, o->ashmemFd(), 0);
189
190 if (ptr != MAP_FAILED) {
191 bool res = true;
192 for (size_t i = 0; i < o->size(); ++i) {
193 if (ptr[i] != val) {
194 res = false;
195 break;
196 }
197 }
198 munmap(ptr, o->size());
199 return res;
200 }
201 return false;
202 }
203
getTestAllocatorParams(std::vector<uint8_t> * params)204 void getTestAllocatorParams(std::vector<uint8_t> *params) {
205 constexpr static int kAllocationSize = 1024 * 10;
206 Params ashmemParams(kAllocationSize);
207
208 params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
209 }
210