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 = &num;
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 }