Home | History | Annotate | Download | only in binder
      1 /*
      2  * Copyright (C) 2008 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_TAG "MemoryHeapPmem"
     18 
     19 #include <stdlib.h>
     20 #include <stdint.h>
     21 #include <unistd.h>
     22 #include <fcntl.h>
     23 #include <errno.h>
     24 #include <sys/types.h>
     25 #include <sys/stat.h>
     26 #include <sys/ioctl.h>
     27 
     28 #include <cutils/log.h>
     29 
     30 #include <binder/MemoryHeapPmem.h>
     31 #include <binder/MemoryHeapBase.h>
     32 
     33 #if HAVE_ANDROID_OS
     34 #include <linux/android_pmem.h>
     35 #endif
     36 
     37 namespace android {
     38 
     39 // ---------------------------------------------------------------------------
     40 
     41 MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
     42     : BnMemory(), mClientHeap(heap)
     43 {
     44 }
     45 
     46 MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
     47     if (mClientHeap != NULL) {
     48         mClientHeap->remove(this);
     49     }
     50 }
     51 
     52 // ---------------------------------------------------------------------------
     53 
     54 class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
     55 public:
     56     SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
     57     virtual ~SubRegionMemory();
     58     virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
     59 private:
     60     friend class MemoryHeapPmem;
     61     void revoke();
     62     size_t              mSize;
     63     ssize_t             mOffset;
     64 };
     65 
     66 SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
     67         ssize_t offset, size_t size)
     68     : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
     69 {
     70 #ifndef NDEBUG
     71     void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
     72     memset(start_ptr, 0xda, size);
     73 #endif
     74 
     75 #if HAVE_ANDROID_OS
     76     if (size > 0) {
     77         const size_t pagesize = getpagesize();
     78         size = (size + pagesize-1) & ~(pagesize-1);
     79         int our_fd = heap->heapID();
     80         struct pmem_region sub = { offset, size };
     81         int err = ioctl(our_fd, PMEM_MAP, &sub);
     82         LOGE_IF(err<0, "PMEM_MAP failed (%s), "
     83                 "mFD=%d, sub.offset=%lu, sub.size=%lu",
     84                 strerror(errno), our_fd, sub.offset, sub.len);
     85 }
     86 #endif
     87 }
     88 
     89 sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
     90 {
     91     if (offset) *offset = mOffset;
     92     if (size)   *size = mSize;
     93     return getHeap();
     94 }
     95 
     96 SubRegionMemory::~SubRegionMemory()
     97 {
     98     revoke();
     99 }
    100 
    101 
    102 void SubRegionMemory::revoke()
    103 {
    104     // NOTE: revoke() doesn't need to be protected by a lock because it
    105     // can only be called from MemoryHeapPmem::revoke(), which means
    106     // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
    107     // which means MemoryHeapPmem::revoke() wouldn't have been able to
    108     // promote() it.
    109 
    110 #if HAVE_ANDROID_OS
    111     if (mSize != 0) {
    112         const sp<MemoryHeapPmem>& heap(getHeap());
    113         int our_fd = heap->heapID();
    114         struct pmem_region sub;
    115         sub.offset = mOffset;
    116         sub.len = mSize;
    117         int err = ioctl(our_fd, PMEM_UNMAP, &sub);
    118         LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
    119                 "mFD=%d, sub.offset=%lu, sub.size=%lu",
    120                 strerror(errno), our_fd, sub.offset, sub.len);
    121         mSize = 0;
    122     }
    123 #endif
    124 }
    125 
    126 // ---------------------------------------------------------------------------
    127 
    128 MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
    129         uint32_t flags)
    130     : MemoryHeapBase()
    131 {
    132     char const * const device = pmemHeap->getDevice();
    133 #if HAVE_ANDROID_OS
    134     if (device) {
    135         int fd = open(device, O_RDWR | (flags & NO_CACHING ? O_SYNC : 0));
    136         LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
    137         if (fd >= 0) {
    138             int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
    139             if (err < 0) {
    140                 LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
    141                         strerror(errno), fd, pmemHeap->heapID());
    142                 close(fd);
    143             } else {
    144                 // everything went well...
    145                 mParentHeap = pmemHeap;
    146                 MemoryHeapBase::init(fd,
    147                         pmemHeap->getBase(),
    148                         pmemHeap->getSize(),
    149                         pmemHeap->getFlags() | flags,
    150                         device);
    151             }
    152         }
    153     }
    154 #else
    155     mParentHeap = pmemHeap;
    156     MemoryHeapBase::init(
    157             dup(pmemHeap->heapID()),
    158             pmemHeap->getBase(),
    159             pmemHeap->getSize(),
    160             pmemHeap->getFlags() | flags,
    161             device);
    162 #endif
    163 }
    164 
    165 MemoryHeapPmem::~MemoryHeapPmem()
    166 {
    167 }
    168 
    169 sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
    170 {
    171     sp<MemoryPmem> memory = createMemory(offset, size);
    172     if (memory != 0) {
    173         Mutex::Autolock _l(mLock);
    174         mAllocations.add(memory);
    175     }
    176     return memory;
    177 }
    178 
    179 sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
    180         size_t offset, size_t size)
    181 {
    182     sp<SubRegionMemory> memory;
    183     if (heapID() > 0)
    184         memory = new SubRegionMemory(this, offset, size);
    185     return memory;
    186 }
    187 
    188 status_t MemoryHeapPmem::slap()
    189 {
    190 #if HAVE_ANDROID_OS
    191     size_t size = getSize();
    192     const size_t pagesize = getpagesize();
    193     size = (size + pagesize-1) & ~(pagesize-1);
    194     int our_fd = getHeapID();
    195     struct pmem_region sub = { 0, size };
    196     int err = ioctl(our_fd, PMEM_MAP, &sub);
    197     LOGE_IF(err<0, "PMEM_MAP failed (%s), "
    198             "mFD=%d, sub.offset=%lu, sub.size=%lu",
    199             strerror(errno), our_fd, sub.offset, sub.len);
    200     return -errno;
    201 #else
    202     return NO_ERROR;
    203 #endif
    204 }
    205 
    206 status_t MemoryHeapPmem::unslap()
    207 {
    208 #if HAVE_ANDROID_OS
    209     size_t size = getSize();
    210     const size_t pagesize = getpagesize();
    211     size = (size + pagesize-1) & ~(pagesize-1);
    212     int our_fd = getHeapID();
    213     struct pmem_region sub = { 0, size };
    214     int err = ioctl(our_fd, PMEM_UNMAP, &sub);
    215     LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
    216             "mFD=%d, sub.offset=%lu, sub.size=%lu",
    217             strerror(errno), our_fd, sub.offset, sub.len);
    218     return -errno;
    219 #else
    220     return NO_ERROR;
    221 #endif
    222 }
    223 
    224 void MemoryHeapPmem::revoke()
    225 {
    226     SortedVector< wp<MemoryPmem> > allocations;
    227 
    228     { // scope for lock
    229         Mutex::Autolock _l(mLock);
    230         allocations = mAllocations;
    231     }
    232 
    233     ssize_t count = allocations.size();
    234     for (ssize_t i=0 ; i<count ; i++) {
    235         sp<MemoryPmem> memory(allocations[i].promote());
    236         if (memory != 0)
    237             memory->revoke();
    238     }
    239 }
    240 
    241 void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
    242 {
    243     Mutex::Autolock _l(mLock);
    244     mAllocations.remove(memory);
    245 }
    246 
    247 // ---------------------------------------------------------------------------
    248 }; // namespace android
    249