• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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__anon367c2c860211::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__anon367c2c860211::HandleAshmem40   int ashmemFd() const { return mFds.mAshmem; }
size__anon367c2c860211::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__anon367c2c860211::AllocationDtor113   AllocationDtor(const std::shared_ptr<AllocationAshmem> &alloc)
114       : mAlloc(alloc) {}
115 
operator ()__anon367c2c860211::AllocationDtor116   void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
117 
118   const std::shared_ptr<AllocationAshmem> mAlloc;
119 };
120 
121 }
122 
init()123 void IpcMutex::init() {
124   pthread_mutexattr_t mattr;
125   pthread_mutexattr_init(&mattr);
126   pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
127   pthread_mutex_init(&lock, &mattr);
128   pthread_mutexattr_destroy(&mattr);
129 
130   pthread_condattr_t cattr;
131   pthread_condattr_init(&cattr);
132   pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
133   pthread_cond_init(&cond, &cattr);
134   pthread_condattr_destroy(&cattr);
135 }
136 
Import(void * pMutex)137 IpcMutex *IpcMutex::Import(void *pMutex) {
138   return reinterpret_cast<IpcMutex *>(pMutex);
139 }
140 
141 
allocate(const std::vector<uint8_t> & params,std::shared_ptr<BufferPoolAllocation> * alloc,size_t * allocSize)142 ResultStatus TestBufferPoolAllocator::allocate(
143     const std::vector<uint8_t> &params,
144     std::shared_ptr<BufferPoolAllocation> *alloc,
145     size_t *allocSize) {
146   Params ashmemParams;
147   memcpy(&ashmemParams, params.data(), std::min(sizeof(Params), params.size()));
148 
149   std::shared_ptr<AllocationAshmem> ashmemAlloc =
150       std::shared_ptr<AllocationAshmem>(
151           AllocationAshmem::Alloc(ashmemParams.data.capacity));
152   if (ashmemAlloc) {
153     BufferPoolAllocation *ptr = new BufferPoolAllocation(ashmemAlloc->handle());
154     if (ptr) {
155       *alloc = std::shared_ptr<BufferPoolAllocation>(ptr, AllocationDtor(ashmemAlloc));
156       if (*alloc) {
157           *allocSize = ashmemParams.data.capacity;
158           return ResultStatus::OK;
159       }
160       delete ptr;
161       return ResultStatus::NO_MEMORY;
162     }
163   }
164   return ResultStatus::CRITICAL_ERROR;
165 }
166 
compatible(const std::vector<uint8_t> & newParams,const std::vector<uint8_t> & oldParams)167 bool TestBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
168                                         const std::vector<uint8_t> &oldParams) {
169   size_t newSize = newParams.size();
170   size_t oldSize = oldParams.size();
171   if (newSize == oldSize) {
172     for (size_t i = 0; i < newSize; ++i) {
173       if (newParams[i] != oldParams[i]) {
174         return false;
175       }
176     }
177     return true;
178   }
179   return false;
180 }
181 
Fill(const native_handle_t * handle,const unsigned char val)182 bool TestBufferPoolAllocator::Fill(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|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
189 
190   if (ptr != MAP_FAILED) {
191     for (size_t i = 0; i < o->size(); ++i) {
192       ptr[i] = val;
193     }
194     munmap(ptr, o->size());
195     return true;
196   }
197   return false;
198 }
199 
Verify(const native_handle_t * handle,const unsigned char val)200 bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsigned char val) {
201   if (!HandleAshmem::isValid(handle)) {
202     return false;
203   }
204   const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
205   unsigned char *ptr = (unsigned char *)mmap(
206       NULL, o->size(), PROT_READ, MAP_SHARED, o->ashmemFd(), 0);
207 
208   if (ptr != MAP_FAILED) {
209     bool res = true;
210     for (size_t i = 0; i < o->size(); ++i) {
211       if (ptr[i] != val) {
212         res = false;
213         break;
214       }
215     }
216     munmap(ptr, o->size());
217     return res;
218   }
219   return false;
220 }
221 
MapMemoryForMutex(const native_handle_t * handle,void ** mem)222 bool TestBufferPoolAllocator::MapMemoryForMutex(const native_handle_t *handle, void **mem) {
223   if (!HandleAshmem::isValid(handle)) {
224     return false;
225   }
226   const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
227   *mem = mmap(
228       NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
229   if (*mem == MAP_FAILED || *mem == nullptr) {
230     return false;
231   }
232   return true;
233 }
234 
UnmapMemoryForMutex(void * mem)235 bool TestBufferPoolAllocator::UnmapMemoryForMutex(void *mem) {
236   munmap(mem, sizeof(IpcMutex));
237   return true;
238 }
239 
getTestAllocatorParams(std::vector<uint8_t> * params)240 void getTestAllocatorParams(std::vector<uint8_t> *params) {
241   constexpr static int kAllocationSize = 1024 * 10;
242   Params ashmemParams(kAllocationSize);
243 
244   params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
245 }
246 
getIpcMutexParams(std::vector<uint8_t> * params)247 void getIpcMutexParams(std::vector<uint8_t> *params) {
248   Params ashmemParams(sizeof(IpcMutex));
249 
250   params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
251 }
252