• 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 "buffferpool_unit_test"
18 
19 #include <gtest/gtest.h>
20 
21 #include <android-base/logging.h>
22 #include <binder/ProcessState.h>
23 #include <bufferpool/ClientManager.h>
24 #include <errno.h>
25 #include <hidl/HidlSupport.h>
26 #include <hidl/HidlTransportSupport.h>
27 #include <hidl/LegacySupport.h>
28 #include <hidl/Status.h>
29 #include <signal.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33 #include <iostream>
34 #include <memory>
35 #include <vector>
36 #include "allocator.h"
37 
38 using android::hardware::configureRpcThreadpool;
39 using android::hardware::hidl_handle;
40 using android::hardware::media::bufferpool::V2_0::IClientManager;
41 using android::hardware::media::bufferpool::V2_0::ResultStatus;
42 using android::hardware::media::bufferpool::V2_0::implementation::BufferId;
43 using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
44 using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
45 using android::hardware::media::bufferpool::V2_0::implementation::TransactionId;
46 using android::hardware::media::bufferpool::BufferPoolData;
47 
48 namespace {
49 
50 // communication message types between processes.
51 enum PipeCommand : int32_t {
52     INIT_OK = 0,
53     INIT_ERROR,
54     SEND,
55     RECEIVE_OK,
56     RECEIVE_ERROR,
57 };
58 
59 // communication message between processes.
60 union PipeMessage {
61     struct  {
62         int32_t command;
63         BufferId bufferId;
64         ConnectionId connectionId;
65         TransactionId transactionId;
66         int64_t  timestampUs;
67     } data;
68     char array[0];
69 };
70 
71 constexpr int kSignalInt = 200;
72 
73 // media.bufferpool test setup
74 class BufferpoolMultiTest : public ::testing::Test {
75  public:
SetUp()76   virtual void SetUp() override {
77     ResultStatus status;
78     mReceiverPid = -1;
79     mConnectionValid = false;
80 
81     ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
82     ASSERT_TRUE(pipe(mResultPipeFds) == 0);
83 
84     mReceiverPid = fork();
85     ASSERT_TRUE(mReceiverPid >= 0);
86 
87     if (mReceiverPid == 0) {
88       doReceiver();
89       // In order to ignore gtest behaviour, wait for being killed from
90       // tearDown
91       pause();
92     }
93 
94     mManager = ClientManager::getInstance();
95     ASSERT_NE(mManager, nullptr);
96 
97     mAllocator = std::make_shared<TestBufferPoolAllocator>();
98     ASSERT_TRUE((bool)mAllocator);
99 
100     status = mManager->create(mAllocator, &mConnectionId);
101     ASSERT_TRUE(status == ResultStatus::OK);
102     mConnectionValid = true;
103   }
104 
TearDown()105   virtual void TearDown() override {
106     if (mReceiverPid > 0) {
107       kill(mReceiverPid, SIGKILL);
108       int wstatus;
109       wait(&wstatus);
110     }
111 
112     if (mConnectionValid) {
113       mManager->close(mConnectionId);
114     }
115   }
116 
117  protected:
description(const std::string & description)118   static void description(const std::string& description) {
119     RecordProperty("description", description);
120   }
121 
122   android::sp<ClientManager> mManager;
123   std::shared_ptr<BufferPoolAllocator> mAllocator;
124   bool mConnectionValid;
125   ConnectionId mConnectionId;
126   pid_t mReceiverPid;
127   int mCommandPipeFds[2];
128   int mResultPipeFds[2];
129 
sendMessage(int * pipes,const PipeMessage & message)130   bool sendMessage(int *pipes, const PipeMessage &message) {
131     int ret = write(pipes[1], message.array, sizeof(PipeMessage));
132     return ret == sizeof(PipeMessage);
133   }
134 
receiveMessage(int * pipes,PipeMessage * message)135   bool receiveMessage(int *pipes, PipeMessage *message) {
136     int ret = read(pipes[0], message->array, sizeof(PipeMessage));
137     return ret == sizeof(PipeMessage);
138   }
139 
doReceiver()140   void doReceiver() {
141     configureRpcThreadpool(1, false);
142     PipeMessage message;
143     mManager = ClientManager::getInstance();
144     if (!mManager) {
145       message.data.command = PipeCommand::INIT_ERROR;
146       sendMessage(mResultPipeFds, message);
147       return;
148     }
149     android::status_t status = mManager->registerAsService();
150     if (status != android::OK) {
151       message.data.command = PipeCommand::INIT_ERROR;
152       sendMessage(mResultPipeFds, message);
153       return;
154     }
155     message.data.command = PipeCommand::INIT_OK;
156     sendMessage(mResultPipeFds, message);
157 
158     int val = 0;
159     receiveMessage(mCommandPipeFds, &message);
160     {
161       native_handle_t *rhandle = nullptr;
162       std::shared_ptr<BufferPoolData> rbuffer;
163       void *mem = nullptr;
164       IpcMutex *mutex = nullptr;
165       ResultStatus status = mManager->receive(
166           message.data.connectionId, message.data.transactionId,
167           message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
168       mManager->close(message.data.connectionId);
169       if (status != ResultStatus::OK) {
170           message.data.command = PipeCommand::RECEIVE_ERROR;
171           sendMessage(mResultPipeFds, message);
172           return;
173       }
174       if (!TestBufferPoolAllocator::MapMemoryForMutex(rhandle, &mem)) {
175           message.data.command = PipeCommand::RECEIVE_ERROR;
176           sendMessage(mResultPipeFds, message);
177           return;
178       }
179       mutex = IpcMutex::Import(mem);
180       pthread_mutex_lock(&(mutex->lock));
181       while (mutex->signalled != true) {
182           pthread_cond_wait(&(mutex->cond), &(mutex->lock));
183       }
184       val = mutex->counter;
185       pthread_mutex_unlock(&(mutex->lock));
186 
187       (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
188       if (rhandle) {
189         native_handle_close(rhandle);
190         native_handle_delete(rhandle);
191       }
192     }
193     if (val == kSignalInt) {
194       message.data.command = PipeCommand::RECEIVE_OK;
195     } else {
196       message.data.command = PipeCommand::RECEIVE_ERROR;
197     }
198     sendMessage(mResultPipeFds, message);
199   }
200 };
201 
202 // Buffer transfer test between processes.
TEST_F(BufferpoolMultiTest,TransferBuffer)203 TEST_F(BufferpoolMultiTest, TransferBuffer) {
204   ResultStatus status;
205   PipeMessage message;
206 
207   ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
208 
209   android::sp<IClientManager> receiver = IClientManager::getService();
210   ConnectionId receiverId;
211   ASSERT_TRUE((bool)receiver);
212 
213   status = mManager->registerSender(receiver, mConnectionId, &receiverId);
214   ASSERT_TRUE(status == ResultStatus::OK);
215   {
216     native_handle_t *shandle = nullptr;
217     std::shared_ptr<BufferPoolData> sbuffer;
218     TransactionId transactionId;
219     int64_t postUs;
220     std::vector<uint8_t> vecParams;
221     void *mem = nullptr;
222     IpcMutex *mutex = nullptr;
223 
224     getIpcMutexParams(&vecParams);
225     status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
226     ASSERT_TRUE(status == ResultStatus::OK);
227 
228     ASSERT_TRUE(TestBufferPoolAllocator::MapMemoryForMutex(shandle, &mem));
229 
230     mutex = new(mem) IpcMutex();
231     mutex->init();
232 
233     status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
234     ASSERT_TRUE(status == ResultStatus::OK);
235 
236     message.data.command = PipeCommand::SEND;
237     message.data.bufferId = sbuffer->mId;
238     message.data.connectionId = receiverId;
239     message.data.transactionId = transactionId;
240     message.data.timestampUs = postUs;
241     sendMessage(mCommandPipeFds, message);
242     for (int i=0; i < 200000000; ++i) {
243       // no-op in order to ensure
244       // pthread_cond_wait is called before pthread_cond_signal
245     }
246     pthread_mutex_lock(&(mutex->lock));
247     mutex->counter = kSignalInt;
248     mutex->signalled = true;
249     pthread_cond_signal(&(mutex->cond));
250     pthread_mutex_unlock(&(mutex->lock));
251     (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
252     if (shandle) {
253       native_handle_close(shandle);
254       native_handle_delete(shandle);
255     }
256   }
257   EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
258   EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
259 }
260 
261 }  // anonymous namespace
262 
main(int argc,char ** argv)263 int main(int argc, char** argv) {
264   android::hardware::details::setTrebleTestingOverride(true);
265   ::testing::InitGoogleTest(&argc, argv);
266   int status = RUN_ALL_TESTS();
267   LOG(INFO) << "Test result = " << status;
268   return status;
269 }
270