1f857971dSopenharmony_ci/*
2f857971dSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3f857971dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4f857971dSopenharmony_ci * you may not use this file except in compliance with the License.
5f857971dSopenharmony_ci * You may obtain a copy of the License at
6f857971dSopenharmony_ci *
7f857971dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8f857971dSopenharmony_ci *
9f857971dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10f857971dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11f857971dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f857971dSopenharmony_ci * See the License for the specific language governing permissions and
13f857971dSopenharmony_ci * limitations under the License.
14f857971dSopenharmony_ci */
15f857971dSopenharmony_ci
16f857971dSopenharmony_ci#include "virtual_device_builder.h"
17f857971dSopenharmony_ci
18f857971dSopenharmony_ci#include <cerrno>
19f857971dSopenharmony_ci#include <csignal>
20f857971dSopenharmony_ci#include <cstring>
21f857971dSopenharmony_ci#include <fstream>
22f857971dSopenharmony_ci#include <iostream>
23f857971dSopenharmony_ci#include <regex>
24f857971dSopenharmony_ci#include <sstream>
25f857971dSopenharmony_ci#include <map>
26f857971dSopenharmony_ci
27f857971dSopenharmony_ci#include <dirent.h>
28f857971dSopenharmony_ci#include <fcntl.h>
29f857971dSopenharmony_ci#include <unistd.h>
30f857971dSopenharmony_ci#include <sys/ioctl.h>
31f857971dSopenharmony_ci#include <sys/stat.h>
32f857971dSopenharmony_ci#include <sys/types.h>
33f857971dSopenharmony_ci
34f857971dSopenharmony_ci#include <securec.h>
35f857971dSopenharmony_ci
36f857971dSopenharmony_ci#include "devicestatus_define.h"
37f857971dSopenharmony_ci#include "fi_log.h"
38f857971dSopenharmony_ci#include "if_stream_wrap.h"
39f857971dSopenharmony_ci#include "napi_constants.h"
40f857971dSopenharmony_ci#include "utility.h"
41f857971dSopenharmony_ci#include "virtual_mouse.h"
42f857971dSopenharmony_ci#include "virtual_touchscreen.h"
43f857971dSopenharmony_ci
44f857971dSopenharmony_ci#undef LOG_TAG
45f857971dSopenharmony_ci#define LOG_TAG "VirtualDeviceBuilder"
46f857971dSopenharmony_ci
47f857971dSopenharmony_cinamespace OHOS {
48f857971dSopenharmony_cinamespace Msdp {
49f857971dSopenharmony_cinamespace DeviceStatus {
50f857971dSopenharmony_cinamespace {
51f857971dSopenharmony_ciconstexpr int32_t MAXIMUM_WAIT_TIME_ALLOWED { 3000 };
52f857971dSopenharmony_ciconstexpr int32_t MINIMUM_WAIT_TIME_ALLOWED { 5 };
53f857971dSopenharmony_ciconstexpr ssize_t MAXIMUM_FILESIZE_ALLOWED { 0x100000 };
54f857971dSopenharmony_ci} // namespace
55f857971dSopenharmony_ci
56f857971dSopenharmony_ciVirtualDeviceBuilder::VirtualDeviceBuilder(const std::string &name, uint16_t bustype,
57f857971dSopenharmony_ci                                           uint16_t vendor, uint16_t product)
58f857971dSopenharmony_ci    : uinputDev_ {
59f857971dSopenharmony_ci        .id = {
60f857971dSopenharmony_ci            .bustype = bustype,
61f857971dSopenharmony_ci            .vendor = vendor,
62f857971dSopenharmony_ci            .product = product,
63f857971dSopenharmony_ci            .version = 1
64f857971dSopenharmony_ci        }
65f857971dSopenharmony_ci    }
66f857971dSopenharmony_ci{
67f857971dSopenharmony_ci    if (strcpy_s(uinputDev_.name, sizeof(uinputDev_.name), name.c_str()) != EOK) {
68f857971dSopenharmony_ci        FI_HILOGE("Invalid device name:\'%{public}s\'", name.c_str());
69f857971dSopenharmony_ci    }
70f857971dSopenharmony_ci}
71f857971dSopenharmony_ci
72f857971dSopenharmony_ciVirtualDeviceBuilder::VirtualDeviceBuilder(const std::string &name, std::shared_ptr<VirtualDevice> vDev) : vDev_(vDev)
73f857971dSopenharmony_ci{
74f857971dSopenharmony_ci    CopyProperties(name, vDev);
75f857971dSopenharmony_ci}
76f857971dSopenharmony_ci
77f857971dSopenharmony_ciVirtualDeviceBuilder::~VirtualDeviceBuilder()
78f857971dSopenharmony_ci{
79f857971dSopenharmony_ci    Close();
80f857971dSopenharmony_ci}
81f857971dSopenharmony_ci
82f857971dSopenharmony_civoid VirtualDeviceBuilder::Daemonize()
83f857971dSopenharmony_ci{
84f857971dSopenharmony_ci    int32_t fd = fork();
85f857971dSopenharmony_ci    if (fd < 0) {
86f857971dSopenharmony_ci        exit(EXIT_FAILURE);
87f857971dSopenharmony_ci    } else if (fd > 0) {
88f857971dSopenharmony_ci        exit(EXIT_SUCCESS);
89f857971dSopenharmony_ci    }
90f857971dSopenharmony_ci    if (setsid() < 0) {
91f857971dSopenharmony_ci        exit(EXIT_SUCCESS);
92f857971dSopenharmony_ci    }
93f857971dSopenharmony_ci    fd = fork();
94f857971dSopenharmony_ci    if (fd < 0) {
95f857971dSopenharmony_ci        exit(EXIT_FAILURE);
96f857971dSopenharmony_ci    } else if (fd > 0) {
97f857971dSopenharmony_ci        exit(EXIT_SUCCESS);
98f857971dSopenharmony_ci    }
99f857971dSopenharmony_ci    close(STDIN_FILENO);
100f857971dSopenharmony_ci    fd = open("/dev/null", O_RDWR);
101f857971dSopenharmony_ci    if (fd != STDIN_FILENO) {
102f857971dSopenharmony_ci        exit(EXIT_FAILURE);
103f857971dSopenharmony_ci    }
104f857971dSopenharmony_ci    if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) {
105f857971dSopenharmony_ci        exit(EXIT_FAILURE);
106f857971dSopenharmony_ci    }
107f857971dSopenharmony_ci    if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
108f857971dSopenharmony_ci        exit(EXIT_FAILURE);
109f857971dSopenharmony_ci    }
110f857971dSopenharmony_ci}
111f857971dSopenharmony_ci
112f857971dSopenharmony_civoid VirtualDeviceBuilder::ConcatenationName(std::string &sLine)
113f857971dSopenharmony_ci{
114f857971dSopenharmony_ci    auto s = sLine.begin();
115f857971dSopenharmony_ci    while (s != sLine.end() && (isspace(*s) || (*s == '\0'))) {
116f857971dSopenharmony_ci        s = sLine.erase(s);
117f857971dSopenharmony_ci    }
118f857971dSopenharmony_ci    while (s != sLine.end()) {
119f857971dSopenharmony_ci        while (s != sLine.end() && !isspace(*s) && *s != '\0') {
120f857971dSopenharmony_ci            ++s;
121f857971dSopenharmony_ci        }
122f857971dSopenharmony_ci        auto t = s;
123f857971dSopenharmony_ci        while (t != sLine.end() && (isspace(*t) || (*t == '\0'))) {
124f857971dSopenharmony_ci            ++t;
125f857971dSopenharmony_ci        }
126f857971dSopenharmony_ci        if (t != sLine.end()) {
127f857971dSopenharmony_ci            *s++ = '_';
128f857971dSopenharmony_ci        }
129f857971dSopenharmony_ci        while (s != sLine.end() && (isspace(*s) || (*s == '\0'))) {
130f857971dSopenharmony_ci            s = sLine.erase(s);
131f857971dSopenharmony_ci        }
132f857971dSopenharmony_ci    }
133f857971dSopenharmony_ci}
134f857971dSopenharmony_ci
135f857971dSopenharmony_cibool VirtualDeviceBuilder::ExecuteUnmount(const char *id, const char *name, const std::string &direntName)
136f857971dSopenharmony_ci{
137f857971dSopenharmony_ci    std::ostringstream sPattern;
138f857971dSopenharmony_ci    sPattern << "^vdevadm_(mount|clone)_-t_?" << id;
139f857971dSopenharmony_ci    std::regex pattern { sPattern.str() };
140f857971dSopenharmony_ci    if (!Utility::IsInteger(direntName)) {
141f857971dSopenharmony_ci        return false;
142f857971dSopenharmony_ci    }
143f857971dSopenharmony_ci
144f857971dSopenharmony_ci    std::ostringstream spath;
145f857971dSopenharmony_ci    spath << "/proc/" << direntName;
146f857971dSopenharmony_ci    struct stat statBuf;
147f857971dSopenharmony_ci    if (stat(spath.str().c_str(), &statBuf) != 0) {
148f857971dSopenharmony_ci        std::cout << "stat \'" << spath.str() << "\' failed: " << strerror(errno) << std::endl;
149f857971dSopenharmony_ci        return false;
150f857971dSopenharmony_ci    }
151f857971dSopenharmony_ci    if (!S_ISDIR(statBuf.st_mode)) {
152f857971dSopenharmony_ci        return false;
153f857971dSopenharmony_ci    }
154f857971dSopenharmony_ci    spath << "/cmdline";
155f857971dSopenharmony_ci    char realPath[PATH_MAX] = { 0 };
156f857971dSopenharmony_ci    if (realpath(spath.str().c_str(), realPath) == nullptr) {
157f857971dSopenharmony_ci        std::cout << "Invalid path" << spath.str().c_str() << std::endl;
158f857971dSopenharmony_ci        return false;
159f857971dSopenharmony_ci    }
160f857971dSopenharmony_ci    IfStreamWrap fileStream;
161f857971dSopenharmony_ci    fileStream.ifStream = std::ifstream(spath.str(), std::ios::in);
162f857971dSopenharmony_ci    if (!fileStream.IsOpen()) {
163f857971dSopenharmony_ci        return false;
164f857971dSopenharmony_ci    }
165f857971dSopenharmony_ci    std::string sLine;
166f857971dSopenharmony_ci    while (std::getline(fileStream.ifStream, sLine)) {
167f857971dSopenharmony_ci        ConcatenationName(sLine);
168f857971dSopenharmony_ci        if (std::regex_search(sLine, pattern)) {
169f857971dSopenharmony_ci            std::cout << "\tfound: \'" << direntName << "\'" << std::endl;
170f857971dSopenharmony_ci            int32_t pid = std::atoi(direntName.c_str());
171f857971dSopenharmony_ci            if (kill(static_cast<pid_t>(pid), SIGTERM) != 0) {
172f857971dSopenharmony_ci                std::cout << "Failed to stop backing process [" << pid << "]: " << strerror(errno) << std::endl;
173f857971dSopenharmony_ci            } else {
174f857971dSopenharmony_ci                std::cout << "Unmount virtual " << name << " successfully." << std::endl;
175f857971dSopenharmony_ci            }
176f857971dSopenharmony_ci            return true;
177f857971dSopenharmony_ci        }
178f857971dSopenharmony_ci    }
179f857971dSopenharmony_ci    return false;
180f857971dSopenharmony_ci}
181f857971dSopenharmony_ci
182f857971dSopenharmony_civoid VirtualDeviceBuilder::Unmount(const char *name, const char *id)
183f857971dSopenharmony_ci{
184f857971dSopenharmony_ci    std::cout << "Start to unmount virtual " << name << " ..." << std::endl;
185f857971dSopenharmony_ci    DIR *procDir = opendir("/proc");
186f857971dSopenharmony_ci    if (procDir == nullptr) {
187f857971dSopenharmony_ci        std::cout << "Failed to unmount virtual " << name << ": " << strerror(errno) << std::endl;
188f857971dSopenharmony_ci        return;
189f857971dSopenharmony_ci    }
190f857971dSopenharmony_ci
191f857971dSopenharmony_ci    struct dirent *dent;
192f857971dSopenharmony_ci    while ((dent = readdir(procDir)) != nullptr) {
193f857971dSopenharmony_ci        std::string direntName { dent->d_name };
194f857971dSopenharmony_ci        if (ExecuteUnmount(id, name, direntName)) {
195f857971dSopenharmony_ci            goto EXIT;
196f857971dSopenharmony_ci        }
197f857971dSopenharmony_ci    }
198f857971dSopenharmony_ci    std::cout << "The backing process for virtual " << name << "can't be found." << std::endl;
199f857971dSopenharmony_ciEXIT:
200f857971dSopenharmony_ci    if (closedir(procDir) != 0) {
201f857971dSopenharmony_ci        FI_HILOGE("closedir error:%{public}s", strerror(errno));
202f857971dSopenharmony_ci    }
203f857971dSopenharmony_ci}
204f857971dSopenharmony_ci
205f857971dSopenharmony_civoid VirtualDeviceBuilder::SetSupportedEvents()
206f857971dSopenharmony_ci{
207f857971dSopenharmony_ci    static const std::map<int32_t, std::function<std::vector<uint32_t>()>> uinputTypes {
208f857971dSopenharmony_ci        { UI_SET_EVBIT, [this] { return this->GetEventTypes(); } },
209f857971dSopenharmony_ci        { UI_SET_KEYBIT, [this] { return this->GetKeys(); } },
210f857971dSopenharmony_ci        { UI_SET_PROPBIT, [this] { return this->GetProperties(); } },
211f857971dSopenharmony_ci        { UI_SET_ABSBIT, [this] { return this->GetAbs(); } },
212f857971dSopenharmony_ci        { UI_SET_RELBIT, [this] { return this->GetRelBits(); } },
213f857971dSopenharmony_ci        { UI_SET_MSCBIT, [this] { return this->GetMiscellaneous(); } },
214f857971dSopenharmony_ci        { UI_SET_LEDBIT, [this] { return this->GetLeds(); } },
215f857971dSopenharmony_ci        { UI_SET_SWBIT, [this] { return this->GetSwitches(); } },
216f857971dSopenharmony_ci        { UI_SET_FFBIT, [this] { return this->GetRepeats(); } }
217f857971dSopenharmony_ci    };
218f857971dSopenharmony_ci
219f857971dSopenharmony_ci    for (const auto &setEvents : uinputTypes) {
220f857971dSopenharmony_ci        const auto &events = setEvents.second();
221f857971dSopenharmony_ci        for (const auto &e : events) {
222f857971dSopenharmony_ci            if (ioctl(fd_, setEvents.first, e) < 0) {
223f857971dSopenharmony_ci                FI_HILOGE("Failed while setting event type:%{public}s", strerror(errno));
224f857971dSopenharmony_ci            }
225f857971dSopenharmony_ci        }
226f857971dSopenharmony_ci    }
227f857971dSopenharmony_ci}
228f857971dSopenharmony_ci
229f857971dSopenharmony_civoid VirtualDeviceBuilder::SetAbsResolution()
230f857971dSopenharmony_ci{
231f857971dSopenharmony_ci    for (const auto &item : absInit_) {
232f857971dSopenharmony_ci        if (ioctl(fd_, UI_ABS_SETUP, &item) < 0) {
233f857971dSopenharmony_ci            FI_HILOGE("Failed while setting abs info:%{public}s", strerror(errno));
234f857971dSopenharmony_ci        }
235f857971dSopenharmony_ci    }
236f857971dSopenharmony_ci}
237f857971dSopenharmony_ci
238f857971dSopenharmony_civoid VirtualDeviceBuilder::SetPhys()
239f857971dSopenharmony_ci{
240f857971dSopenharmony_ci    std::string phys;
241f857971dSopenharmony_ci
242f857971dSopenharmony_ci    if (vDev_ != nullptr) {
243f857971dSopenharmony_ci        phys = vDev_->GetPhys();
244f857971dSopenharmony_ci    } else {
245f857971dSopenharmony_ci        static const std::map<std::string, std::string> mapNames {
246f857971dSopenharmony_ci            { "Virtual Mouse", "mouse" },
247f857971dSopenharmony_ci            { "Virtual TouchScreen", "touchscreen" },
248f857971dSopenharmony_ci            { "Virtual Keyboard", "Keyboard" },
249f857971dSopenharmony_ci        };
250f857971dSopenharmony_ci        auto tIter = mapNames.find(std::string(uinputDev_.name));
251f857971dSopenharmony_ci        if (tIter == mapNames.cend()) {
252f857971dSopenharmony_ci            FI_HILOGE("Unrecognized device name");
253f857971dSopenharmony_ci            return;
254f857971dSopenharmony_ci        }
255f857971dSopenharmony_ci        phys = tIter->second;
256f857971dSopenharmony_ci        phys.append("/").append(std::to_string(getpid()));
257f857971dSopenharmony_ci    }
258f857971dSopenharmony_ci
259f857971dSopenharmony_ci    if (ioctl(fd_, UI_SET_PHYS, phys.c_str()) < 0) {
260f857971dSopenharmony_ci        FI_HILOGE("Failed while setting phys:%{public}s", strerror(errno));
261f857971dSopenharmony_ci    }
262f857971dSopenharmony_ci}
263f857971dSopenharmony_ci
264f857971dSopenharmony_civoid VirtualDeviceBuilder::SetIdentity()
265f857971dSopenharmony_ci{
266f857971dSopenharmony_ci    if (write(fd_, &uinputDev_, sizeof(uinputDev_)) < 0) {
267f857971dSopenharmony_ci        FI_HILOGE("Unable to set uinput device info:%{public}s", strerror(errno));
268f857971dSopenharmony_ci    }
269f857971dSopenharmony_ci}
270f857971dSopenharmony_ci
271f857971dSopenharmony_cibool VirtualDeviceBuilder::SetUp()
272f857971dSopenharmony_ci{
273f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
274f857971dSopenharmony_ci    fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
275f857971dSopenharmony_ci    if (fd_ < 0) {
276f857971dSopenharmony_ci        FI_HILOGE("Unable to open uinput");
277f857971dSopenharmony_ci        return false;
278f857971dSopenharmony_ci    }
279f857971dSopenharmony_ci
280f857971dSopenharmony_ci    SetAbsResolution();
281f857971dSopenharmony_ci    SetPhys();
282f857971dSopenharmony_ci    SetSupportedEvents();
283f857971dSopenharmony_ci    SetIdentity();
284f857971dSopenharmony_ci
285f857971dSopenharmony_ci    if (ioctl(fd_, UI_DEV_CREATE) < 0) {
286f857971dSopenharmony_ci        FI_HILOGE("Failed to setup uinput device");
287f857971dSopenharmony_ci        if (close(fd_) != 0) {
288f857971dSopenharmony_ci            FI_HILOGE("Close error:%{public}s", strerror(errno));
289f857971dSopenharmony_ci        }
290f857971dSopenharmony_ci        fd_ = -1;
291f857971dSopenharmony_ci        return false;
292f857971dSopenharmony_ci    }
293f857971dSopenharmony_ci    return true;
294f857971dSopenharmony_ci}
295f857971dSopenharmony_ci
296f857971dSopenharmony_civoid VirtualDeviceBuilder::Close()
297f857971dSopenharmony_ci{
298f857971dSopenharmony_ci    if (fd_ >= 0) {
299f857971dSopenharmony_ci        if (ioctl(fd_, UI_DEV_DESTROY) < 0) {
300f857971dSopenharmony_ci            FI_HILOGE("ioctl error:%{public}s", strerror(errno));
301f857971dSopenharmony_ci        }
302f857971dSopenharmony_ci        if (close(fd_) != 0) {
303f857971dSopenharmony_ci            FI_HILOGE("close error:%{public}s", strerror(errno));
304f857971dSopenharmony_ci        }
305f857971dSopenharmony_ci        fd_ = -1;
306f857971dSopenharmony_ci    }
307f857971dSopenharmony_ci}
308f857971dSopenharmony_ci
309f857971dSopenharmony_civoid VirtualDeviceBuilder::SetResolution(const ResolutionInfo &resolutionInfo)
310f857971dSopenharmony_ci{
311f857971dSopenharmony_ci    uinputAbs_.code = resolutionInfo.axisCode;
312f857971dSopenharmony_ci    uinputAbs_.absinfo.resolution = resolutionInfo.absResolution;
313f857971dSopenharmony_ci    absInit_.push_back(uinputAbs_);
314f857971dSopenharmony_ci}
315f857971dSopenharmony_ci
316f857971dSopenharmony_civoid VirtualDeviceBuilder::SetAbsValue(const AbsInfo &absInfo)
317f857971dSopenharmony_ci{
318f857971dSopenharmony_ci    uinputDev_.absmin[absInfo.code] = absInfo.minValue;
319f857971dSopenharmony_ci    uinputDev_.absmax[absInfo.code] = absInfo.maxValue;
320f857971dSopenharmony_ci    uinputDev_.absfuzz[absInfo.code] = absInfo.fuzz;
321f857971dSopenharmony_ci    uinputDev_.absflat[absInfo.code] = absInfo.flat;
322f857971dSopenharmony_ci}
323f857971dSopenharmony_ci
324f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetEventTypes() const
325f857971dSopenharmony_ci{
326f857971dSopenharmony_ci    return eventTypes_;
327f857971dSopenharmony_ci}
328f857971dSopenharmony_ci
329f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetKeys() const
330f857971dSopenharmony_ci{
331f857971dSopenharmony_ci    return keys_;
332f857971dSopenharmony_ci}
333f857971dSopenharmony_ci
334f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetProperties() const
335f857971dSopenharmony_ci{
336f857971dSopenharmony_ci    return properties_;
337f857971dSopenharmony_ci}
338f857971dSopenharmony_ci
339f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetAbs() const
340f857971dSopenharmony_ci{
341f857971dSopenharmony_ci    return abs_;
342f857971dSopenharmony_ci}
343f857971dSopenharmony_ci
344f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetRelBits() const
345f857971dSopenharmony_ci{
346f857971dSopenharmony_ci    return relBits_;
347f857971dSopenharmony_ci}
348f857971dSopenharmony_ci
349f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetLeds() const
350f857971dSopenharmony_ci{
351f857971dSopenharmony_ci    return leds_;
352f857971dSopenharmony_ci}
353f857971dSopenharmony_ci
354f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetRepeats() const
355f857971dSopenharmony_ci{
356f857971dSopenharmony_ci    return repeats_;
357f857971dSopenharmony_ci}
358f857971dSopenharmony_ci
359f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetMiscellaneous() const
360f857971dSopenharmony_ci{
361f857971dSopenharmony_ci    return miscellaneous_;
362f857971dSopenharmony_ci}
363f857971dSopenharmony_ci
364f857971dSopenharmony_ciconst std::vector<uint32_t> &VirtualDeviceBuilder::GetSwitches() const
365f857971dSopenharmony_ci{
366f857971dSopenharmony_ci    return switches_;
367f857971dSopenharmony_ci}
368f857971dSopenharmony_ci
369f857971dSopenharmony_civoid VirtualDeviceBuilder::WaitFor(const char *path, const char *name)
370f857971dSopenharmony_ci{
371f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
372f857971dSopenharmony_ci    CHKPV(path);
373f857971dSopenharmony_ci    if (!Utility::IsInteger(std::string(path))) {
374f857971dSopenharmony_ci        std::cout << "Invalid argument to \'-w\', time duration of integer type is expected." << std::endl;
375f857971dSopenharmony_ci        return;
376f857971dSopenharmony_ci    }
377f857971dSopenharmony_ci    WaitFor(name, std::atoi(path));
378f857971dSopenharmony_ci}
379f857971dSopenharmony_ci
380f857971dSopenharmony_civoid VirtualDeviceBuilder::WaitFor(const char *name, int32_t timeout)
381f857971dSopenharmony_ci{
382f857971dSopenharmony_ci    CHKPV(name);
383f857971dSopenharmony_ci    if (timeout < MINIMUM_WAIT_TIME_ALLOWED) {
384f857971dSopenharmony_ci        std::cout << "Minimum wait time is " << MINIMUM_WAIT_TIME_ALLOWED << ", no wait." << std::endl;
385f857971dSopenharmony_ci        return;
386f857971dSopenharmony_ci    }
387f857971dSopenharmony_ci    if (timeout > MAXIMUM_WAIT_TIME_ALLOWED) {
388f857971dSopenharmony_ci        std::cout << "Maximum wait time is " << MAXIMUM_WAIT_TIME_ALLOWED << ", set wait time to this." << std::endl;
389f857971dSopenharmony_ci        timeout = MAXIMUM_WAIT_TIME_ALLOWED;
390f857971dSopenharmony_ci    }
391f857971dSopenharmony_ci    std::cout << "[" << name << "] wait for " << timeout << " milliseconds." << std::endl;
392f857971dSopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
393f857971dSopenharmony_ci}
394f857971dSopenharmony_ci
395f857971dSopenharmony_ciint32_t VirtualDeviceBuilder::ReadFile(const char *path, json &model)
396f857971dSopenharmony_ci{
397f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
398f857971dSopenharmony_ci    CHKPR(path, RET_ERR);
399f857971dSopenharmony_ci    char realPath[PATH_MAX] {};
400f857971dSopenharmony_ci
401f857971dSopenharmony_ci    if (realpath(path, realPath) == nullptr) {
402f857971dSopenharmony_ci        std::cout << "Invalid path: " << path << std::endl;
403f857971dSopenharmony_ci        return RET_ERR;
404f857971dSopenharmony_ci    }
405f857971dSopenharmony_ci    if (Utility::GetFileSize(realPath) > MAXIMUM_FILESIZE_ALLOWED) {
406f857971dSopenharmony_ci        std::cout << "File is too large" << std::endl;
407f857971dSopenharmony_ci        return RET_ERR;
408f857971dSopenharmony_ci    }
409f857971dSopenharmony_ci    std::cout << "Read input data from \'" << realPath << "\'" << std::endl;
410f857971dSopenharmony_ci    IfStreamWrap fileStream;
411f857971dSopenharmony_ci    fileStream.ifStream = std::ifstream(std::string(realPath));
412f857971dSopenharmony_ci    if (!fileStream.IsOpen()) {
413f857971dSopenharmony_ci        FI_HILOGE("Could not open the file");
414f857971dSopenharmony_ci        return RET_ERR;
415f857971dSopenharmony_ci    }
416f857971dSopenharmony_ci    model = nlohmann::json::parse(fileStream.ifStream, nullptr, false);
417f857971dSopenharmony_ci    if (model.is_discarded()) {
418f857971dSopenharmony_ci        FI_HILOGE("model parse failed");
419f857971dSopenharmony_ci        return RET_ERR;
420f857971dSopenharmony_ci    }
421f857971dSopenharmony_ci    return RET_OK;
422f857971dSopenharmony_ci}
423f857971dSopenharmony_ci
424f857971dSopenharmony_ciint32_t VirtualDeviceBuilder::ScanFor(std::function<bool(std::shared_ptr<VirtualDevice>)> pred,
425f857971dSopenharmony_ci    std::vector<std::shared_ptr<VirtualDevice>> &vDevs)
426f857971dSopenharmony_ci{
427f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
428f857971dSopenharmony_ci    DIR *dir = opendir(DEV_INPUT_PATH.c_str());
429f857971dSopenharmony_ci    if (dir == nullptr) {
430f857971dSopenharmony_ci        FI_HILOGE("Failed to open directory \'%{public}s\':%{public}s", DEV_INPUT_PATH.c_str(), strerror(errno));
431f857971dSopenharmony_ci        return RET_ERR;
432f857971dSopenharmony_ci    }
433f857971dSopenharmony_ci    struct dirent *dent;
434f857971dSopenharmony_ci
435f857971dSopenharmony_ci    while ((dent = readdir(dir)) != nullptr) {
436f857971dSopenharmony_ci        const std::string devNode { dent->d_name };
437f857971dSopenharmony_ci        const std::string devPath { DEV_INPUT_PATH + devNode };
438f857971dSopenharmony_ci        struct stat statbuf;
439f857971dSopenharmony_ci
440f857971dSopenharmony_ci        if ((std::strcmp(dent->d_name, ".") == 0) || (std::strcmp(dent->d_name, "..") == 0)) {
441f857971dSopenharmony_ci            continue;
442f857971dSopenharmony_ci        }
443f857971dSopenharmony_ci        if (stat(devPath.c_str(), &statbuf) != 0) {
444f857971dSopenharmony_ci            continue;
445f857971dSopenharmony_ci        }
446f857971dSopenharmony_ci        if (!S_ISCHR(statbuf.st_mode)) {
447f857971dSopenharmony_ci            continue;
448f857971dSopenharmony_ci        }
449f857971dSopenharmony_ci        auto vdev = std::make_shared<VirtualDevice>(devPath);
450f857971dSopenharmony_ci        if (pred(vdev)) {
451f857971dSopenharmony_ci            vDevs.push_back(vdev);
452f857971dSopenharmony_ci        }
453f857971dSopenharmony_ci    }
454f857971dSopenharmony_ci    if (closedir(dir) != 0) {
455f857971dSopenharmony_ci        FI_HILOGE("closedir error:%{public}s", strerror(errno));
456f857971dSopenharmony_ci    }
457f857971dSopenharmony_ci    return RET_OK;
458f857971dSopenharmony_ci}
459f857971dSopenharmony_ci
460f857971dSopenharmony_cistd::shared_ptr<VirtualDevice> VirtualDeviceBuilder::Select(
461f857971dSopenharmony_ci    std::vector<std::shared_ptr<VirtualDevice>> &vDevs, const char *name)
462f857971dSopenharmony_ci{
463f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
464f857971dSopenharmony_ci    if (vDevs.empty()) {
465f857971dSopenharmony_ci        std::cout << "No " << name << "." << std::endl;
466f857971dSopenharmony_ci        return nullptr;
467f857971dSopenharmony_ci    }
468f857971dSopenharmony_ci    auto vDev = vDevs.front();
469f857971dSopenharmony_ci
470f857971dSopenharmony_ci    if (vDevs.size() > 1) {
471f857971dSopenharmony_ci        std::cout << "More than one " << name << " were found, please select one to clone:" << std::endl;
472f857971dSopenharmony_ci        size_t index = 0;
473f857971dSopenharmony_ci
474f857971dSopenharmony_ci        for (const auto &v : vDevs) {
475f857971dSopenharmony_ci            std::cout << "[" << index << "]\t" << v->GetName() << std::endl;
476f857971dSopenharmony_ci            ++index;
477f857971dSopenharmony_ci        }
478f857971dSopenharmony_ci        std::cout << "[>=" << index << "]\tQuit" << std::endl;
479f857971dSopenharmony_ci        std::cin >> index;
480f857971dSopenharmony_ci        if (index >= vDevs.size()) {
481f857971dSopenharmony_ci            std::cout << "Selected index is out of range, quit." << std::endl;
482f857971dSopenharmony_ci            return nullptr;
483f857971dSopenharmony_ci        }
484f857971dSopenharmony_ci        vDev = vDevs[index];
485f857971dSopenharmony_ci    }
486f857971dSopenharmony_ci    return vDev;
487f857971dSopenharmony_ci}
488f857971dSopenharmony_ci
489f857971dSopenharmony_civoid VirtualDeviceBuilder::CopyProperties(const std::string &name, std::shared_ptr<VirtualDevice> vDev)
490f857971dSopenharmony_ci{
491f857971dSopenharmony_ci    CHKPV(vDev);
492f857971dSopenharmony_ci    CopyIdentity(name, vDev);
493f857971dSopenharmony_ci    CopyAbsInfo(vDev);
494f857971dSopenharmony_ci    CopyEvents(vDev);
495f857971dSopenharmony_ci}
496f857971dSopenharmony_ci
497f857971dSopenharmony_civoid VirtualDeviceBuilder::CopyIdentity(const std::string &name, std::shared_ptr<VirtualDevice> vDev)
498f857971dSopenharmony_ci{
499f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
500f857971dSopenharmony_ci    CHKPV(vDev);
501f857971dSopenharmony_ci    uinputDev_.id = vDev->GetInputId();
502f857971dSopenharmony_ci    if (strcpy_s(uinputDev_.name, sizeof(uinputDev_.name), name.c_str()) != EOK) {
503f857971dSopenharmony_ci        FI_HILOGE("Invalid device name:\'%{public}s\'", name.c_str());
504f857971dSopenharmony_ci    }
505f857971dSopenharmony_ci}
506f857971dSopenharmony_ci
507f857971dSopenharmony_civoid VirtualDeviceBuilder::CopyAbsInfo(std::shared_ptr<VirtualDevice> vDev)
508f857971dSopenharmony_ci{
509f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
510f857971dSopenharmony_ci    CHKPV(vDev);
511f857971dSopenharmony_ci    for (size_t abs = ABS_X; abs < ABS_CNT; ++abs) {
512f857971dSopenharmony_ci        struct uinput_abs_setup absSetup {
513f857971dSopenharmony_ci            .code = static_cast<__u16>(abs),
514f857971dSopenharmony_ci        };
515f857971dSopenharmony_ci        if (!vDev->QueryAbsInfo(abs, absSetup.absinfo)) {
516f857971dSopenharmony_ci            FI_HILOGE("Failed to get abs info for axis %{public}zu", abs);
517f857971dSopenharmony_ci            continue;
518f857971dSopenharmony_ci        }
519f857971dSopenharmony_ci        if (absSetup.absinfo.value == 0 && absSetup.absinfo.minimum == 0 &&
520f857971dSopenharmony_ci            absSetup.absinfo.maximum <= absSetup.absinfo.minimum && absSetup.absinfo.fuzz == 0 &&
521f857971dSopenharmony_ci            absSetup.absinfo.flat == 0 && absSetup.absinfo.resolution == 0) {
522f857971dSopenharmony_ci            continue;
523f857971dSopenharmony_ci        }
524f857971dSopenharmony_ci        absInit_.push_back(absSetup);
525f857971dSopenharmony_ci        uinputDev_.absmin[abs] = absSetup.absinfo.minimum;
526f857971dSopenharmony_ci        uinputDev_.absmax[abs] = absSetup.absinfo.maximum;
527f857971dSopenharmony_ci        uinputDev_.absfuzz[abs] = absSetup.absinfo.fuzz;
528f857971dSopenharmony_ci        uinputDev_.absflat[abs] = absSetup.absinfo.flat;
529f857971dSopenharmony_ci    }
530f857971dSopenharmony_ci}
531f857971dSopenharmony_ci
532f857971dSopenharmony_civoid VirtualDeviceBuilder::CopyEvents(std::shared_ptr<VirtualDevice> vDev)
533f857971dSopenharmony_ci{
534f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
535f857971dSopenharmony_ci    CHKPV(vDev);
536f857971dSopenharmony_ci    for (uint32_t ev = EV_SYN; ev < EV_MAX; ++ev) {
537f857971dSopenharmony_ci        if (vDev->SupportEventType(ev)) {
538f857971dSopenharmony_ci            eventTypes_.push_back(ev);
539f857971dSopenharmony_ci        }
540f857971dSopenharmony_ci    }
541f857971dSopenharmony_ci    for (uint32_t key = KEY_ESC; key < KEY_MAX; ++key) {
542f857971dSopenharmony_ci        if (vDev->SupportKey(key)) {
543f857971dSopenharmony_ci            keys_.push_back(key);
544f857971dSopenharmony_ci        }
545f857971dSopenharmony_ci    }
546f857971dSopenharmony_ci    for (uint32_t abs = ABS_X; abs < ABS_MAX; ++abs) {
547f857971dSopenharmony_ci        if (vDev->SupportAbs(abs)) {
548f857971dSopenharmony_ci            abs_.push_back(abs);
549f857971dSopenharmony_ci        }
550f857971dSopenharmony_ci    }
551f857971dSopenharmony_ci    for (uint32_t rel = REL_X; rel < REL_MAX; ++rel) {
552f857971dSopenharmony_ci        if (vDev->SupportRel(rel)) {
553f857971dSopenharmony_ci            relBits_.push_back(rel);
554f857971dSopenharmony_ci        }
555f857971dSopenharmony_ci    }
556f857971dSopenharmony_ci    for (uint32_t msc = MSC_SERIAL; msc < MSC_MAX; ++msc) {
557f857971dSopenharmony_ci        if (vDev->SupportMsc(msc)) {
558f857971dSopenharmony_ci            miscellaneous_.push_back(msc);
559f857971dSopenharmony_ci        }
560f857971dSopenharmony_ci    }
561f857971dSopenharmony_ci    for (uint32_t led = LED_NUML; led < LED_MAX; ++led) {
562f857971dSopenharmony_ci        if (vDev->SupportLed(led)) {
563f857971dSopenharmony_ci            leds_.push_back(led);
564f857971dSopenharmony_ci        }
565f857971dSopenharmony_ci    }
566f857971dSopenharmony_ci    for (uint32_t rep = REP_DELAY; rep < REP_MAX; ++rep) {
567f857971dSopenharmony_ci        if (vDev->SupportRep(rep)) {
568f857971dSopenharmony_ci            repeats_.push_back(rep);
569f857971dSopenharmony_ci        }
570f857971dSopenharmony_ci    }
571f857971dSopenharmony_ci    for (uint32_t prop = INPUT_PROP_POINTER; prop < INPUT_PROP_MAX; ++prop) {
572f857971dSopenharmony_ci        if (vDev->SupportProperty(prop)) {
573f857971dSopenharmony_ci            properties_.push_back(prop);
574f857971dSopenharmony_ci        }
575f857971dSopenharmony_ci    }
576f857971dSopenharmony_ci}
577f857971dSopenharmony_ci} // namespace DeviceStatus
578f857971dSopenharmony_ci} // namespace Msdp
579f857971dSopenharmony_ci} // namespace OHOS