1 /*
2 * Copyright (C) 2016 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 #define LOG_TAG "VtsHalGraphicsMapperV2_0TargetTest"
18
19 #include <chrono>
20 #include <thread>
21 #include <vector>
22
23 #include <android-base/logging.h>
24 #include <gtest/gtest.h>
25 #include <hidl/GtestPrinter.h>
26 #include <hidl/ServiceManagement.h>
27 #include <mapper-vts/2.0/MapperVts.h>
28
29 namespace android {
30 namespace hardware {
31 namespace graphics {
32 namespace mapper {
33 namespace V2_0 {
34 namespace vts {
35 namespace {
36
37 using android::hardware::graphics::common::V1_0::BufferUsage;
38 using android::hardware::graphics::common::V1_0::PixelFormat;
39
40 class GraphicsMapperHidlTest
41 : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
42 protected:
SetUp()43 void SetUp() override {
44 ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
45 std::get<1>(GetParam())));
46
47 mDummyDescriptorInfo.width = 64;
48 mDummyDescriptorInfo.height = 64;
49 mDummyDescriptorInfo.layerCount = 1;
50 mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
51 mDummyDescriptorInfo.usage =
52 static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
53 }
54
TearDown()55 void TearDown() override {}
56
57 std::unique_ptr<Gralloc> mGralloc;
58 IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
59 };
60
61 /**
62 * Test IAllocator::dumpDebugInfo by calling it.
63 */
TEST_P(GraphicsMapperHidlTest,AllocatorDumpDebugInfo)64 TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
65 mGralloc->dumpDebugInfo();
66 }
67
68 /**
69 * Test IAllocator::allocate with valid buffer descriptors.
70 */
TEST_P(GraphicsMapperHidlTest,AllocatorAllocate)71 TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
72 BufferDescriptor descriptor;
73 ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
74
75 for (uint32_t count = 0; count < 5; count++) {
76 std::vector<const native_handle_t*> bufferHandles;
77 uint32_t stride;
78 ASSERT_NO_FATAL_FAILURE(bufferHandles =
79 mGralloc->allocate(descriptor, count, false, &stride));
80
81 if (count >= 1) {
82 EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
83 }
84
85 for (auto bufferHandle : bufferHandles) {
86 mGralloc->freeBuffer(bufferHandle);
87 }
88 }
89 }
90
91 /**
92 * Test IAllocator::allocate with invalid buffer descriptors.
93 */
TEST_P(GraphicsMapperHidlTest,AllocatorAllocateNegative)94 TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
95 // this assumes any valid descriptor is non-empty
96 BufferDescriptor descriptor;
97 mGralloc->getAllocator()->allocate(descriptor, 1,
98 [&](const auto& tmpError, const auto&, const auto&) {
99 EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
100 });
101 }
102
103 /**
104 * Test IAllocator::allocate does not leak.
105 */
TEST_P(GraphicsMapperHidlTest,AllocatorAllocateNoLeak)106 TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
107 auto info = mDummyDescriptorInfo;
108 info.width = 1024;
109 info.height = 1024;
110
111 for (int i = 0; i < 2048; i++) {
112 auto bufferHandle = mGralloc->allocate(info, false);
113 mGralloc->freeBuffer(bufferHandle);
114 }
115 }
116
117 /**
118 * Test that IAllocator::allocate is thread-safe.
119 */
TEST_P(GraphicsMapperHidlTest,AllocatorAllocateThreaded)120 TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
121 BufferDescriptor descriptor;
122 ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
123
124 std::atomic<bool> timeUp(false);
125 std::atomic<uint64_t> allocationCount(0);
126 auto threadLoop = [&]() {
127 while (!timeUp) {
128 mGralloc->getAllocator()->allocate(
129 descriptor, 1, [&](const auto&, const auto&, const auto&) { allocationCount++; });
130 }
131 };
132
133 std::vector<std::thread> threads;
134 for (int i = 0; i < 8; i++) {
135 threads.push_back(std::thread(threadLoop));
136 }
137
138 std::this_thread::sleep_for(std::chrono::seconds(3));
139 timeUp = true;
140 LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations";
141
142 for (auto& thread : threads) {
143 thread.join();
144 }
145 }
146
147 /**
148 * Test IMapper::createDescriptor with valid descriptor info.
149 */
TEST_P(GraphicsMapperHidlTest,CreateDescriptorBasic)150 TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
151 ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
152 }
153
154 /**
155 * Test IMapper::createDescriptor with invalid descriptor info.
156 */
TEST_P(GraphicsMapperHidlTest,CreateDescriptorNegative)157 TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
158 auto info = mDummyDescriptorInfo;
159 info.width = 0;
160 mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
161 EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
162 });
163 }
164
165 /**
166 * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
167 */
TEST_P(GraphicsMapperHidlTest,ImportFreeBufferBasic)168 TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
169 const native_handle_t* bufferHandle;
170 ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
171 ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
172 }
173
174 /**
175 * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
176 */
TEST_P(GraphicsMapperHidlTest,ImportFreeBufferClone)177 TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
178 const native_handle_t* clonedBufferHandle;
179 ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
180
181 // A cloned handle is a raw handle. Check that we can import it multiple
182 // times.
183 const native_handle_t* importedBufferHandles[2];
184 ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] = mGralloc->importBuffer(clonedBufferHandle));
185 ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] = mGralloc->importBuffer(clonedBufferHandle));
186 ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
187 ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));
188
189 ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
190 }
191
192 /**
193 * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
194 */
TEST_P(GraphicsMapperHidlTest,ImportFreeBufferSingleton)195 TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
196 const native_handle_t* rawHandle;
197 ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
198
199 native_handle_t* importedHandle = nullptr;
200 mGralloc->getMapper()->importBuffer(rawHandle, [&](const auto& tmpError, const auto& buffer) {
201 ASSERT_EQ(Error::NONE, tmpError);
202 importedHandle = static_cast<native_handle_t*>(buffer);
203 });
204
205 // free the imported handle with another mapper
206 std::unique_ptr<Gralloc> anotherGralloc;
207 ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
208 std::get<1>(GetParam())));
209 Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
210 ASSERT_EQ(Error::NONE, error);
211
212 ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
213 }
214
215 /**
216 * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
217 */
TEST_P(GraphicsMapperHidlTest,ImportFreeBufferNoLeak)218 TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
219 auto info = mDummyDescriptorInfo;
220 info.width = 1024;
221 info.height = 1024;
222
223 for (int i = 0; i < 2048; i++) {
224 auto bufferHandle = mGralloc->allocate(info, true);
225 mGralloc->freeBuffer(bufferHandle);
226 }
227 }
228
229 /**
230 * Test IMapper::importBuffer with invalid buffers.
231 */
TEST_P(GraphicsMapperHidlTest,ImportBufferNegative)232 TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
233 native_handle_t* invalidHandle = nullptr;
234 mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
235 EXPECT_EQ(Error::BAD_BUFFER, tmpError)
236 << "importBuffer with nullptr did not fail with BAD_BUFFER";
237 });
238
239 invalidHandle = native_handle_create(0, 0);
240 mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
241 EXPECT_EQ(Error::BAD_BUFFER, tmpError)
242 << "importBuffer with invalid handle did not fail with BAD_BUFFER";
243 });
244 native_handle_delete(invalidHandle);
245 }
246
247 /**
248 * Test IMapper::freeBuffer with invalid buffers.
249 */
TEST_P(GraphicsMapperHidlTest,FreeBufferNegative)250 TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
251 native_handle_t* invalidHandle = nullptr;
252 Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
253 EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
254
255 invalidHandle = native_handle_create(0, 0);
256 error = mGralloc->getMapper()->freeBuffer(invalidHandle);
257 EXPECT_EQ(Error::BAD_BUFFER, error)
258 << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
259 native_handle_delete(invalidHandle);
260
261 const native_handle_t* clonedBufferHandle;
262 ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
263 error = mGralloc->getMapper()->freeBuffer(invalidHandle);
264 EXPECT_EQ(Error::BAD_BUFFER, error)
265 << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
266
267 mGralloc->freeBuffer(clonedBufferHandle);
268 }
269
270 /**
271 * Test IMapper::lock and IMapper::unlock.
272 */
TEST_P(GraphicsMapperHidlTest,LockUnlockBasic)273 TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
274 const auto& info = mDummyDescriptorInfo;
275
276 const native_handle_t* bufferHandle;
277 uint32_t stride;
278 ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride));
279
280 // lock buffer for writing
281 const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
282 static_cast<int32_t>(info.height)};
283 int fence = -1;
284 uint8_t* data;
285 ASSERT_NO_FATAL_FAILURE(
286 data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
287
288 // RGBA_8888
289 size_t strideInBytes = stride * 4;
290 size_t writeInBytes = info.width * 4;
291
292 for (uint32_t y = 0; y < info.height; y++) {
293 memset(data, y, writeInBytes);
294 data += strideInBytes;
295 }
296
297 ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
298
299 // lock again for reading
300 ASSERT_NO_FATAL_FAILURE(
301 data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
302 for (uint32_t y = 0; y < info.height; y++) {
303 for (size_t i = 0; i < writeInBytes; i++) {
304 EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
305 }
306 data += strideInBytes;
307 }
308
309 ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
310 if (fence >= 0) {
311 close(fence);
312 }
313 }
314
315 /**
316 * Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can
317 * write to and read from it.
318 */
TEST_P(GraphicsMapperHidlTest,LockYCbCrBasic)319 TEST_P(GraphicsMapperHidlTest, LockYCbCrBasic) {
320 auto info = mDummyDescriptorInfo;
321 info.format = PixelFormat::YV12;
322
323 const native_handle_t* bufferHandle;
324 uint32_t stride;
325 ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride));
326
327 // lock buffer for writing
328 const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
329 static_cast<int32_t>(info.height)};
330 int fence = -1;
331 YCbCrLayout layout;
332 ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
333
334 auto yData = static_cast<uint8_t*>(layout.y);
335 auto cbData = static_cast<uint8_t*>(layout.cb);
336 auto crData = static_cast<uint8_t*>(layout.cr);
337 for (uint32_t y = 0; y < info.height; y++) {
338 for (uint32_t x = 0; x < info.width; x++) {
339 auto val = static_cast<uint8_t>(info.height * y + x);
340
341 yData[layout.yStride * y + x] = val;
342 if (y % 2 == 0 && x % 2 == 0) {
343 cbData[layout.cStride * y / 2 + x / 2] = val;
344 crData[layout.cStride * y / 2 + x / 2] = val;
345 }
346 }
347 }
348
349 ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
350
351 // lock again for reading
352 ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
353
354 yData = static_cast<uint8_t*>(layout.y);
355 cbData = static_cast<uint8_t*>(layout.cb);
356 crData = static_cast<uint8_t*>(layout.cr);
357 for (uint32_t y = 0; y < info.height; y++) {
358 for (uint32_t x = 0; x < info.width; x++) {
359 auto val = static_cast<uint8_t>(info.height * y + x);
360
361 EXPECT_EQ(val, yData[layout.yStride * y + x]);
362 if (y % 2 == 0 && x % 2 == 0) {
363 EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]);
364 EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]);
365 }
366 }
367 }
368
369 ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
370 if (fence >= 0) {
371 close(fence);
372 }
373 }
374
375 /**
376 * Test IMapper::unlock with invalid buffers.
377 */
TEST_P(GraphicsMapperHidlTest,UnlockNegative)378 TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
379 native_handle_t* invalidHandle = nullptr;
380 mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
381 EXPECT_EQ(Error::BAD_BUFFER, tmpError)
382 << "unlock with nullptr did not fail with BAD_BUFFER";
383 });
384
385 invalidHandle = native_handle_create(0, 0);
386 mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
387 EXPECT_EQ(Error::BAD_BUFFER, tmpError)
388 << "unlock with invalid handle did not fail with BAD_BUFFER";
389 });
390 native_handle_delete(invalidHandle);
391
392 ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
393 mGralloc->allocate(mDummyDescriptorInfo, false)));
394 mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
395 EXPECT_EQ(Error::BAD_BUFFER, tmpError)
396 << "unlock with un-imported handle did not fail with BAD_BUFFER";
397 });
398 mGralloc->freeBuffer(invalidHandle);
399
400 // disabled as it fails on many existing drivers
401 #if 0
402 ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
403 mGralloc->allocate(mDummyDescriptorInfo, true)));
404 mGralloc->getMapper()->unlock(
405 invalidHandle, [&](const auto& tmpError, const auto&) {
406 EXPECT_EQ(Error::BAD_BUFFER, tmpError)
407 << "unlock with unlocked handle did not fail with BAD_BUFFER";
408 });
409 mGralloc->freeBuffer(invalidHandle);
410 #endif
411 }
412
413 INSTANTIATE_TEST_CASE_P(
414 PerInstance, GraphicsMapperHidlTest,
415 testing::Combine(
416 testing::ValuesIn(
417 android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
418 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
419 android::hardware::PrintInstanceTupleNameToString<>);
420
421 } // namespace
422 } // namespace vts
423 } // namespace V2_0
424 } // namespace mapper
425 } // namespace graphics
426 } // namespace hardware
427 } // namespace android
428