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 "guest/vsoc/lib/gralloc_region_view.h"
18 
19 #include <common/vsoc/lib/lock_guard.h>
20 #include <log/log.h>
21 #include <sys/types.h>
22 #include <uapi/vsoc_shm.h>
23 #include <atomic>
24 
25 using vsoc::gralloc::GrallocRegionView;
26 using vsoc::layout::gralloc::BufferEntry;
27 using vsoc::layout::gralloc::GrallocBufferLayout;
28 using vsoc::layout::gralloc::GrallocManagerLayout;
29 
30 namespace {
31 template <typename T>
32 inline T gralloc_align(T val) {
33   return (val + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
34 }
35 
36 // Use the thread id to identify the original creator of a buffer.
37 inline uint32_t gralloc_owned_value() {
38   return gettid();
39 }
40 
41 }  // namespace
42 
43 bool GrallocRegionView::Open() {
44   if (!vsoc::ManagerRegionView<GrallocRegionView, GrallocManagerLayout>::Open()) {
45     return false;
46   }
47   std::shared_ptr<vsoc::RegionControl> managed_region =
48       vsoc::RegionControl::Open(
49           GrallocManagerLayout::ManagedRegion::region_name);
50   if (!managed_region) {
51     LOG_FATAL("Unable to open managed region");
52     return false;
53   }
54   offset_of_buffer_memory_ = gralloc_align<uint32_t>(
55       managed_region->region_desc().offset_of_region_data);
56   total_buffer_memory_ =
57       managed_region->region_size() - offset_of_buffer_memory_;
58 
59   // TODO(jemoreira): Handle the case of unexpected values in the region.
60   return true;
61 }
62 
63 int GrallocRegionView::AllocateBuffer(size_t size, uint32_t* begin_offset) {
64   size = gralloc_align<size_t>(size);
65   // Cache the value of buffer_count in shared memory.
66   uint32_t buffer_count_local = 0;
67   {
68     vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock);
69     buffer_count_local = data()->buffer_count;
70   }
71   // Find a free buffer entry of the appropriate size.
72   for (uint32_t idx = 0; idx < buffer_count_local; ++idx) {
73     BufferEntry& entry = data()->buffers_table[idx];
74     if (entry.owned_by == VSOC_REGION_FREE && entry.buffer_size() == size) {
75       int fd = control_->CreateFdScopedPermission(
76           GrallocManagerLayout::ManagedRegion::region_name,
77           pointer_to_region_offset(&entry.owned_by),
78           gralloc_owned_value(),
79           entry.buffer_begin,
80           entry.buffer_end);
81       if (fd >= 0) {
82         if (begin_offset) {
83           *begin_offset = entry.buffer_begin;
84         }
85         return fd;
86       }
87     }
88   }
89 
90   // We couldn't find any suitable buffer, create one
91   {
92     vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock);
93     // don't use the cached value here!!!
94     uint32_t idx = data()->buffer_count;
95     if (pointer_to_region_offset(&data()->buffers_table[idx + 1]) >
96         control_->region_size()) {
97       ALOGE(
98           "Out of memory in gralloc_manager (total: %d, used: %d, "
99           "requested: %d)",
100           static_cast<int>(control_->region_size()),
101           static_cast<int>(
102               pointer_to_region_offset(&data()->buffers_table[idx])),
103           static_cast<int>(sizeof(data()->buffers_table[idx])));
104       return -ENOMEM;
105     }
106     if (total_buffer_memory_ - data()->allocated_buffer_memory < size) {
107       ALOGE(
108           "Out of memory in gralloc_memory (total: %d, used: %d, requested: %d)",
109           static_cast<int>(total_buffer_memory_),
110           static_cast<int>(data()->allocated_buffer_memory),
111           static_cast<int>(size));
112       return -ENOMEM;
113     }
114     // Initialize the buffer entry and acquire ownership
115     // Do it before increasing buffer_count so that another thread looking for
116     // free entries doesn't find this one
117     BufferEntry& new_entry = data()->buffers_table[idx];
118     new_entry.buffer_begin =
119         offset_of_buffer_memory_ + data()->allocated_buffer_memory;
120     data()->allocated_buffer_memory += size;
121     new_entry.buffer_end = new_entry.buffer_begin + size;
122     int fd = control_->CreateFdScopedPermission(
123         GrallocManagerLayout::ManagedRegion::region_name,
124         pointer_to_region_offset(&new_entry.owned_by),
125         gralloc_owned_value(),
126         new_entry.buffer_begin,
127         new_entry.buffer_end);
128     if (fd < 0) {
129       LOG_FATAL(
130           "Unexpected error while creating fd scoped permission over "
131           "uncontested memory: %s",
132           strerror(-fd));
133       return fd;
134     }
135     // Increment buffer_count now that the entry can't be taken from us
136     data()->buffer_count++;
137     if (begin_offset) {
138       *begin_offset = new_entry.buffer_begin;
139     }
140     return fd;
141   }
142 }
143