1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <base/hdi_smq.h>
17 #include <base/hdi_smq_meta.h>
18 #include <base/hdi_smq_syncer.h>
19 #include "osal_mem.h"
20 #include <sys/mman.h>
21 #include <gtest/gtest.h>
22 #include <idevmgr_hdi.h>
23 #include <iservmgr_hdi.h>
24
25 #include "sample_hdi.h"
26
27 #include <algorithm>
28 #include <cstdio>
29 #include <cstring>
30 #include <iostream>
31 #include <sstream>
32
33 #define HDF_LOG_TAG smq_test
34
35 namespace {
36 using namespace testing::ext;
37 using OHOS::IRemoteObject;
38 using OHOS::sptr;
39 using OHOS::HDI::Base::SharedMemQueue;
40 using OHOS::HDI::Base::SharedMemQueueMeta;
41 using OHOS::HDI::Base::SmqType;
42 using OHOS::HDI::DeviceManager::V1_0::IDeviceManager;
43 using OHOS::HDI::ServiceManager::V1_0::IServiceManager;
44
45 static constexpr const uint32_t TEST_NUM = 300;
46 #ifdef SAMPLE_DRIVER
47 static constexpr const char *TEST_SERVICE_HOST_NAME = "sample_host";
48 static constexpr const char *SERVICE_NAME = "sample_driver_service";
49 static constexpr const char16_t *TEST_SERVICE_INTERFACE_DESC = u"hdf.test.sampele_service";
50 static constexpr int SMQ_TEST_QUEUE_SIZE = 10;
51 static constexpr uint32_t HOST_PID_BUFF_SIZE = 20;
52 static constexpr uint32_t CMD_RESULT_BUFF_SIZE = 1024;
53 #endif
54 } // namespace
55
56 #ifdef SAMPLE_DRIVER
Split(const std::string & src,const std::string & limit)57 static std::vector<std::string> Split(const std::string &src, const std::string &limit)
58 {
59 std::vector<std::string> result;
60 if (src.empty()) {
61 return result;
62 }
63
64 if (limit.empty()) {
65 result.push_back(src);
66 return result;
67 }
68
69 size_t begin = 0;
70 size_t pos = src.find(limit, begin);
71 while (pos != std::string::npos) {
72 std::string element = src.substr(begin, pos - begin);
73 if (!element.empty()) {
74 result.push_back(element);
75 }
76 begin = pos + limit.size();
77 pos = src.find(limit, begin);
78 }
79
80 if (begin < src.size()) {
81 std::string element = src.substr(begin);
82 result.push_back(element);
83 }
84 return result;
85 }
86
QueryPidOfHostName(const std::string & hostName,int & hostPid)87 static bool QueryPidOfHostName(const std::string &hostName, int &hostPid)
88 {
89 if (hostName.empty()) {
90 return false;
91 }
92
93 // ps -ef | grep hostName | grep -v "grep" | sed 's/ */ /g' | cut -d ' ' -f 2
94 std::ostringstream cmdStr;
95 cmdStr << "ps -ef | grep '" << hostName << "' | grep -v 'grep' | ";
96 cmdStr << "sed 's/ */ /g' | cut -d ' ' -f 2";
97 FILE *res = popen(cmdStr.str().c_str(), "r");
98 if (res == nullptr) {
99 HDF_LOGE("[%{public}s:%{public}d] failed to popen '%{public}s'", __func__, __LINE__, cmdStr.str().c_str());
100 return false;
101 }
102
103 HDF_LOGD("[%{public}s:%{public}d] popen '%{public}s'", __func__, __LINE__, cmdStr.str().c_str());
104 char resBuf[HOST_PID_BUFF_SIZE] = {0};
105 (void)fread(resBuf, HOST_PID_BUFF_SIZE - 1, 1, res);
106 pclose(res);
107
108 // if no result, can not convert string to number
109 if (strlen(resBuf) == 0) {
110 return false;
111 }
112
113 hostPid = std::stoi(resBuf);
114 return true;
115 }
116
QueryOpendFdsByHostPid(int hostPid,std::set<int> & fds)117 static bool QueryOpendFdsByHostPid(int hostPid, std::set<int> &fds)
118 {
119 if (hostPid <= 0) {
120 HDF_LOGE("[%{public}s:%{public}d] invalid hostPid", __func__, __LINE__);
121 return false;
122 }
123
124 std::ostringstream cmdStr;
125 cmdStr << "ls /proc/" << hostPid << "/fd | sort -n | xargs";
126
127 FILE *res = popen(cmdStr.str().c_str(), "r");
128 if (res == nullptr) {
129 HDF_LOGE("[%{public}s:%{public}d] failed to popen '%{public}s'", __func__, __LINE__, cmdStr.str().c_str());
130 return false;
131 }
132
133 int resFd = fileno(res);
134 HDF_LOGD("[%{public}s:%{public}d] popen '%{public}s'", __func__, __LINE__, cmdStr.str().c_str());
135 char resBuf[CMD_RESULT_BUFF_SIZE] = {0};
136 (void)fread(resBuf, CMD_RESULT_BUFF_SIZE - 1, 1, res);
137 pclose(res);
138
139 std::vector<std::string> fdsResult = Split(resBuf, " ");
140 for (const auto &fdStr : fdsResult) {
141 int fd = std::stoi(fdStr);
142 if (fd == resFd) {
143 continue;
144 }
145 fds.insert(fd);
146 }
147 return true;
148 }
149
QueryOpenedFdsByHostName(const std::string & hostName,std::set<int> & fds)150 static bool QueryOpenedFdsByHostName(const std::string &hostName, std::set<int> &fds)
151 {
152 int hostPid = 0;
153 if (!QueryPidOfHostName(hostName, hostPid)) {
154 return false;
155 }
156
157 if (!QueryOpendFdsByHostPid(hostPid, fds)) {
158 return false;
159 }
160
161 return true;
162 }
163
QueryOpenedFdsOfCurrentHost(std::set<int> & fds)164 static bool QueryOpenedFdsOfCurrentHost(std::set<int> &fds)
165 {
166 int pid = getpid();
167 if (!QueryOpendFdsByHostPid(pid, fds)) {
168 return false;
169 }
170 return true;
171 }
172
PrintFds(const std::string & info,const std::set<int> & fds)173 static void PrintFds(const std::string &info, const std::set<int> &fds)
174 {
175 std::cout << info << ":";
176 for (const auto& fd: fds) {
177 std::cout << fd << ' ';
178 }
179 std::cout << std::endl;
180 }
181 #endif
182
183 class SmqTest : public testing::Test {
184 public:
SetUpTestCase()185 static void SetUpTestCase()
186 {
187 #ifdef SAMPLE_DRIVER
188 auto devmgr = IDeviceManager::Get();
189 if (devmgr != nullptr) {
190 HDF_LOGI("%{public}s:%{public}d", __func__, __LINE__);
191 devmgr->LoadDevice(SERVICE_NAME);
192 }
193 #endif
194 }
195
TearDownTestCase()196 static void TearDownTestCase()
197 {
198 #ifdef SAMPLE_DRIVER
199 auto devmgr = IDeviceManager::Get();
200 if (devmgr != nullptr) {
201 HDF_LOGI("%{public}s:%{public}d", __func__, __LINE__);
202 devmgr->UnloadDevice(SERVICE_NAME);
203 }
204 #endif
205 }
206
SetUp()207 void SetUp() {};
TearDown()208 void TearDown() {};
209 };
210
211 #ifdef SAMPLE_DRIVER
212 HWTEST_F(SmqTest, SmqTest001, TestSize.Level1)
213 {
214 std::set<int> fds1;
215 EXPECT_TRUE(QueryOpenedFdsOfCurrentHost(fds1));
216 std::cout << "File descriptor opened by the current host at the current time:\n";
217 PrintFds("current host:", fds1);
218 {
219 std::unique_ptr<SharedMemQueue<int32_t>> smq =
220 std::make_unique<SharedMemQueue<int32_t>>(SMQ_TEST_QUEUE_SIZE, SmqType::SYNCED_SMQ);
221 ASSERT_TRUE(smq->IsGood());
222 ASSERT_NE(smq->GetMeta(), nullptr);
223
224 OHOS::MessageParcel data;
225 ASSERT_TRUE(smq->GetMeta()->Marshalling(data));
226 std::shared_ptr<SharedMemQueueMeta<int32_t>> replyMeta = SharedMemQueueMeta<int32_t>::UnMarshalling(data);
227 ASSERT_NE(replyMeta, nullptr);
228 std::shared_ptr<SharedMemQueue<int32_t>> smq2 = std::make_shared<SharedMemQueue<int32_t>>(*replyMeta);
229 ASSERT_TRUE(smq2->IsGood());
230 }
231
232 std::set<int> fds2;
233 EXPECT_TRUE(QueryOpenedFdsOfCurrentHost(fds2));
234 std::cout << "File descriptor opened by the current host at the current time:\n";
235 PrintFds("current host:", fds2);
236
237 std::set<int> unclosedFds;
238 std::set_difference(fds2.begin(), fds2.end(), fds1.begin(), fds1.end(),
239 std::inserter(unclosedFds, unclosedFds.begin()));
240 EXPECT_TRUE(unclosedFds.empty());
241 if (!unclosedFds.empty()) {
242 PrintFds("unclosed fds:", unclosedFds);
243 }
244 }
245
246 HWTEST_F(SmqTest, SmqTest002, TestSize.Level1)
247 {
248 // query fds of current host
249 std::set<int> hostFds1;
250 EXPECT_TRUE(QueryOpenedFdsOfCurrentHost(hostFds1));
251 std::cout << "File descriptor opened by the current host at the current time:\n";
252 PrintFds("current host:", hostFds1);
253
254 // query fds of sample_host
255 std::set<int> servFds1;
256 EXPECT_TRUE(QueryOpenedFdsByHostName(TEST_SERVICE_HOST_NAME, servFds1));
257 std::cout << "File descriptor opened by the sample_host at the current time:\n";
258 PrintFds("sample_host:", servFds1);
259
260 {
261 auto servmgr = IServiceManager::Get();
262 ASSERT_TRUE(servmgr != nullptr);
263
264 auto sampleService = servmgr->GetService(SERVICE_NAME);
265 ASSERT_TRUE(sampleService != nullptr);
266
267 OHOS::MessageParcel data;
268 OHOS::MessageParcel reply;
269 OHOS::MessageOption option;
270 std::unique_ptr<SharedMemQueue<SampleSmqElement>> smq =
271 std::make_unique<SharedMemQueue<SampleSmqElement>>(SMQ_TEST_QUEUE_SIZE, SmqType::SYNCED_SMQ);
272 ASSERT_TRUE(smq->IsGood());
273
274 bool ret = data.WriteInterfaceToken(TEST_SERVICE_INTERFACE_DESC);
275 ASSERT_EQ(ret, true);
276 ret = smq->GetMeta()->Marshalling(data);
277 ASSERT_TRUE(ret);
278 data.WriteUint32(1);
279
280 int status = sampleService->SendRequest(SAMPLE_TRANS_SMQ, data, reply, option);
281 ASSERT_EQ(status, 0);
282 }
283
284 // query fds of current host
285 std::set<int> hostFds2;
286 EXPECT_TRUE(QueryOpenedFdsOfCurrentHost(hostFds2));
287 std::cout << "File descriptor opened by the current host at the current time:\n";
288 PrintFds("current host:", hostFds2);
289
290 // query fds of sample_host
291 std::set<int> servFds2;
292 EXPECT_TRUE(QueryOpenedFdsByHostName(TEST_SERVICE_HOST_NAME, servFds2));
293 std::cout << "File descriptor opened by the sample_host at the current time:\n";
294 PrintFds("sample_host:", servFds2);
295
296 // the fds that host didn't to close
297 std::set<int> hostUnclosedFds;
298 std::set_difference(hostFds2.begin(), hostFds2.end(), hostFds1.begin(), hostFds1.end(),
299 std::inserter(hostUnclosedFds, hostUnclosedFds.begin()));
300 EXPECT_TRUE(hostUnclosedFds.empty());
301 if (!hostUnclosedFds.empty()) {
302 PrintFds("current host unclosed fds:", hostUnclosedFds);
303 }
304
305 // the fds that sample_host didn't to close
306 std::set<int> servHostUnclosedFds;
307 std::set_difference(servFds2.begin(), servFds2.end(), servFds1.begin(), servFds1.end(),
308 std::inserter(servHostUnclosedFds, servHostUnclosedFds.begin()));
309 EXPECT_TRUE(servHostUnclosedFds.empty());
310 if (!servHostUnclosedFds.empty()) {
311 PrintFds("sample_host unclosed fds:", servHostUnclosedFds);
312 }
313 }
314 #endif
315
MapMemZone(uint32_t zoneType)316 static uintptr_t MapMemZone(uint32_t zoneType)
317 {
318 std::shared_ptr<SharedMemQueueMeta<uint8_t>> meta_ =
319 std::make_shared<SharedMemQueueMeta<uint8_t>>(TEST_NUM, SmqType::SYNCED_SMQ);
320 auto memzone = meta_->GetMemZone(zoneType);
321 if (memzone == nullptr) {
322 HDF_LOGE("invalid smq mem zone type %{public}u", zoneType);
323 return reinterpret_cast<uintptr_t>(nullptr);
324 }
325
326 int offset = (static_cast<int>(memzone->offset) / PAGE_SIZE) * PAGE_SIZE;
327 int length = static_cast<int>(memzone->offset) - offset + static_cast<int>(memzone->size);
328
329 void *ptr = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, meta_->GetFd(), offset);
330 if (ptr == MAP_FAILED) {
331 HDF_LOGE(
332 "failed to map memzone %{public}u, size %{public}u, offset %{public}u , fd %{public}d, errnor=%{public}d",
333 zoneType, length, offset, meta_->GetFd(), errno);
334 unsigned int num = 20;
335 unsigned int *uptr = #
336 return reinterpret_cast<uintptr_t>(uptr);
337 }
338 return (reinterpret_cast<uintptr_t>(ptr) + (static_cast<int>(memzone->offset) - offset));
339 }
340
341 HWTEST_F(SmqTest, SmqTest003, TestSize.Level1)
342 {
343 std::atomic<uint32_t> *syncerPtr_ =
344 reinterpret_cast<std::atomic<uint32_t> *>(MapMemZone(SharedMemQueueMeta<uint8_t>::MEMZONE_SYNCER));
345 std::unique_ptr<OHOS::HDI::Base::SharedMemQueueSyncer> syncer_ =
346 std::make_unique<OHOS::HDI::Base::SharedMemQueueSyncer>(syncerPtr_);
347 syncer_->Wake(OHOS::HDI::Base::SharedMemQueueSyncer::SYNC_WORD_WRITE);
348 syncer_->Wait(OHOS::HDI::Base::SharedMemQueueSyncer::SYNC_WORD_WRITE, 0);
349 syncer_->Wake(OHOS::HDI::Base::SharedMemQueueSyncer::SYNC_WORD_WRITE);
350 syncer_->Wait(OHOS::HDI::Base::SharedMemQueueSyncer::SYNC_WORD_WRITE, 5);
351 }