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_NDEBUG 0
18 #define LOG_TAG "C2AllocatorIon"
19 #include <utils/Log.h>
20
21 #include <list>
22
23 #include <ion/ion.h>
24 #include <sys/mman.h>
25 #include <unistd.h> // getpagesize, size_t, close, dup
26
27 #include <C2AllocatorIon.h>
28 #include <C2Buffer.h>
29 #include <C2Debug.h>
30 #include <C2ErrnoUtils.h>
31
32 namespace android {
33
34 namespace {
35 constexpr size_t USAGE_LRU_CACHE_SIZE = 1024;
36 }
37
38 /* size_t <=> int(lo), int(hi) conversions */
size2intLo(size_t s)39 constexpr inline int size2intLo(size_t s) {
40 return int(s & 0xFFFFFFFF);
41 }
42
size2intHi(size_t s)43 constexpr inline int size2intHi(size_t s) {
44 // cast to uint64_t as size_t may be 32 bits wide
45 return int((uint64_t(s) >> 32) & 0xFFFFFFFF);
46 }
47
ints2size(int intLo,int intHi)48 constexpr inline size_t ints2size(int intLo, int intHi) {
49 // convert in 2 stages to 64 bits as intHi may be negative
50 return size_t(unsigned(intLo)) | size_t(uint64_t(unsigned(intHi)) << 32);
51 }
52
53 /* ========================================= ION HANDLE ======================================== */
54 /**
55 * ION handle
56 *
57 * There can be only a sole ion client per process, this is captured in the ion fd that is passed
58 * to the constructor, but this should be managed by the ion buffer allocator/mapper.
59 *
60 * ion uses ion_user_handle_t for buffers. We don't store this in the native handle as
61 * it requires an ion_free to decref. Instead, we share the buffer to get an fd that also holds
62 * a refcount.
63 *
64 * This handle will not capture mapped fd-s as updating that would require a global mutex.
65 */
66
67 struct C2HandleIon : public C2Handle {
68 // ion handle owns ionFd(!) and bufferFd
C2HandleIonandroid::C2HandleIon69 C2HandleIon(int bufferFd, size_t size)
70 : C2Handle(cHeader),
71 mFds{ bufferFd },
72 mInts{ int(size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } { }
73
74 static bool isValid(const C2Handle * const o);
75
bufferFdandroid::C2HandleIon76 int bufferFd() const { return mFds.mBuffer; }
sizeandroid::C2HandleIon77 size_t size() const {
78 return size_t(unsigned(mInts.mSizeLo))
79 | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
80 }
81
82 protected:
83 struct {
84 int mBuffer; // shared ion buffer
85 } mFds;
86 struct {
87 int mSizeLo; // low 32-bits of size
88 int mSizeHi; // high 32-bits of size
89 int mMagic;
90 } mInts;
91
92 private:
93 typedef C2HandleIon _type;
94 enum {
95 kMagic = '\xc2io\x00',
96 numFds = sizeof(mFds) / sizeof(int),
97 numInts = sizeof(mInts) / sizeof(int),
98 version = sizeof(C2Handle)
99 };
100 //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
101 const static C2Handle cHeader;
102 };
103
104 const C2Handle C2HandleIon::cHeader = {
105 C2HandleIon::version,
106 C2HandleIon::numFds,
107 C2HandleIon::numInts,
108 {}
109 };
110
111 // static
isValid(const C2Handle * const o)112 bool C2HandleIon::isValid(const C2Handle * const o) {
113 if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
114 return false;
115 }
116 const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
117 return other->mInts.mMagic == kMagic;
118 }
119
120 // TODO: is the dup of an ion fd identical to ion_share?
121
122 /* ======================================= ION ALLOCATION ====================================== */
123 class C2AllocationIon : public C2LinearAllocation {
124 public:
125 /* Interface methods */
126 virtual c2_status_t map(
127 size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence,
128 void **addr /* nonnull */) override;
129 virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fenceFd) override;
130 virtual ~C2AllocationIon() override;
131 virtual const C2Handle *handle() const override;
132 virtual id_t getAllocatorId() const override;
133 virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const override;
134
135 // internal methods
136 C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
137 C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id);
138
139 c2_status_t status() const;
140
141 protected:
142 class Impl;
143 class ImplV2;
144 Impl *mImpl;
145
146 // TODO: we could make this encapsulate shared_ptr and copiable
147 C2_DO_NOT_COPY(C2AllocationIon);
148 };
149
150 class C2AllocationIon::Impl {
151 protected:
152 /**
153 * Constructs an ion allocation.
154 *
155 * \note We always create an ion allocation, even if the allocation or import fails
156 * so that we can capture the error.
157 *
158 * \param ionFd ion client (ownership transferred to created object)
159 * \param capacity size of allocation
160 * \param bufferFd buffer handle (ownership transferred to created object). Must be
161 * invalid if err is not 0.
162 * \param buffer ion buffer user handle (ownership transferred to created object). Must be
163 * invalid if err is not 0.
164 * \param err errno during buffer allocation or import
165 */
Impl(int ionFd,size_t capacity,int bufferFd,ion_user_handle_t buffer,C2Allocator::id_t id,int err)166 Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
167 : mIonFd(ionFd),
168 mHandle(bufferFd, capacity),
169 mBuffer(buffer),
170 mId(id),
171 mInit(c2_map_errno<ENOMEM, EACCES, EINVAL>(err)),
172 mMapFd(-1) {
173 if (mInit != C2_OK) {
174 // close ionFd now on error
175 if (mIonFd >= 0) {
176 close(mIonFd);
177 mIonFd = -1;
178 }
179 // C2_CHECK(bufferFd < 0);
180 // C2_CHECK(buffer < 0);
181 }
182 }
183
184 public:
185 /**
186 * Constructs an ion allocation by importing a shared buffer fd.
187 *
188 * \param ionFd ion client (ownership transferred to created object)
189 * \param capacity size of allocation
190 * \param bufferFd buffer handle (ownership transferred to created object)
191 *
192 * \return created ion allocation (implementation) which may be invalid if the
193 * import failed.
194 */
195 static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id);
196
197 /**
198 * Constructs an ion allocation by allocating an ion buffer.
199 *
200 * \param ionFd ion client (ownership transferred to created object)
201 * \param size size of allocation
202 * \param align desired alignment of allocation
203 * \param heapMask mask of heaps considered
204 * \param flags ion allocation flags
205 *
206 * \return created ion allocation (implementation) which may be invalid if the
207 * allocation failed.
208 */
209 static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
210
map(size_t offset,size_t size,C2MemoryUsage usage,C2Fence * fence,void ** addr)211 c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
212 (void)fence; // TODO: wait for fence
213 *addr = nullptr;
214 if (!mMappings.empty()) {
215 ALOGV("multiple map");
216 // TODO: technically we should return DUPLICATE here, but our block views don't
217 // actually unmap, so we end up remapping an ion buffer multiple times.
218 //
219 // return C2_DUPLICATE;
220 }
221 if (size == 0) {
222 return C2_BAD_VALUE;
223 }
224
225 int prot = PROT_NONE;
226 int flags = MAP_SHARED;
227 if (usage.expected & C2MemoryUsage::CPU_READ) {
228 prot |= PROT_READ;
229 }
230 if (usage.expected & C2MemoryUsage::CPU_WRITE) {
231 prot |= PROT_WRITE;
232 }
233
234 size_t alignmentBytes = offset % PAGE_SIZE;
235 size_t mapOffset = offset - alignmentBytes;
236 size_t mapSize = size + alignmentBytes;
237 Mapping map = { nullptr, alignmentBytes, mapSize };
238
239 c2_status_t err = mapInternal(mapSize, mapOffset, alignmentBytes, prot, flags, &(map.addr), addr);
240 if (map.addr) {
241 mMappings.push_back(map);
242 }
243 return err;
244 }
245
unmap(void * addr,size_t size,C2Fence * fence)246 c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
247 if (mMappings.empty()) {
248 ALOGD("tried to unmap unmapped buffer");
249 return C2_NOT_FOUND;
250 }
251 for (auto it = mMappings.begin(); it != mMappings.end(); ++it) {
252 if (addr != (uint8_t *)it->addr + it->alignmentBytes ||
253 size + it->alignmentBytes != it->size) {
254 continue;
255 }
256 int err = munmap(it->addr, it->size);
257 if (err != 0) {
258 ALOGD("munmap failed");
259 return c2_map_errno<EINVAL>(errno);
260 }
261 if (fence) {
262 *fence = C2Fence(); // not using fences
263 }
264 (void)mMappings.erase(it);
265 ALOGV("successfully unmapped: %d", mHandle.bufferFd());
266 return C2_OK;
267 }
268 ALOGD("unmap failed to find specified map");
269 return C2_BAD_VALUE;
270 }
271
~Impl()272 virtual ~Impl() {
273 if (!mMappings.empty()) {
274 ALOGD("Dangling mappings!");
275 for (const Mapping &map : mMappings) {
276 (void)munmap(map.addr, map.size);
277 }
278 }
279 if (mMapFd >= 0) {
280 close(mMapFd);
281 mMapFd = -1;
282 }
283 if (mInit == C2_OK) {
284 if (mBuffer >= 0) {
285 (void)ion_free(mIonFd, mBuffer);
286 }
287 native_handle_close(&mHandle);
288 }
289 if (mIonFd >= 0) {
290 close(mIonFd);
291 }
292 }
293
status() const294 c2_status_t status() const {
295 return mInit;
296 }
297
handle() const298 const C2Handle *handle() const {
299 return &mHandle;
300 }
301
getAllocatorId() const302 C2Allocator::id_t getAllocatorId() const {
303 return mId;
304 }
305
ionHandle() const306 virtual ion_user_handle_t ionHandle() const {
307 return mBuffer;
308 }
309
310 protected:
mapInternal(size_t mapSize,size_t mapOffset,size_t alignmentBytes,int prot,int flags,void ** base,void ** addr)311 virtual c2_status_t mapInternal(size_t mapSize, size_t mapOffset, size_t alignmentBytes,
312 int prot, int flags, void** base, void** addr) {
313 c2_status_t err = C2_OK;
314 if (mMapFd == -1) {
315 int ret = ion_map(mIonFd, mBuffer, mapSize, prot,
316 flags, mapOffset, (unsigned char**)base, &mMapFd);
317 ALOGV("ion_map(ionFd = %d, handle = %d, size = %zu, prot = %d, flags = %d, "
318 "offset = %zu) returned (%d)",
319 mIonFd, mBuffer, mapSize, prot, flags, mapOffset, ret);
320 if (ret) {
321 mMapFd = -1;
322 *base = *addr = nullptr;
323 err = c2_map_errno<EINVAL>(-ret);
324 } else {
325 *addr = (uint8_t *)*base + alignmentBytes;
326 }
327 } else {
328 *base = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
329 ALOGV("mmap(size = %zu, prot = %d, flags = %d, mapFd = %d, offset = %zu) "
330 "returned (%d)",
331 mapSize, prot, flags, mMapFd, mapOffset, errno);
332 if (*base == MAP_FAILED) {
333 *base = *addr = nullptr;
334 err = c2_map_errno<EINVAL>(errno);
335 } else {
336 *addr = (uint8_t *)*base + alignmentBytes;
337 }
338 }
339 return err;
340 }
341
342 int mIonFd;
343 C2HandleIon mHandle;
344 ion_user_handle_t mBuffer;
345 C2Allocator::id_t mId;
346 c2_status_t mInit;
347 int mMapFd; // only one for now
348 struct Mapping {
349 void *addr;
350 size_t alignmentBytes;
351 size_t size;
352 };
353 std::list<Mapping> mMappings;
354 };
355
356 class C2AllocationIon::ImplV2 : public C2AllocationIon::Impl {
357 public:
358 /**
359 * Constructs an ion allocation for platforms with new (ion_4.12.h) api
360 *
361 * \note We always create an ion allocation, even if the allocation or import fails
362 * so that we can capture the error.
363 *
364 * \param ionFd ion client (ownership transferred to created object)
365 * \param capacity size of allocation
366 * \param bufferFd buffer handle (ownership transferred to created object). Must be
367 * invalid if err is not 0.
368 * \param err errno during buffer allocation or import
369 */
ImplV2(int ionFd,size_t capacity,int bufferFd,C2Allocator::id_t id,int err)370 ImplV2(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id, int err)
371 : Impl(ionFd, capacity, bufferFd, -1 /*buffer*/, id, err) {
372 }
373
374 virtual ~ImplV2() = default;
375
ionHandle() const376 virtual ion_user_handle_t ionHandle() const {
377 return mHandle.bufferFd();
378 }
379
380 protected:
mapInternal(size_t mapSize,size_t mapOffset,size_t alignmentBytes,int prot,int flags,void ** base,void ** addr)381 virtual c2_status_t mapInternal(size_t mapSize, size_t mapOffset, size_t alignmentBytes,
382 int prot, int flags, void** base, void** addr) {
383 c2_status_t err = C2_OK;
384 *base = mmap(nullptr, mapSize, prot, flags, mHandle.bufferFd(), mapOffset);
385 ALOGV("mmapV2(size = %zu, prot = %d, flags = %d, mapFd = %d, offset = %zu) "
386 "returned (%d)",
387 mapSize, prot, flags, mHandle.bufferFd(), mapOffset, errno);
388 if (*base == MAP_FAILED) {
389 *base = *addr = nullptr;
390 err = c2_map_errno<EINVAL>(errno);
391 } else {
392 *addr = (uint8_t *)*base + alignmentBytes;
393 }
394 return err;
395 }
396
397 };
398
Import(int ionFd,size_t capacity,int bufferFd,C2Allocator::id_t id)399 C2AllocationIon::Impl *C2AllocationIon::Impl::Import(int ionFd, size_t capacity, int bufferFd,
400 C2Allocator::id_t id) {
401 int ret = 0;
402 if (ion_is_legacy(ionFd)) {
403 ion_user_handle_t buffer = -1;
404 ret = ion_import(ionFd, bufferFd, &buffer);
405 return new Impl(ionFd, capacity, bufferFd, buffer, id, ret);
406 } else {
407 return new ImplV2(ionFd, capacity, bufferFd, id, ret);
408 }
409 }
410
Alloc(int ionFd,size_t size,size_t align,unsigned heapMask,unsigned flags,C2Allocator::id_t id)411 C2AllocationIon::Impl *C2AllocationIon::Impl::Alloc(int ionFd, size_t size, size_t align,
412 unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
413 int bufferFd = -1;
414 ion_user_handle_t buffer = -1;
415 size_t alignedSize = align == 0 ? size : (size + align - 1) & ~(align - 1);
416 int ret;
417
418 if (ion_is_legacy(ionFd)) {
419 ret = ion_alloc(ionFd, alignedSize, align, heapMask, flags, &buffer);
420 ALOGV("ion_alloc(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
421 "returned (%d) ; buffer = %d",
422 ionFd, alignedSize, align, heapMask, flags, ret, buffer);
423 if (ret == 0) {
424 // get buffer fd for native handle constructor
425 ret = ion_share(ionFd, buffer, &bufferFd);
426 if (ret != 0) {
427 ion_free(ionFd, buffer);
428 buffer = -1;
429 }
430 }
431 return new Impl(ionFd, alignedSize, bufferFd, buffer, id, ret);
432
433 } else {
434 ret = ion_alloc_fd(ionFd, alignedSize, align, heapMask, flags, &bufferFd);
435 ALOGV("ion_alloc_fd(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
436 "returned (%d) ; bufferFd = %d",
437 ionFd, alignedSize, align, heapMask, flags, ret, bufferFd);
438
439 return new ImplV2(ionFd, alignedSize, bufferFd, id, ret);
440 }
441 }
442
map(size_t offset,size_t size,C2MemoryUsage usage,C2Fence * fence,void ** addr)443 c2_status_t C2AllocationIon::map(
444 size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
445 return mImpl->map(offset, size, usage, fence, addr);
446 }
447
unmap(void * addr,size_t size,C2Fence * fence)448 c2_status_t C2AllocationIon::unmap(void *addr, size_t size, C2Fence *fence) {
449 return mImpl->unmap(addr, size, fence);
450 }
451
status() const452 c2_status_t C2AllocationIon::status() const {
453 return mImpl->status();
454 }
455
getAllocatorId() const456 C2Allocator::id_t C2AllocationIon::getAllocatorId() const {
457 return mImpl->getAllocatorId();
458 }
459
equals(const std::shared_ptr<C2LinearAllocation> & other) const460 bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
461 if (!other || other->getAllocatorId() != getAllocatorId()) {
462 return false;
463 }
464 // get user handle to compare objects
465 std::shared_ptr<C2AllocationIon> otherAsIon = std::static_pointer_cast<C2AllocationIon>(other);
466 return mImpl->ionHandle() == otherAsIon->mImpl->ionHandle();
467 }
468
handle() const469 const C2Handle *C2AllocationIon::handle() const {
470 return mImpl->handle();
471 }
472
~C2AllocationIon()473 C2AllocationIon::~C2AllocationIon() {
474 delete mImpl;
475 }
476
C2AllocationIon(int ionFd,size_t size,size_t align,unsigned heapMask,unsigned flags,C2Allocator::id_t id)477 C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align,
478 unsigned heapMask, unsigned flags, C2Allocator::id_t id)
479 : C2LinearAllocation(size),
480 mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags, id)) { }
481
C2AllocationIon(int ionFd,size_t size,int shareFd,C2Allocator::id_t id)482 C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id)
483 : C2LinearAllocation(size),
484 mImpl(Impl::Import(ionFd, size, shareFd, id)) { }
485
486 /* ======================================= ION ALLOCATOR ====================================== */
C2AllocatorIon(id_t id)487 C2AllocatorIon::C2AllocatorIon(id_t id)
488 : mInit(C2_OK),
489 mIonFd(ion_open()) {
490 if (mIonFd < 0) {
491 switch (errno) {
492 case ENOENT: mInit = C2_OMITTED; break;
493 default: mInit = c2_map_errno<EACCES>(errno); break;
494 }
495 } else {
496 C2MemoryUsage minUsage = { 0, 0 };
497 C2MemoryUsage maxUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
498 Traits traits = { "android.allocator.ion", id, LINEAR, minUsage, maxUsage };
499 mTraits = std::make_shared<Traits>(traits);
500 mBlockSize = ::getpagesize();
501 }
502 }
503
~C2AllocatorIon()504 C2AllocatorIon::~C2AllocatorIon() {
505 if (mInit == C2_OK) {
506 ion_close(mIonFd);
507 }
508 }
509
getId() const510 C2Allocator::id_t C2AllocatorIon::getId() const {
511 std::lock_guard<std::mutex> lock(mUsageMapperLock);
512 return mTraits->id;
513 }
514
getName() const515 C2String C2AllocatorIon::getName() const {
516 std::lock_guard<std::mutex> lock(mUsageMapperLock);
517 return mTraits->name;
518 }
519
getTraits() const520 std::shared_ptr<const C2Allocator::Traits> C2AllocatorIon::getTraits() const {
521 std::lock_guard<std::mutex> lock(mUsageMapperLock);
522 return mTraits;
523 }
524
setUsageMapper(const UsageMapperFn & mapper,uint64_t minUsage,uint64_t maxUsage,uint64_t blockSize)525 void C2AllocatorIon::setUsageMapper(
526 const UsageMapperFn &mapper, uint64_t minUsage, uint64_t maxUsage, uint64_t blockSize) {
527 std::lock_guard<std::mutex> lock(mUsageMapperLock);
528 mUsageMapperCache.clear();
529 mUsageMapperLru.clear();
530 mUsageMapper = mapper;
531 Traits traits = {
532 mTraits->name, mTraits->id, LINEAR,
533 C2MemoryUsage(minUsage), C2MemoryUsage(maxUsage)
534 };
535 mTraits = std::make_shared<Traits>(traits);
536 mBlockSize = blockSize;
537 }
538
operator ()(const MapperKey & k) const539 std::size_t C2AllocatorIon::MapperKeyHash::operator()(const MapperKey &k) const {
540 return std::hash<uint64_t>{}(k.first) ^ std::hash<size_t>{}(k.second);
541 }
542
mapUsage(C2MemoryUsage usage,size_t capacity,size_t * align,unsigned * heapMask,unsigned * flags)543 c2_status_t C2AllocatorIon::mapUsage(
544 C2MemoryUsage usage, size_t capacity, size_t *align, unsigned *heapMask, unsigned *flags) {
545 std::lock_guard<std::mutex> lock(mUsageMapperLock);
546 c2_status_t res = C2_OK;
547 // align capacity
548 capacity = (capacity + mBlockSize - 1) & ~(mBlockSize - 1);
549 MapperKey key = std::make_pair(usage.expected, capacity);
550 auto entry = mUsageMapperCache.find(key);
551 if (entry == mUsageMapperCache.end()) {
552 if (mUsageMapper) {
553 res = mUsageMapper(usage, capacity, align, heapMask, flags);
554 } else {
555 *align = 0; // TODO make this 1
556 *heapMask = ~0; // default mask
557 if (usage.expected & (C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE)) {
558 *flags = ION_FLAG_CACHED; // cache CPU accessed buffers
559 } else {
560 *flags = 0; // default flags
561 }
562 res = C2_NO_INIT;
563 }
564 // add usage to cache
565 MapperValue value = std::make_tuple(*align, *heapMask, *flags, res);
566 mUsageMapperLru.emplace_front(key, value);
567 mUsageMapperCache.emplace(std::make_pair(key, mUsageMapperLru.begin()));
568 if (mUsageMapperCache.size() > USAGE_LRU_CACHE_SIZE) {
569 // remove LRU entry
570 MapperKey lruKey = mUsageMapperLru.front().first;
571 mUsageMapperCache.erase(lruKey);
572 mUsageMapperLru.pop_back();
573 }
574 } else {
575 // move entry to MRU
576 mUsageMapperLru.splice(mUsageMapperLru.begin(), mUsageMapperLru, entry->second);
577 const MapperValue &value = entry->second->second;
578 std::tie(*align, *heapMask, *flags, res) = value;
579 }
580 return res;
581 }
582
newLinearAllocation(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2LinearAllocation> * allocation)583 c2_status_t C2AllocatorIon::newLinearAllocation(
584 uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
585 if (allocation == nullptr) {
586 return C2_BAD_VALUE;
587 }
588
589 allocation->reset();
590 if (mInit != C2_OK) {
591 return mInit;
592 }
593
594 size_t align = 0;
595 unsigned heapMask = ~0;
596 unsigned flags = 0;
597 c2_status_t ret = mapUsage(usage, capacity, &align, &heapMask, &flags);
598 if (ret && ret != C2_NO_INIT) {
599 return ret;
600 }
601
602 std::shared_ptr<C2AllocationIon> alloc
603 = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
604 ret = alloc->status();
605 if (ret == C2_OK) {
606 *allocation = alloc;
607 }
608 return ret;
609 }
610
priorLinearAllocation(const C2Handle * handle,std::shared_ptr<C2LinearAllocation> * allocation)611 c2_status_t C2AllocatorIon::priorLinearAllocation(
612 const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
613 *allocation = nullptr;
614 if (mInit != C2_OK) {
615 return mInit;
616 }
617
618 if (!C2HandleIon::isValid(handle)) {
619 return C2_BAD_VALUE;
620 }
621
622 // TODO: get capacity and validate it
623 const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
624 std::shared_ptr<C2AllocationIon> alloc
625 = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
626 c2_status_t ret = alloc->status();
627 if (ret == C2_OK) {
628 *allocation = alloc;
629 native_handle_delete(const_cast<native_handle_t*>(
630 reinterpret_cast<const native_handle_t*>(handle)));
631 }
632 return ret;
633 }
634
isValid(const C2Handle * const o)635 bool C2AllocatorIon::isValid(const C2Handle* const o) {
636 return C2HandleIon::isValid(o);
637 }
638
639 } // namespace android
640
641