• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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