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