1 /*
2 * Copyright (C) 2018 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 "VtsHalBufferHubV1_0TargetTest"
18
19 #include <VtsHalHidlTargetTestBase.h>
20 #include <android-base/logging.h>
21 #include <android/frameworks/bufferhub/1.0/IBufferClient.h>
22 #include <android/frameworks/bufferhub/1.0/IBufferHub.h>
23 #include <android/hardware_buffer.h>
24 #include <gtest/gtest.h>
25 #include <hwbinder/IPCThreadState.h>
26 #include <ui/BufferHubDefs.h>
27
28 using ::android::frameworks::bufferhub::V1_0::BufferHubStatus;
29 using ::android::frameworks::bufferhub::V1_0::BufferTraits;
30 using ::android::frameworks::bufferhub::V1_0::IBufferClient;
31 using ::android::frameworks::bufferhub::V1_0::IBufferHub;
32 using ::android::hardware::hidl_handle;
33 using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
34
35 namespace android {
36 namespace frameworks {
37 namespace bufferhub {
38 namespace vts {
39
40 // Stride is an output that unknown before allocation.
41 const AHardwareBuffer_Desc kDesc = {
42 /*width=*/640UL, /*height=*/480UL,
43 /*layers=*/1, /*format=*/AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
44 /*usage=*/0ULL, /*stride=*/0UL,
45 /*rfu0=*/0UL, /*rfu1=*/0ULL};
46 const size_t kUserMetadataSize = 1;
47
48 // Test environment for BufferHub HIDL HAL.
49 class BufferHubHidlEnv : public ::testing::VtsHalHidlTargetTestEnvBase {
50 public:
51 // get the test environment singleton
Instance()52 static BufferHubHidlEnv* Instance() {
53 static BufferHubHidlEnv* instance = new BufferHubHidlEnv;
54 return instance;
55 }
56
registerTestServices()57 void registerTestServices() override { registerTestService<IBufferHub>(); }
58
59 private:
BufferHubHidlEnv()60 BufferHubHidlEnv() {}
61 };
62
63 class HalBufferHubVts : public ::testing::VtsHalHidlTargetTestBase {
64 protected:
SetUp()65 void SetUp() override {
66 VtsHalHidlTargetTestBase::SetUp();
67
68 mBufferHub = IBufferHub::getService();
69 ASSERT_NE(nullptr, mBufferHub.get());
70 }
71
72 sp<IBufferHub> mBufferHub;
73 };
74
75 // TOOD(b/121345852): use bit_cast to unpack bufferInfo when C++20 becomes available.
clientStateMask(const BufferTraits & bufferTraits)76 uint32_t clientStateMask(const BufferTraits& bufferTraits) {
77 uint32_t clientStateMask;
78 memcpy(&clientStateMask, &bufferTraits.bufferInfo->data[3], sizeof(clientStateMask));
79 return clientStateMask;
80 }
81
82 // Helper function to verify that given bufferTrais:
83 // 1. is consistent with kDesc
84 // 2. have a non-null gralloc handle
85 // 3. have a non-null buffer info handle with:
86 // 1) metadata fd >= 0 (valid fd)
87 // 2) event fd >= 0 (valid fd)
88 // 3) buffer Id >= 0
89 // 4) client bit mask != 0
90 // 5) user metadata size = kUserMetadataSize
91 //
92 // The structure of BufferTraits.bufferInfo handle is defined in ui/BufferHubDefs.h
isValidTraits(const BufferTraits & bufferTraits)93 bool isValidTraits(const BufferTraits& bufferTraits) {
94 AHardwareBuffer_Desc desc;
95 memcpy(&desc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc));
96
97 const native_handle_t* bufferInfo = bufferTraits.bufferInfo.getNativeHandle();
98 if (bufferInfo == nullptr) {
99 return false;
100 }
101 const int metadataFd = bufferInfo->data[0];
102 const int eventFd = bufferInfo->data[1];
103 const int bufferId = bufferInfo->data[2];
104 uint32_t userMetadataSize;
105 memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[4], sizeof(userMetadataSize));
106
107 // Not comparing stride because it's unknown before allocation
108 return desc.format == kDesc.format && desc.height == kDesc.height &&
109 desc.layers == kDesc.layers && desc.usage == kDesc.usage && desc.width == kDesc.width &&
110 bufferTraits.bufferHandle.getNativeHandle() != nullptr && metadataFd >= 0 &&
111 eventFd >= 0 && bufferId >= 0 && clientStateMask(bufferTraits) != 0U &&
112 userMetadataSize == kUserMetadataSize;
113 }
114
115 // Test IBufferHub::allocateBuffer then IBufferClient::close
TEST_F(HalBufferHubVts,AllocateAndFreeBuffer)116 TEST_F(HalBufferHubVts, AllocateAndFreeBuffer) {
117 HardwareBufferDescription desc;
118 memcpy(&desc, &kDesc, sizeof(HardwareBufferDescription));
119
120 BufferHubStatus ret;
121 sp<IBufferClient> client;
122 BufferTraits bufferTraits = {};
123 IBufferHub::allocateBuffer_cb callback = [&](const auto& status, const auto& outClient,
124 const auto& traits) {
125 ret = status;
126 client = outClient;
127 bufferTraits = std::move(traits);
128 };
129 ASSERT_TRUE(mBufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
130 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
131 ASSERT_NE(nullptr, client.get());
132 EXPECT_TRUE(isValidTraits(bufferTraits));
133
134 ASSERT_EQ(BufferHubStatus::NO_ERROR, client->close());
135 EXPECT_EQ(BufferHubStatus::CLIENT_CLOSED, client->close());
136 }
137
138 // Test destroying IBufferClient without calling close
TEST_F(HalBufferHubVts,DestroyClientWithoutClose)139 TEST_F(HalBufferHubVts, DestroyClientWithoutClose) {
140 HardwareBufferDescription desc;
141 memcpy(&desc, &kDesc, sizeof(HardwareBufferDescription));
142
143 BufferHubStatus ret;
144 sp<IBufferClient> client;
145 BufferTraits bufferTraits = {};
146 IBufferHub::allocateBuffer_cb callback = [&](const auto& status, const auto& outClient,
147 const auto& traits) {
148 ret = status;
149 client = outClient;
150 bufferTraits = std::move(traits);
151 };
152 ASSERT_TRUE(mBufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
153 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
154 ASSERT_NE(nullptr, client.get());
155 EXPECT_TRUE(isValidTraits(bufferTraits));
156
157 // Not calling client->close() before destruction here intentionally to see if anything would
158 // break. User is recommended to call close() in any case.
159 client.clear();
160
161 // Flush the command to remote side, wait for 10ms, and ping service again to check if alive
162 hardware::IPCThreadState::self()->flushCommands();
163 usleep(10000);
164 ASSERT_TRUE(mBufferHub->ping().isOk());
165 }
166
167 // Test IBufferClient::duplicate after IBufferClient::close
TEST_F(HalBufferHubVts,DuplicateFreedBuffer)168 TEST_F(HalBufferHubVts, DuplicateFreedBuffer) {
169 HardwareBufferDescription desc;
170 memcpy(&desc, &kDesc, sizeof(HardwareBufferDescription));
171
172 BufferHubStatus ret;
173 sp<IBufferClient> client;
174 BufferTraits bufferTraits = {};
175 IBufferHub::allocateBuffer_cb callback = [&](const auto& status, const auto& outClient,
176 const auto& traits) {
177 ret = status;
178 client = outClient;
179 bufferTraits = std::move(traits);
180 };
181 ASSERT_TRUE(mBufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
182 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
183 ASSERT_NE(nullptr, client.get());
184 EXPECT_TRUE(isValidTraits(bufferTraits));
185
186 ASSERT_EQ(BufferHubStatus::NO_ERROR, client->close());
187
188 hidl_handle token;
189 IBufferClient::duplicate_cb dupCb = [&](const auto& outToken, const auto& status) {
190 token = outToken;
191 ret = status;
192 };
193 ASSERT_TRUE(client->duplicate(dupCb).isOk());
194 EXPECT_EQ(ret, BufferHubStatus::CLIENT_CLOSED);
195 EXPECT_EQ(token.getNativeHandle(), nullptr);
196 }
197
198 // Test normal import process using IBufferHub::import function
TEST_F(HalBufferHubVts,DuplicateAndImportBuffer)199 TEST_F(HalBufferHubVts, DuplicateAndImportBuffer) {
200 HardwareBufferDescription desc;
201 memcpy(&desc, &kDesc, sizeof(HardwareBufferDescription));
202
203 BufferHubStatus ret;
204 sp<IBufferClient> client;
205 BufferTraits bufferTraits = {};
206 IBufferHub::allocateBuffer_cb callback = [&](const auto& status, const auto& outClient,
207 const auto& traits) {
208 ret = status;
209 client = outClient;
210 bufferTraits = std::move(traits);
211 };
212 ASSERT_TRUE(mBufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
213 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
214 ASSERT_NE(nullptr, client.get());
215 EXPECT_TRUE(isValidTraits(bufferTraits));
216
217 hidl_handle token;
218 IBufferClient::duplicate_cb dupCb = [&](const auto& outToken, const auto& status) {
219 token = outToken;
220 ret = status;
221 };
222 ASSERT_TRUE(client->duplicate(dupCb).isOk());
223 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
224 ASSERT_NE(token.getNativeHandle(), nullptr);
225 EXPECT_GT(token->numInts, 1);
226 EXPECT_EQ(token->numFds, 0);
227
228 sp<IBufferClient> client2;
229 BufferTraits bufferTraits2 = {};
230 IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient,
231 const auto& traits) {
232 ret = status;
233 client2 = outClient;
234 bufferTraits2 = std::move(traits);
235 };
236 ASSERT_TRUE(mBufferHub->importBuffer(token, importCb).isOk());
237 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
238 EXPECT_NE(nullptr, client2.get());
239 EXPECT_TRUE(isValidTraits(bufferTraits2));
240
241 // Since they are two clients of one buffer, the id should be the same but client state bit mask
242 // should be different.
243 const int bufferId1 = bufferTraits.bufferInfo->data[2];
244 const int bufferId2 = bufferTraits2.bufferInfo->data[2];
245 EXPECT_EQ(bufferId1, bufferId2);
246 EXPECT_NE(clientStateMask(bufferTraits), clientStateMask(bufferTraits2));
247
248 EXPECT_EQ(BufferHubStatus::NO_ERROR, client->close());
249 EXPECT_EQ(BufferHubStatus::NO_ERROR, client2->close());
250 }
251
252 // Test calling IBufferHub::import with nullptr. Must not crash the service
TEST_F(HalBufferHubVts,ImportNullToken)253 TEST_F(HalBufferHubVts, ImportNullToken) {
254 hidl_handle nullToken;
255 BufferHubStatus ret;
256 sp<IBufferClient> client;
257 BufferTraits bufferTraits = {};
258 IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient,
259 const auto& traits) {
260 ret = status;
261 client = outClient;
262 bufferTraits = std::move(traits);
263 };
264 ASSERT_TRUE(mBufferHub->importBuffer(nullToken, importCb).isOk());
265 EXPECT_EQ(ret, BufferHubStatus::INVALID_TOKEN);
266 EXPECT_EQ(nullptr, client.get());
267 EXPECT_FALSE(isValidTraits(bufferTraits));
268 }
269
270 // Test calling IBufferHub::import with an nonexistant token.
TEST_F(HalBufferHubVts,ImportInvalidToken)271 TEST_F(HalBufferHubVts, ImportInvalidToken) {
272 native_handle_t* tokenHandle = native_handle_create(/*numFds=*/0, /*numInts=*/2);
273 tokenHandle->data[0] = 0;
274 // Assign a random number since we cannot know the HMAC value.
275 tokenHandle->data[1] = 42;
276
277 hidl_handle invalidToken(tokenHandle);
278 BufferHubStatus ret;
279 sp<IBufferClient> client;
280 BufferTraits bufferTraits = {};
281 IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient,
282 const auto& traits) {
283 ret = status;
284 client = outClient;
285 bufferTraits = std::move(traits);
286 };
287 ASSERT_TRUE(mBufferHub->importBuffer(invalidToken, importCb).isOk());
288 EXPECT_EQ(ret, BufferHubStatus::INVALID_TOKEN);
289 EXPECT_EQ(nullptr, client.get());
290 EXPECT_FALSE(isValidTraits(bufferTraits));
291 }
292
293 // Test calling IBufferHub::import after the original IBufferClient is closed
TEST_F(HalBufferHubVts,ImportFreedBuffer)294 TEST_F(HalBufferHubVts, ImportFreedBuffer) {
295 HardwareBufferDescription desc;
296 memcpy(&desc, &kDesc, sizeof(HardwareBufferDescription));
297
298 BufferHubStatus ret;
299 sp<IBufferClient> client;
300 BufferTraits bufferTraits = {};
301 IBufferHub::allocateBuffer_cb callback = [&](const auto& status, const auto& outClient,
302 const auto& traits) {
303 ret = status;
304 client = outClient;
305 bufferTraits = std::move(traits);
306 };
307 ASSERT_TRUE(mBufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
308 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
309 ASSERT_NE(nullptr, client.get());
310 EXPECT_TRUE(isValidTraits(bufferTraits));
311
312 hidl_handle token;
313 IBufferClient::duplicate_cb dupCb = [&](const auto& outToken, const auto& status) {
314 token = outToken;
315 ret = status;
316 };
317 ASSERT_TRUE(client->duplicate(dupCb).isOk());
318 EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
319 ASSERT_NE(token.getNativeHandle(), nullptr);
320 EXPECT_GT(token->numInts, 1);
321 EXPECT_EQ(token->numFds, 0);
322
323 // Close the client. Now the token should be invalid.
324 ASSERT_EQ(BufferHubStatus::NO_ERROR, client->close());
325
326 sp<IBufferClient> client2;
327 BufferTraits bufferTraits2 = {};
328 IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient,
329 const auto& traits) {
330 ret = status;
331 client2 = outClient;
332 bufferTraits2 = std::move(traits);
333 };
334 ASSERT_TRUE(mBufferHub->importBuffer(token, importCb).isOk());
335 EXPECT_EQ(ret, BufferHubStatus::INVALID_TOKEN);
336 EXPECT_EQ(nullptr, client2.get());
337 EXPECT_FALSE(isValidTraits(bufferTraits2));
338 }
339
340 } // namespace vts
341 } // namespace bufferhub
342 } // namespace frameworks
343 } // namespace android
344
main(int argc,char ** argv)345 int main(int argc, char** argv) {
346 ::testing::AddGlobalTestEnvironment(
347 android::frameworks::bufferhub::vts::BufferHubHidlEnv::Instance());
348 ::testing::InitGoogleTest(&argc, argv);
349 android::frameworks::bufferhub::vts::BufferHubHidlEnv::Instance()->init(&argc, argv);
350 int status = RUN_ALL_TESTS();
351 LOG(INFO) << "Test result = " << status;
352 return status;
353 }
354