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