Home | History | Annotate | Download | only in gralloc
      1 /*
      2  * Copyright (C) 2017 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 "gralloc_vsoc_priv.h"
     18 
     19 #include <unistd.h>
     20 #include <string.h>
     21 #include <sys/mman.h>
     22 
     23 #include <cutils/hashmap.h>
     24 #include <hardware/gralloc.h>
     25 #include <hardware/hardware.h>
     26 #include <log/log.h>
     27 
     28 namespace {
     29 
     30 const size_t g_page_size = sysconf(_SC_PAGESIZE);
     31 
     32 struct HmLockGuard {
     33   HmLockGuard(Hashmap* map) : map_(map) {
     34     hashmapLock(map_);
     35   }
     36   ~HmLockGuard() {
     37     hashmapUnlock(map_);
     38   }
     39  private:
     40   Hashmap* map_;
     41 };
     42 
     43 int offset_hash(void* key) {
     44   return *reinterpret_cast<int*>(key);
     45 }
     46 
     47 bool offset_equals(void* key1, void* key2) {
     48   return *reinterpret_cast<int*>(key1) ==
     49          *reinterpret_cast<int*>(key2);
     50 }
     51 
     52 // Keeps track of how many times a buffer is locked in the current process.
     53 struct GrallocBuffer {
     54   void* vaddr;
     55   int ref_count;
     56   GrallocBuffer() : vaddr(NULL), ref_count(0) {}
     57 
     58   static Hashmap* mapped_buffers() {
     59     static Hashmap* mapped_buffers =
     60         hashmapCreate(19, offset_hash, offset_equals);
     61     return mapped_buffers;
     62   }
     63 };
     64 
     65 }
     66 
     67 void* reference_buffer(const vsoc_buffer_handle_t* hnd) {
     68   Hashmap* map = GrallocBuffer::mapped_buffers();
     69   HmLockGuard lock_guard(map);
     70   GrallocBuffer* buffer = reinterpret_cast<GrallocBuffer*>(
     71       hashmapGet(map, const_cast<int*>(&hnd->offset)));
     72   if (!buffer) {
     73     buffer = new GrallocBuffer();
     74     hashmapPut(map, const_cast<int*>(&hnd->offset), buffer);
     75   }
     76 
     77   if (!buffer->vaddr) {
     78     void* mapped =
     79       mmap(NULL, hnd->size, PROT_READ | PROT_WRITE, MAP_SHARED, hnd->fd, 0);
     80     if (mapped == MAP_FAILED) {
     81       ALOGE("Unable to map buffer (offset: %d, size: %d): %s",
     82             hnd->offset,
     83             hnd->size,
     84             strerror(errno));
     85       return NULL;
     86     }
     87     // Set up the guard pages. The last page is always a guard
     88     uintptr_t base = uintptr_t(mapped);
     89     uintptr_t addr = base + hnd->size - g_page_size;
     90     if (mprotect((void*)addr, g_page_size, PROT_NONE) == -1) {
     91       ALOGW("Unable to protect last page of buffer (offset: %d, size: %d): %s",
     92             hnd->offset,
     93             hnd->size,
     94             strerror(errno));
     95     }
     96     buffer->vaddr = mapped;
     97   }
     98   buffer->ref_count++;
     99   return buffer->vaddr;
    100 }
    101 
    102 int unreference_buffer(const vsoc_buffer_handle_t* hnd) {
    103   int result = 0;
    104   Hashmap* map = GrallocBuffer::mapped_buffers();
    105   HmLockGuard lock_guard(map);
    106   GrallocBuffer* buffer = reinterpret_cast<GrallocBuffer*>(
    107       hashmapGet(map, const_cast<int*>(&hnd->offset)));
    108   if (!buffer) {
    109     ALOGE("Unreferencing an unknown buffer (offset: %d, size: %d)",
    110           hnd->offset,
    111           hnd->size);
    112     return -EINVAL;
    113   }
    114   if (buffer->ref_count == 0) {
    115     ALOGE("Unbalanced reference/unreference on buffer (offset: %d, size: %d)",
    116           hnd->offset,
    117           hnd->size);
    118     return -EINVAL;
    119   }
    120   buffer->ref_count--;
    121   if (buffer->ref_count == 0) {
    122     result = munmap(buffer->vaddr, hnd->size);
    123     if (result) {
    124       ALOGE("Unable to unmap buffer (offset: %d, size: %d): %s",
    125             hnd->offset,
    126             hnd->size,
    127             strerror(errno));
    128     }
    129     buffer->vaddr = NULL;
    130   }
    131   return result;
    132 }
    133