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