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