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