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