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 "GrallocWrapper.h"
18 
19 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
20 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
21 #include <android/hardware/graphics/allocator/4.0/IAllocator.h>
22 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
23 #include <android/hardware/graphics/mapper/2.1/IMapper.h>
24 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
25 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
26 
27 #include <utils/Log.h>
28 
29 #include <cinttypes>
30 #include <type_traits>
31 
32 using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
33 using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
34 using IAllocator4 = ::android::hardware::graphics::allocator::V4_0::IAllocator;
35 using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
36 using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
37 using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
38 using IMapper4 = ::android::hardware::graphics::mapper::V4_0::IMapper;
39 
40 using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
41 using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
42 using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
43 
44 using ::android::hardware::graphics::common::V1_0::BufferUsage;
45 using ::android::hardware::graphics::common::V1_0::PixelFormat;
46 
47 using ::android::hardware::hidl_handle;
48 using ::android::hardware::hidl_string;
49 using ::android::hardware::hidl_vec;
50 
51 namespace android {
52 
53 // Since we use the same APIs across allocator/mapper HALs but they have major
54 // version differences (meaning they are not related through inheritance), we
55 // create a common interface abstraction for the IAllocator + IMapper combination
56 // (major versions need to match in the current HALs, e.g. IAllocator 3.0 needs to
57 // be paired with IMapper 3.0, so these are tied together)
58 class IGrallocHalWrapper {
59   public:
60     virtual ~IGrallocHalWrapper() = default;
61 
62     // IAllocator
63     virtual native_handle_t* allocate(uint32_t size) = 0;
64     virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
65 
66     // IMapper
67     virtual void* lock(native_handle_t* bufferHandle) = 0;
68     virtual void unlock(native_handle_t* bufferHandle) = 0;
69 };
70 
71 namespace {
72 
failed(Error2 error)73 bool failed(Error2 error) {
74     return (error != Error2::NONE);
75 }
failed(Error3 error)76 bool failed(Error3 error) {
77     return (error != Error3::NONE);
78 }
failed(Error4 error)79 bool failed(Error4 error) {
80     return (error != Error4::NONE);
81 }
82 
83 template <typename>
84 struct FirstArg;
85 
86 // Template specialization for pointer to a non-static member function, which exposes
87 // the type of the first argument given to said function
88 template <typename ReturnType, typename ClassT, typename Arg1, typename... OtherArgs>
89 struct FirstArg<ReturnType (ClassT::*)(Arg1, OtherArgs...)> {
90     using type = Arg1;
91 };
92 
93 // Alias to FirstArg which also removes any reference type and const associated
94 template <typename T>
95 using BaseTypeOfFirstArg = typename std::remove_const<
96         typename std::remove_reference<typename FirstArg<T>::type>::type>::type;
97 
98 // Since all the type and function names are the same for the things we use across the major HAL
99 // versions, we use template magic to avoid repeating ourselves.
100 template <typename AllocatorT, typename MapperT>
101 class GrallocHalWrapper : public IGrallocHalWrapper {
102   public:
GrallocHalWrapper(const sp<AllocatorT> & allocator,const sp<MapperT> & mapper)103     GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper)
104         : mAllocator(allocator), mMapper(mapper) {
105         if (mapper->isRemote()) {
106             ALOGE("Mapper is in passthrough mode");
107         }
108     }
109 
110     virtual native_handle_t* allocate(uint32_t size) override;
111     virtual void freeBuffer(native_handle_t* bufferHandle) override;
112 
113     virtual void* lock(native_handle_t* bufferHandle) override;
114     virtual void unlock(native_handle_t* bufferHandle) override;
115 
116   private:
117     static constexpr uint64_t kBufferUsage =
118             static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
119     sp<AllocatorT> mAllocator;
120     sp<MapperT> mMapper;
121 
122     // v2.0 and v3.0 use vec<uint32_t> for BufferDescriptor, but v4.0 uses vec<uint8_t>, so use
123     // some template magic to deduce the right type based off of the first argument to allocate(),
124     // which is always the version-specific BufferDescriptor type
125     typedef BaseTypeOfFirstArg<decltype(&AllocatorT::allocate)> BufferDescriptorT;
126 
127     BufferDescriptorT getDescriptor(uint32_t size);
128     native_handle_t* importBuffer(const hidl_handle& rawHandle);
129 };
130 
131 template <typename AllocatorT, typename MapperT>
allocate(uint32_t size)132 native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
133     constexpr uint32_t kBufferCount = 1;
134     BufferDescriptorT descriptor = getDescriptor(size);
135     native_handle_t* bufferHandle = nullptr;
136 
137     auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
138         if (failed(error)) {
139             ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
140         } else if (buffers.size() != kBufferCount) {
141             ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", buffers.size(),
142                   kBufferCount);
143         } else {
144             bufferHandle = importBuffer(buffers[0]);
145         }
146     };
147 
148     mAllocator->allocate(descriptor, kBufferCount, callback);
149     return bufferHandle;
150 }
151 
152 template <typename AllocatorT, typename MapperT>
freeBuffer(native_handle_t * bufferHandle)153 void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) {
154     auto error = mMapper->freeBuffer(bufferHandle);
155     if (!error.isOk() || failed(error)) {
156         ALOGE("Failed to free buffer %p", bufferHandle);
157     }
158 }
159 
160 template <typename AllocatorT, typename MapperT>
161 typename GrallocHalWrapper<AllocatorT, MapperT>::BufferDescriptorT
getDescriptor(uint32_t size)162 GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
163     typename MapperT::BufferDescriptorInfo descriptorInfo = {
164             .width = size,
165             .height = 1,
166             .layerCount = 1,
167             .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
168             .usage = kBufferUsage,
169     };
170 
171     BufferDescriptorT descriptor;
172     auto callback = [&](auto error, const BufferDescriptorT& tmpDescriptor) {
173         if (failed(error)) {
174             ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
175         } else {
176             descriptor = tmpDescriptor;
177         }
178     };
179 
180     mMapper->createDescriptor(descriptorInfo, callback);
181     return descriptor;
182 }
183 
184 template <typename AllocatorT, typename MapperT>
importBuffer(const hidl_handle & rawHandle)185 native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer(
186         const hidl_handle& rawHandle) {
187     native_handle_t* bufferHandle = nullptr;
188 
189     mMapper->importBuffer(rawHandle, [&](auto error, void* tmpBuffer) {
190         if (failed(error)) {
191             ALOGE("Failed to import buffer %p: %" PRId32, rawHandle.getNativeHandle(),
192                   static_cast<int32_t>(error));
193         } else {
194             bufferHandle = static_cast<native_handle_t*>(tmpBuffer);
195         }
196     });
197 
198     return bufferHandle;
199 }
200 
201 template <typename AllocatorT, typename MapperT>
lock(native_handle_t * bufferHandle)202 void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) {
203     // Per the HAL, all-zeros Rect means the entire buffer
204     typename MapperT::Rect accessRegion = {};
205     hidl_handle acquireFenceHandle;  // No fence needed, already safe to lock
206 
207     void* data = nullptr;
208     mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
209                   [&](auto error, void* tmpData, ...) {  // V3/4 pass extra args we don't use
210                       if (failed(error)) {
211                           ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
212                                 static_cast<int32_t>(error));
213                       } else {
214                           data = tmpData;
215                       }
216                   });
217 
218     return data;
219 }
220 
221 template <typename AllocatorT, typename MapperT>
unlock(native_handle_t * bufferHandle)222 void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) {
223     mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
224         if (failed(error)) {
225             ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
226                   static_cast<int32_t>(error));
227         }
228     });
229 }
230 
231 }  // anonymous namespace
232 
GrallocWrapper()233 GrallocWrapper::GrallocWrapper() {
234     sp<IAllocator4> allocator4 = IAllocator4::getService();
235     sp<IMapper4> mapper4 = IMapper4::getService();
236 
237     if (allocator4 != nullptr && mapper4 != nullptr) {
238         ALOGD("Using IAllocator/IMapper v4.0");
239         mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
240                 new GrallocHalWrapper<IAllocator4, IMapper4>(allocator4, mapper4));
241     } else {
242         ALOGD("Graphics HALs 4.0 not found (allocator %d mapper %d), falling back to 3.0",
243               (allocator4 != nullptr), (mapper4 != nullptr));
244 
245         sp<IAllocator3> allocator3 = IAllocator3::getService();
246         sp<IMapper3> mapper3 = IMapper3::getService();
247 
248         if (allocator3 != nullptr && mapper3 != nullptr) {
249             mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
250                     new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
251         } else {
252             ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
253                   (allocator3 != nullptr), (mapper3 != nullptr));
254 
255             sp<IAllocator2> allocator2 = IAllocator2::getService();
256             sp<IMapper2> mapper2 = IMapper2_1::getService();
257             if (mapper2 == nullptr) {
258                 mapper2 = IMapper2::getService();
259             }
260 
261             if (allocator2 != nullptr && mapper2 != nullptr) {
262                 mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
263                         new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
264             } else {
265                 ALOGE("Couldn't open graphics HALs (2.x allocator %d mapper %d)",
266                       (allocator2 != nullptr), (mapper2 != nullptr));
267             }
268         }
269     }
270 }
271 
~GrallocWrapper()272 GrallocWrapper::~GrallocWrapper() {
273     for (auto bufferHandle : mAllocatedBuffers) {
274         mGrallocHal->unlock(bufferHandle);
275         mGrallocHal->freeBuffer(bufferHandle);
276     }
277     mAllocatedBuffers.clear();
278 }
279 
allocate(uint32_t size)280 std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
281     native_handle_t* bufferHandle = mGrallocHal->allocate(size);
282     void* buffer = nullptr;
283     if (bufferHandle) {
284         buffer = mGrallocHal->lock(bufferHandle);
285         if (buffer) {
286             mAllocatedBuffers.insert(bufferHandle);
287         } else {
288             mGrallocHal->freeBuffer(bufferHandle);
289             bufferHandle = nullptr;
290         }
291     }
292     return std::make_pair<>(bufferHandle, buffer);
293 }
294 
freeBuffer(native_handle_t * bufferHandle)295 void GrallocWrapper::freeBuffer(native_handle_t* bufferHandle) {
296     if (mAllocatedBuffers.erase(bufferHandle)) {
297         mGrallocHal->unlock(bufferHandle);
298         mGrallocHal->freeBuffer(bufferHandle);
299     }
300 }
301 
302 }  // namespace android
303