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