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