• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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