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> &params,
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