1 /*
2  * Copyright (C) 2021 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_NDEBUG 0
18 #define LOG_TAG "BufferpoolUnitTest"
19 #include <utils/Log.h>
20 
21 #include <binder/ProcessState.h>
22 #include <bufferpool/ClientManager.h>
23 #include <gtest/gtest.h>
24 #include <hidl/LegacySupport.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <unordered_set>
28 #include <vector>
29 #include "allocator.h"
30 
31 using android::hardware::configureRpcThreadpool;
32 using android::hardware::media::bufferpool::BufferPoolData;
33 using android::hardware::media::bufferpool::V2_0::IClientManager;
34 using android::hardware::media::bufferpool::V2_0::ResultStatus;
35 using android::hardware::media::bufferpool::V2_0::implementation::BufferId;
36 using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
37 using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
38 using android::hardware::media::bufferpool::V2_0::implementation::TransactionId;
39 
40 using namespace android;
41 
42 // communication message types between processes.
43 enum PipeCommand : int32_t {
44     INIT,
45     TRANSFER,
46     STOP,
47 
48     INIT_OK,
49     INIT_ERROR,
50     TRANSFER_OK,
51     TRANSFER_ERROR,
52     STOP_OK,
53     STOP_ERROR,
54 };
55 
56 // communication message between processes.
57 union PipeMessage {
58     struct {
59         int32_t command;
60         int32_t memsetValue;
61         BufferId bufferId;
62         ConnectionId connectionId;
63         TransactionId transactionId;
64         int64_t timestampUs;
65     } data;
66     char array[0];
67 };
68 
69 static int32_t kNumIterationCount = 10;
70 
71 class BufferpoolTest {
72   public:
BufferpoolTest()73     BufferpoolTest() : mConnectionValid(false), mManager(nullptr), mAllocator(nullptr) {
74         mConnectionId = -1;
75         mReceiverId = -1;
76     }
77 
~BufferpoolTest()78     ~BufferpoolTest() {
79         if (mConnectionValid) {
80             mManager->close(mConnectionId);
81         }
82     }
83 
84   protected:
85     bool mConnectionValid;
86     ConnectionId mConnectionId;
87     ConnectionId mReceiverId;
88 
89     android::sp<ClientManager> mManager;
90     std::shared_ptr<BufferPoolAllocator> mAllocator;
91 
92     void setupBufferpoolManager();
93 };
94 
setupBufferpoolManager()95 void BufferpoolTest::setupBufferpoolManager() {
96     // retrieving per process bufferpool object sp<ClientManager>
97     mManager = ClientManager::getInstance();
98     ASSERT_NE(mManager, nullptr) << "unable to get ClientManager\n";
99 
100     mAllocator = std::make_shared<TestBufferPoolAllocator>();
101     ASSERT_NE(mAllocator, nullptr) << "unable to create TestBufferPoolAllocator\n";
102 
103     // set-up local bufferpool connection for sender
104     ResultStatus status = mManager->create(mAllocator, &mConnectionId);
105     ASSERT_EQ(status, ResultStatus::OK)
106             << "unable to set-up local bufferpool connection for sender\n";
107     mConnectionValid = true;
108 }
109 
110 class BufferpoolUnitTest : public BufferpoolTest, public ::testing::Test {
111   public:
SetUp()112     virtual void SetUp() override { setupBufferpoolManager(); }
113 
TearDown()114     virtual void TearDown() override {}
115 };
116 
117 class BufferpoolFunctionalityTest : public BufferpoolTest, public ::testing::Test {
118   public:
SetUp()119     virtual void SetUp() override {
120         mReceiverPid = -1;
121 
122         ASSERT_TRUE(pipe(mCommandPipeFds) == 0) << "pipe connection failed for commandPipe\n";
123         ASSERT_TRUE(pipe(mResultPipeFds) == 0) << "pipe connection failed for resultPipe\n";
124 
125         mReceiverPid = fork();
126         ASSERT_TRUE(mReceiverPid >= 0) << "fork failed\n";
127 
128         if (mReceiverPid == 0) {
129             doReceiver();
130             // In order to ignore gtest behaviour, wait for being killed from tearDown
131             pause();
132         }
133         setupBufferpoolManager();
134     }
135 
TearDown()136     virtual void TearDown() override {
137         if (mReceiverPid > 0) {
138             kill(mReceiverPid, SIGKILL);
139             int wstatus;
140             wait(&wstatus);
141         }
142     }
143 
144   protected:
145     pid_t mReceiverPid;
146     int mCommandPipeFds[2];
147     int mResultPipeFds[2];
148 
sendMessage(int * pipes,const PipeMessage & message)149     bool sendMessage(int* pipes, const PipeMessage& message) {
150         int ret = write(pipes[1], message.array, sizeof(PipeMessage));
151         return ret == sizeof(PipeMessage);
152     }
153 
receiveMessage(int * pipes,PipeMessage * message)154     bool receiveMessage(int* pipes, PipeMessage* message) {
155         int ret = read(pipes[0], message->array, sizeof(PipeMessage));
156         return ret == sizeof(PipeMessage);
157     }
158 
159     void doReceiver();
160 };
161 
doReceiver()162 void BufferpoolFunctionalityTest::doReceiver() {
163     // Configures the threadpool used for handling incoming RPC calls in this process.
164     configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
165     bool receiverRunning = true;
166     while (receiverRunning) {
167         PipeMessage message;
168         receiveMessage(mCommandPipeFds, &message);
169         ResultStatus err = ResultStatus::OK;
170         switch (message.data.command) {
171             case PipeCommand::INIT: {
172                 // receiver manager creation
173                 mManager = ClientManager::getInstance();
174                 if (!mManager) {
175                     message.data.command = PipeCommand::INIT_ERROR;
176                     sendMessage(mResultPipeFds, message);
177                     return;
178                 }
179 
180                 android::status_t status = mManager->registerAsService();
181                 if (status != android::OK) {
182                     message.data.command = PipeCommand::INIT_ERROR;
183                     sendMessage(mResultPipeFds, message);
184                     return;
185                 }
186                 message.data.command = PipeCommand::INIT_OK;
187                 sendMessage(mResultPipeFds, message);
188                 break;
189             }
190             case PipeCommand::TRANSFER: {
191                 native_handle_t* receiveHandle = nullptr;
192                 std::shared_ptr<BufferPoolData> receiveBuffer;
193                 err = mManager->receive(message.data.connectionId, message.data.transactionId,
194                                         message.data.bufferId, message.data.timestampUs,
195                                         &receiveHandle, &receiveBuffer);
196                 if (err != ResultStatus::OK) {
197                     message.data.command = PipeCommand::TRANSFER_ERROR;
198                     sendMessage(mResultPipeFds, message);
199                     return;
200                 }
201                 if (!TestBufferPoolAllocator::Verify(receiveHandle, message.data.memsetValue)) {
202                     message.data.command = PipeCommand::TRANSFER_ERROR;
203                     sendMessage(mResultPipeFds, message);
204                     return;
205                 }
206                 if (receiveHandle) {
207                     native_handle_close(receiveHandle);
208                     native_handle_delete(receiveHandle);
209                 }
210                 receiveHandle = nullptr;
211                 receiveBuffer.reset();
212                 message.data.command = PipeCommand::TRANSFER_OK;
213                 sendMessage(mResultPipeFds, message);
214                 break;
215             }
216             case PipeCommand::STOP: {
217                 err = mManager->close(message.data.connectionId);
218                 if (err != ResultStatus::OK) {
219                     message.data.command = PipeCommand::STOP_ERROR;
220                     sendMessage(mResultPipeFds, message);
221                     return;
222                 }
223                 message.data.command = PipeCommand::STOP_OK;
224                 sendMessage(mResultPipeFds, message);
225                 receiverRunning = false;
226                 break;
227             }
228             default:
229                 ALOGE("unknown command. try again");
230                 break;
231         }
232     }
233 }
234 
235 // Buffer allocation test.
236 // Check whether each buffer allocation is done successfully with unique buffer id.
TEST_F(BufferpoolUnitTest,AllocateBuffer)237 TEST_F(BufferpoolUnitTest, AllocateBuffer) {
238     std::vector<uint8_t> vecParams;
239     getTestAllocatorParams(&vecParams);
240 
241     std::vector<std::shared_ptr<BufferPoolData>> buffers{};
242     std::vector<native_handle_t*> allocHandle{};
243     ResultStatus status;
244     for (int i = 0; i < kNumIterationCount; ++i) {
245         native_handle_t* handle = nullptr;
246         std::shared_ptr<BufferPoolData> buffer{};
247         status = mManager->allocate(mConnectionId, vecParams, &handle, &buffer);
248         ASSERT_EQ(status, ResultStatus::OK) << "allocate failed for " << i << "iteration";
249 
250         buffers.push_back(std::move(buffer));
251         if (handle) {
252             allocHandle.push_back(std::move(handle));
253         }
254     }
255 
256     for (int i = 0; i < kNumIterationCount; ++i) {
257         for (int j = i + 1; j < kNumIterationCount; ++j) {
258             ASSERT_TRUE(buffers[i]->mId != buffers[j]->mId) << "allocated buffers are not unique";
259         }
260     }
261     // delete the buffer handles
262     for (auto handle : allocHandle) {
263         native_handle_close(handle);
264         native_handle_delete(handle);
265     }
266     // clear the vectors
267     buffers.clear();
268     allocHandle.clear();
269 }
270 
271 // Buffer recycle test.
272 // Check whether de-allocated buffers are recycled.
TEST_F(BufferpoolUnitTest,RecycleBuffer)273 TEST_F(BufferpoolUnitTest, RecycleBuffer) {
274     std::vector<uint8_t> vecParams;
275     getTestAllocatorParams(&vecParams);
276 
277     ResultStatus status;
278     std::vector<BufferId> bid{};
279     std::vector<native_handle_t*> allocHandle{};
280     for (int i = 0; i < kNumIterationCount; ++i) {
281         native_handle_t* handle = nullptr;
282         std::shared_ptr<BufferPoolData> buffer;
283         status = mManager->allocate(mConnectionId, vecParams, &handle, &buffer);
284         ASSERT_EQ(status, ResultStatus::OK) << "allocate failed for " << i << "iteration";
285 
286         bid.push_back(buffer->mId);
287         if (handle) {
288             allocHandle.push_back(std::move(handle));
289         }
290         buffer.reset();
291     }
292 
293     std::unordered_set<BufferId> set(bid.begin(), bid.end());
294     ASSERT_EQ(set.size(), 1) << "buffers are not recycled properly";
295 
296     // delete the buffer handles
297     for (auto handle : allocHandle) {
298         native_handle_close(handle);
299         native_handle_delete(handle);
300     }
301     allocHandle.clear();
302 }
303 
304 // Validate cache evict and invalidate APIs.
TEST_F(BufferpoolUnitTest,FlushTest)305 TEST_F(BufferpoolUnitTest, FlushTest) {
306     std::vector<uint8_t> vecParams;
307     getTestAllocatorParams(&vecParams);
308 
309     ResultStatus status = mManager->registerSender(mManager, mConnectionId, &mReceiverId);
310     ASSERT_TRUE(status == ResultStatus::ALREADY_EXISTS && mReceiverId == mConnectionId);
311 
312     // testing empty flush
313     status = mManager->flush(mConnectionId);
314     ASSERT_EQ(status, ResultStatus::OK) << "failed to flush connection : " << mConnectionId;
315 
316     std::vector<std::shared_ptr<BufferPoolData>> senderBuffer{};
317     std::vector<native_handle_t*> allocHandle{};
318     std::vector<TransactionId> tid{};
319     std::vector<int64_t> timestampUs{};
320 
321     std::map<TransactionId, BufferId> bufferMap{};
322 
323     for (int i = 0; i < kNumIterationCount; i++) {
324         int64_t postUs;
325         TransactionId transactionId;
326         native_handle_t* handle = nullptr;
327         std::shared_ptr<BufferPoolData> buffer{};
328         status = mManager->allocate(mConnectionId, vecParams, &handle, &buffer);
329         ASSERT_EQ(status, ResultStatus::OK) << "allocate failed for " << i << " iteration";
330 
331         ASSERT_TRUE(TestBufferPoolAllocator::Fill(handle, i));
332 
333         status = mManager->postSend(mReceiverId, buffer, &transactionId, &postUs);
334         ASSERT_EQ(status, ResultStatus::OK) << "unable to post send transaction on bufferpool";
335 
336         timestampUs.push_back(postUs);
337         tid.push_back(transactionId);
338         bufferMap.insert({transactionId, buffer->mId});
339 
340         senderBuffer.push_back(std::move(buffer));
341         if (handle) {
342             allocHandle.push_back(std::move(handle));
343         }
344         buffer.reset();
345     }
346 
347     status = mManager->flush(mConnectionId);
348     ASSERT_EQ(status, ResultStatus::OK) << "failed to flush connection : " << mConnectionId;
349 
350     std::shared_ptr<BufferPoolData> receiverBuffer{};
351     native_handle_t* recvHandle = nullptr;
352     for (int i = 0; i < kNumIterationCount; i++) {
353         status = mManager->receive(mReceiverId, tid[i], senderBuffer[i]->mId, timestampUs[i],
354                                    &recvHandle, &receiverBuffer);
355         ASSERT_EQ(status, ResultStatus::OK) << "receive failed for buffer " << senderBuffer[i]->mId;
356 
357         // find the buffer id from transaction id
358         auto findIt = bufferMap.find(tid[i]);
359         ASSERT_NE(findIt, bufferMap.end()) << "inconsistent buffer mapping";
360 
361         // buffer id received must be same as the buffer id sent
362         ASSERT_EQ(findIt->second, receiverBuffer->mId) << "invalid buffer received";
363 
364         ASSERT_TRUE(TestBufferPoolAllocator::Verify(recvHandle, i))
365                 << "Message received not same as that sent";
366 
367         bufferMap.erase(findIt);
368         if (recvHandle) {
369             native_handle_close(recvHandle);
370             native_handle_delete(recvHandle);
371         }
372         recvHandle = nullptr;
373         receiverBuffer.reset();
374     }
375 
376     ASSERT_EQ(bufferMap.size(), 0) << "buffers received is less than the number of buffers sent";
377 
378     for (auto handle : allocHandle) {
379         native_handle_close(handle);
380         native_handle_delete(handle);
381     }
382     allocHandle.clear();
383     senderBuffer.clear();
384     timestampUs.clear();
385 }
386 
387 // Buffer transfer test between processes.
TEST_F(BufferpoolFunctionalityTest,TransferBuffer)388 TEST_F(BufferpoolFunctionalityTest, TransferBuffer) {
389     // initialize the receiver
390     PipeMessage message;
391     message.data.command = PipeCommand::INIT;
392     sendMessage(mCommandPipeFds, message);
393     ASSERT_TRUE(receiveMessage(mResultPipeFds, &message)) << "receiveMessage failed\n";
394     ASSERT_EQ(message.data.command, PipeCommand::INIT_OK) << "receiver init failed";
395 
396     android::sp<IClientManager> receiver = IClientManager::getService();
397     ASSERT_NE(receiver, nullptr) << "getService failed for receiver\n";
398 
399     ConnectionId receiverId;
400     ResultStatus status = mManager->registerSender(receiver, mConnectionId, &receiverId);
401     ASSERT_EQ(status, ResultStatus::OK)
402             << "registerSender failed for connection id " << mConnectionId << "\n";
403 
404     std::vector<uint8_t> vecParams;
405     getTestAllocatorParams(&vecParams);
406 
407     for (int i = 0; i < kNumIterationCount; ++i) {
408         native_handle_t* handle = nullptr;
409         std::shared_ptr<BufferPoolData> buffer;
410         status = mManager->allocate(mConnectionId, vecParams, &handle, &buffer);
411         ASSERT_EQ(status, ResultStatus::OK) << "allocate failed for " << i << "iteration";
412 
413         ASSERT_TRUE(TestBufferPoolAllocator::Fill(handle, i))
414                 << "Fill fail for buffer handle " << handle << "\n";
415 
416         // send the buffer to the receiver
417         int64_t postUs;
418         TransactionId transactionId;
419         status = mManager->postSend(receiverId, buffer, &transactionId, &postUs);
420         ASSERT_EQ(status, ResultStatus::OK)
421                 << "postSend failed for receiver " << receiverId << "\n";
422 
423         // PipeMessage message;
424         message.data.command = PipeCommand::TRANSFER;
425         message.data.memsetValue = i;
426         message.data.bufferId = buffer->mId;
427         message.data.connectionId = receiverId;
428         message.data.transactionId = transactionId;
429         message.data.timestampUs = postUs;
430         sendMessage(mCommandPipeFds, message);
431         // delete buffer handle
432         if (handle) {
433             native_handle_close(handle);
434             native_handle_delete(handle);
435         }
436         ASSERT_TRUE(receiveMessage(mResultPipeFds, &message)) << "receiveMessage failed\n";
437         ASSERT_EQ(message.data.command, PipeCommand::TRANSFER_OK)
438                 << "received error during buffer transfer\n";
439     }
440     message.data.command = PipeCommand::STOP;
441     sendMessage(mCommandPipeFds, message);
442     ASSERT_TRUE(receiveMessage(mResultPipeFds, &message)) << "receiveMessage failed\n";
443     ASSERT_EQ(message.data.command, PipeCommand::STOP_OK)
444             << "received error during buffer transfer\n";
445 }
446 
447 /* Validate bufferpool for following corner cases:
448  1. invalid connectionID
449  2. invalid receiver
450  3. when sender is not registered
451  4. when connection is closed
452 */
453 // TODO: Enable when the issue in b/212196495 is fixed
TEST_F(BufferpoolFunctionalityTest,DISABLED_ValidityTest)454 TEST_F(BufferpoolFunctionalityTest, DISABLED_ValidityTest) {
455     std::vector<uint8_t> vecParams;
456     getTestAllocatorParams(&vecParams);
457 
458     std::shared_ptr<BufferPoolData> senderBuffer;
459     native_handle_t* allocHandle = nullptr;
460 
461     // call allocate() on a random connection id
462     ConnectionId randomId = rand();
463     ResultStatus status = mManager->allocate(randomId, vecParams, &allocHandle, &senderBuffer);
464     EXPECT_TRUE(status == ResultStatus::NOT_FOUND);
465 
466     // initialize the receiver
467     PipeMessage message;
468     message.data.command = PipeCommand::INIT;
469     sendMessage(mCommandPipeFds, message);
470     ASSERT_TRUE(receiveMessage(mResultPipeFds, &message)) << "receiveMessage failed\n";
471     ASSERT_EQ(message.data.command, PipeCommand::INIT_OK) << "receiver init failed";
472 
473     allocHandle = nullptr;
474     senderBuffer.reset();
475     status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &senderBuffer);
476 
477     ASSERT_TRUE(TestBufferPoolAllocator::Fill(allocHandle, 0x77));
478 
479     // send buffers w/o registering sender
480     int64_t postUs;
481     TransactionId transactionId;
482 
483     // random receiver
484     status = mManager->postSend(randomId, senderBuffer, &transactionId, &postUs);
485     ASSERT_NE(status, ResultStatus::OK) << "bufferpool shouldn't allow send on random receiver";
486 
487     // establish connection
488     android::sp<IClientManager> receiver = IClientManager::getService();
489     ASSERT_NE(receiver, nullptr) << "getService failed for receiver\n";
490 
491     ConnectionId receiverId;
492     status = mManager->registerSender(receiver, mConnectionId, &receiverId);
493     ASSERT_EQ(status, ResultStatus::OK)
494             << "registerSender failed for connection id " << mConnectionId << "\n";
495 
496     allocHandle = nullptr;
497     senderBuffer.reset();
498     status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &senderBuffer);
499     ASSERT_EQ(status, ResultStatus::OK) << "allocate failed for connection " << mConnectionId;
500 
501     ASSERT_TRUE(TestBufferPoolAllocator::Fill(allocHandle, 0x88));
502 
503     // send the buffer to the receiver
504     status = mManager->postSend(receiverId, senderBuffer, &transactionId, &postUs);
505     ASSERT_EQ(status, ResultStatus::OK) << "postSend failed for receiver " << receiverId << "\n";
506 
507     // PipeMessage message;
508     message.data.command = PipeCommand::TRANSFER;
509     message.data.memsetValue = 0x88;
510     message.data.bufferId = senderBuffer->mId;
511     message.data.connectionId = receiverId;
512     message.data.transactionId = transactionId;
513     message.data.timestampUs = postUs;
514     sendMessage(mCommandPipeFds, message);
515     ASSERT_TRUE(receiveMessage(mResultPipeFds, &message)) << "receiveMessage failed\n";
516     ASSERT_EQ(message.data.command, PipeCommand::TRANSFER_OK)
517             << "received error during buffer transfer\n";
518 
519     if (allocHandle) {
520         native_handle_close(allocHandle);
521         native_handle_delete(allocHandle);
522     }
523 
524     message.data.command = PipeCommand::STOP;
525     sendMessage(mCommandPipeFds, message);
526     ASSERT_TRUE(receiveMessage(mResultPipeFds, &message)) << "receiveMessage failed\n";
527     ASSERT_EQ(message.data.command, PipeCommand::STOP_OK)
528             << "received error during buffer transfer\n";
529 
530     // try to send msg to closed connection
531     status = mManager->postSend(receiverId, senderBuffer, &transactionId, &postUs);
532     ASSERT_NE(status, ResultStatus::OK) << "bufferpool shouldn't allow send on closed connection";
533 }
534 
main(int argc,char ** argv)535 int main(int argc, char** argv) {
536     android::hardware::details::setTrebleTestingOverride(true);
537     ::testing::InitGoogleTest(&argc, argv);
538     int status = RUN_ALL_TESTS();
539     ALOGV("Test result = %d\n", status);
540     return status;
541 }
542