1 /*
2 * Copyright (c) 2022-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 "device.h"
17
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <sys/ioctl.h>
21
22 #include <cstring>
23 #include <fstream>
24 #include <map>
25 #include <regex>
26 #include <sstream>
27
28 #include <openssl/sha.h>
29 #include <securec.h>
30
31 #include "devicestatus_define.h"
32 #include "devicestatus_errors.h"
33 #include "fi_log.h"
34 #include "napi_constants.h"
35 #include "utility.h"
36
37 namespace OHOS {
38 namespace Msdp {
39 namespace DeviceStatus {
40 struct Range {
41 size_t start { 0 };
42 size_t end { 0 };
43 };
44
45 namespace {
46 constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "Device" };
47 constexpr int32_t COMMENT_SUBSCRIPT { 0 };
48 constexpr ssize_t MAX_FILE_SIZE_ALLOWED { 0x5000 };
49
50 const struct Range KEY_BLOCKS[] {
51 { KEY_ESC, BTN_MISC },
52 { KEY_OK, BTN_DPAD_UP },
53 { KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY }
54 };
55 } // namespace
56
Device(int32_t deviceId)57 Device::Device(int32_t deviceId)
58 : deviceId_(deviceId)
59 {}
60
~Device()61 Device::~Device()
62 {
63 Close();
64 }
65
Open()66 int32_t Device::Open()
67 {
68 CALL_DEBUG_ENTER;
69 char buf[PATH_MAX] {};
70 if (realpath(devPath_.c_str(), buf) == nullptr) {
71 FI_HILOGE("Not real path:%{public}s", devPath_.c_str());
72 return RET_ERR;
73 }
74
75 int32_t nRetries { 6 };
76 for (;;) {
77 Utility::ShowUserAndGroup();
78 Utility::ShowFileAttributes(buf);
79
80 fd_ = open(buf, O_RDWR | O_NONBLOCK | O_CLOEXEC);
81 if (fd_ < 0) {
82 FI_HILOGE("Open device \'%{public}s\':%{public}s failed", buf, strerror(errno));
83 if (nRetries-- > 0) {
84 static constexpr int32_t DEFAULT_WAIT_TIME { 500 };
85 std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_WAIT_TIME));
86 FI_HILOGI("Retry opening the device \'%{public}s\'", buf);
87 } else {
88 return RET_ERR;
89 }
90 } else {
91 FI_HILOGD("Successful opening \'%{public}s\'", buf);
92 break;
93 }
94 }
95 QueryDeviceInfo();
96 QuerySupportedEvents();
97 UpdateCapability();
98 LoadDeviceConfig();
99 return RET_OK;
100 }
101
Close()102 void Device::Close()
103 {
104 CALL_DEBUG_ENTER;
105 if (fd_ >= 0) {
106 if (close(fd_) < 0) {
107 FI_HILOGE("Close fd failed, error:%{public}s, fd_:%{public}d", strerror(errno), fd_);
108 }
109 fd_ = -1;
110 }
111 }
112
Dispatch(const struct epoll_event & ev)113 void Device::Dispatch(const struct epoll_event &ev)
114 {
115 if ((ev.events & EPOLLIN) == EPOLLIN) {
116 FI_HILOGD("Input data received");
117 } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
118 FI_HILOGE("Epoll hangup, errno:%{public}s", strerror(errno));
119 }
120 }
121
QueryDeviceInfo()122 void Device::QueryDeviceInfo()
123 {
124 CALL_DEBUG_ENTER;
125 char buffer[PATH_MAX] = { 0 };
126 int32_t rc = ioctl(fd_, EVIOCGNAME(sizeof(buffer) - 1), &buffer);
127 if (rc < 0) {
128 FI_HILOGE("Could not get device name, errno:%{public}s", strerror(errno));
129 } else {
130 name_.assign(buffer);
131 }
132
133 struct input_id inputId;
134 rc = ioctl(fd_, EVIOCGID, &inputId);
135 if (rc < 0) {
136 FI_HILOGE("Could not get device input id, errno:%{public}s", strerror(errno));
137 } else {
138 bus_ = inputId.bustype;
139 product_ = inputId.product;
140 vendor_ = inputId.vendor;
141 version_ = inputId.version;
142 }
143
144 errno_t ret = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
145 if (ret != EOK) {
146 FI_HILOGE("Call memset_s failed");
147 return;
148 }
149 rc = ioctl(fd_, EVIOCGPHYS(sizeof(buffer) - 1), &buffer);
150 if (rc < 0) {
151 FI_HILOGE("Could not get location:%{public}s", strerror(errno));
152 } else {
153 phys_.assign(buffer);
154 }
155 ret = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
156 if (ret != EOK) {
157 FI_HILOGE("Call memset_s failed");
158 return;
159 }
160 rc = ioctl(fd_, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer);
161 if (rc < 0) {
162 FI_HILOGE("Could not get uniq, errno:%{public}s", strerror(errno));
163 } else {
164 uniq_.assign(buffer);
165 }
166 }
167
GetEventMask(const std::string & eventName,uint32_t type,std::size_t arrayLength,uint8_t * whichBitMask) const168 void Device::GetEventMask(const std::string &eventName, uint32_t type,
169 std::size_t arrayLength, uint8_t *whichBitMask) const
170 {
171 int32_t rc = ioctl(fd_, EVIOCGBIT(type, arrayLength), whichBitMask);
172 if (rc < 0) {
173 FI_HILOGE("Could not get %{public}s events mask:%{public}s", eventName.c_str(), strerror(errno));
174 }
175 }
176
GetPropMask(const std::string & eventName,std::size_t arrayLength,uint8_t * whichBitMask) const177 void Device::GetPropMask(const std::string &eventName, std::size_t arrayLength, uint8_t *whichBitMask) const
178 {
179 int32_t rc = ioctl(fd_, EVIOCGPROP(arrayLength), whichBitMask);
180 if (rc < 0) {
181 FI_HILOGE("Could not get %{public}s mask:%{public}s", eventName.c_str(), strerror(errno));
182 }
183 }
184
QuerySupportedEvents()185 void Device::QuerySupportedEvents()
186 {
187 CALL_DEBUG_ENTER;
188 GetEventMask("", 0, sizeof(evBitmask_), evBitmask_);
189 GetEventMask("key", EV_KEY, sizeof(keyBitmask_), keyBitmask_);
190 GetEventMask("abs", EV_ABS, sizeof(absBitmask_), absBitmask_);
191 GetEventMask("rel", EV_REL, sizeof(relBitmask_), relBitmask_);
192 GetPropMask("properties", sizeof(propBitmask_), propBitmask_);
193 }
194
UpdateCapability()195 void Device::UpdateCapability()
196 {
197 CALL_DEBUG_ENTER;
198 CheckPointers();
199 CheckPencilMouse();
200 CheckKeys();
201 }
202
HasAxesOrButton(size_t start,size_t end,const uint8_t * whichBitMask) const203 bool Device::HasAxesOrButton(size_t start, size_t end, const uint8_t* whichBitMask) const
204 {
205 for (size_t type = start; type < end; ++type) {
206 if (TestBit(type, whichBitMask)) {
207 return true;
208 }
209 }
210 return false;
211 }
212
HasJoystickAxesOrButtons() const213 bool Device::HasJoystickAxesOrButtons() const
214 {
215 if (!TestBit(BTN_JOYSTICK - 1, keyBitmask_)) {
216 if (HasAxesOrButton(BTN_JOYSTICK, BTN_DIGI, keyBitmask_) ||
217 // BTN_TRIGGER_HAPPY40 + 1 : loop boundary
218 HasAxesOrButton(BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY40 + 1, keyBitmask_) ||
219 HasAxesOrButton(BTN_DPAD_UP, BTN_DPAD_RIGHT + 1, keyBitmask_)) { // BTN_DPAD_RIGHT + 1 : loop boundary
220 return true;
221 }
222 }
223 return HasAxesOrButton(ABS_RX, ABS_PRESSURE, absBitmask_);
224 }
225
HasAbsCoord() const226 bool Device::HasAbsCoord() const
227 {
228 return (HasAbs(ABS_X) && HasAbs(ABS_Y));
229 }
230
HasMtCoord() const231 bool Device::HasMtCoord() const
232 {
233 return (HasAbs(ABS_MT_POSITION_X) && HasAbs(ABS_MT_POSITION_Y));
234 }
235
HasRelCoord() const236 bool Device::HasRelCoord() const
237 {
238 return (HasRel(REL_X) && HasRel(REL_Y));
239 }
240
PrintCapsDevice() const241 void Device::PrintCapsDevice() const
242 {
243 const std::map<std::size_t, std::string> deviceComparisonTable {
244 { DEVICE_CAP_KEYBOARD, "keyboard" },
245 { DEVICE_CAP_TOUCH, "touch device" },
246 { DEVICE_CAP_POINTER, "pointer" },
247 { DEVICE_CAP_TABLET_TOOL, "tablet tool" },
248 { DEVICE_CAP_TABLET_PAD, "pad" },
249 { DEVICE_CAP_GESTURE, "gesture" },
250 { DEVICE_CAP_SWITCH, "switch" },
251 { DEVICE_CAP_JOYSTICK, "joystick" }
252 };
253 for (const auto &[cap, name]: deviceComparisonTable) {
254 if (caps_.test(cap)) {
255 FI_HILOGD("This is %{public}s", name.c_str());
256 }
257 }
258 }
259
CheckPointers()260 void Device::CheckPointers()
261 {
262 CALL_DEBUG_ENTER;
263 if (HasAbsCoord()) {
264 CheckAbs();
265 } else {
266 CheckJoystick();
267 }
268 if (HasMtCoord()) {
269 CheckMt();
270 }
271 CheckAdditional();
272 PrintCapsDevice();
273 }
274
CheckAbs()275 void Device::CheckAbs()
276 {
277 CALL_DEBUG_ENTER;
278 if (HasKey(BTN_STYLUS) || HasKey(BTN_TOOL_PEN)) {
279 caps_.set(DEVICE_CAP_TABLET_TOOL);
280 } else if (HasKey(BTN_TOOL_FINGER) && !HasKey(BTN_TOOL_PEN) && !HasProperty(INPUT_PROP_DIRECT)) {
281 caps_.set(DEVICE_CAP_POINTER);
282 } else if (HasAxesOrButton(BTN_MOUSE, BTN_JOYSTICK, keyBitmask_)) {
283 caps_.set(DEVICE_CAP_POINTER);
284 } else if (HasKey(BTN_TOUCH) || HasProperty(INPUT_PROP_DIRECT)) {
285 caps_.set(DEVICE_CAP_TOUCH);
286 } else if (HasJoystickAxesOrButtons()) {
287 caps_.set(DEVICE_CAP_JOYSTICK);
288 }
289 }
290
CheckJoystick()291 void Device::CheckJoystick()
292 {
293 CALL_DEBUG_ENTER;
294 if (HasJoystickAxesOrButtons()) {
295 caps_.set(DEVICE_CAP_JOYSTICK);
296 }
297 }
298
CheckMt()299 void Device::CheckMt()
300 {
301 CALL_DEBUG_ENTER;
302 if (HasKey(BTN_STYLUS) || HasKey(BTN_TOOL_PEN)) {
303 caps_.set(DEVICE_CAP_TABLET_TOOL);
304 } else if (HasKey(BTN_TOOL_FINGER) && !HasKey(BTN_TOOL_PEN) && !HasProperty(INPUT_PROP_DIRECT)) {
305 caps_.set(DEVICE_CAP_POINTER);
306 } else if (HasKey(BTN_TOUCH) || HasProperty(INPUT_PROP_DIRECT)) {
307 caps_.set(DEVICE_CAP_TOUCH);
308 }
309 }
310
CheckAdditional()311 void Device::CheckAdditional()
312 {
313 CALL_DEBUG_ENTER;
314 if (!HasCapability(DEVICE_CAP_TABLET_TOOL) &&
315 !HasCapability(DEVICE_CAP_POINTER) &&
316 !HasCapability(DEVICE_CAP_JOYSTICK) &&
317 HasAxesOrButton(BTN_MOUSE, BTN_JOYSTICK, keyBitmask_) &&
318 (HasRelCoord() || !HasAbsCoord())) {
319 caps_.set(DEVICE_CAP_POINTER);
320 }
321 }
322
CheckPencilMouse()323 void Device::CheckPencilMouse()
324 {
325 CALL_DEBUG_ENTER;
326 if (name_ == "M-Pencil Mouse") {
327 caps_.set(DEVICE_CAP_POINTER, 0);
328 }
329 }
330
CheckKeys()331 void Device::CheckKeys()
332 {
333 CALL_DEBUG_ENTER;
334 if (!TestBit(EV_KEY, evBitmask_)) {
335 FI_HILOGD("No EV_KEY capability");
336 return;
337 }
338 size_t length = sizeof(KEY_BLOCKS) / sizeof(struct Range);
339 for (size_t block { 0U }; block < length; ++block) {
340 for (size_t key = KEY_BLOCKS[block].start; key < KEY_BLOCKS[block].end; ++key) {
341 if (TestBit(key, keyBitmask_)) {
342 FI_HILOGD("Found key:%{public}zx", key);
343 caps_.set(DEVICE_CAP_KEYBOARD);
344 return;
345 }
346 }
347 }
348 }
349
MakeConfigFileName() const350 std::string Device::MakeConfigFileName() const
351 {
352 std::ostringstream ss;
353 ss << GetVendor() << "_" << GetProduct() << "_" << GetVersion() << "_" << GetName();
354 std::string fname { ss.str() };
355 Utility::RemoveSpace(fname);
356
357 std::ostringstream sp;
358 sp << "/vendor/etc/keymap/" << fname << ".TOML";
359 return sp.str();
360 }
361
ReadConfigFile(const std::string & filePath)362 int32_t Device::ReadConfigFile(const std::string &filePath)
363 {
364 CALL_DEBUG_ENTER;
365 std::ifstream cfgFile(filePath);
366 if (!cfgFile.is_open()) {
367 FI_HILOGE("Failed to open config file");
368 return FILE_OPEN_FAIL;
369 }
370 std::string tmp;
371 while (std::getline(cfgFile, tmp)) {
372 Utility::RemoveSpace(tmp);
373 size_t pos = tmp.find('#');
374 if ((pos != tmp.npos) && (pos != COMMENT_SUBSCRIPT)) {
375 FI_HILOGE("File format is error");
376 cfgFile.close();
377 return RET_ERR;
378 }
379 if (tmp.empty() || (tmp.front() == '#')) {
380 continue;
381 }
382 pos = tmp.find('=');
383 if ((pos == (tmp.size() - 1)) || (pos == tmp.npos)) {
384 FI_HILOGE("Find config item error");
385 cfgFile.close();
386 return RET_ERR;
387 }
388 std::string configItem = tmp.substr(0, pos);
389 std::string value = tmp.substr(pos + 1);
390 if (ConfigItemSwitch(configItem, value) == RET_ERR) {
391 FI_HILOGE("Configuration item error");
392 cfgFile.close();
393 return RET_ERR;
394 }
395 }
396 cfgFile.close();
397 return RET_OK;
398 }
399
ConfigItemSwitch(const std::string & configItem,const std::string & value)400 int32_t Device::ConfigItemSwitch(const std::string &configItem, const std::string &value)
401 {
402 CALL_DEBUG_ENTER;
403 const std::string CONFIG_ITEM_KEYBOARD_TYPE { "Key.keyboard.type" };
404 if (configItem.empty() || value.empty() || !Utility::IsInteger(value)) {
405 FI_HILOGE("Invalid configuration encountered");
406 return RET_ERR;
407 }
408 if (configItem == CONFIG_ITEM_KEYBOARD_TYPE) {
409 keyboardType_ = static_cast<IDevice::KeyboardType>(stoi(value));
410 }
411 return RET_OK;
412 }
413
ReadTomlFile(const std::string & filePath)414 int32_t Device::ReadTomlFile(const std::string &filePath)
415 {
416 CALL_DEBUG_ENTER;
417 char temp[PATH_MAX] {};
418 if (realpath(filePath.c_str(), temp) == nullptr) {
419 FI_HILOGE("Not real path (\'%{public}s\'):%{public}s", filePath.c_str(), strerror(errno));
420 return RET_ERR;
421 }
422 FI_HILOGD("Config file path:%{public}s", temp);
423
424 if (!Utility::DoesFileExist(temp)) {
425 FI_HILOGE("File does not exist:%{public}s", temp);
426 return RET_ERR;
427 }
428 if (Utility::GetFileSize(temp) > MAX_FILE_SIZE_ALLOWED) {
429 FI_HILOGE("File size is out of range");
430 return RET_ERR;
431 }
432 if (ReadConfigFile(std::string(temp)) != RET_OK) {
433 FI_HILOGE("ReadConfigFile failed");
434 return RET_ERR;
435 }
436 return RET_OK;
437 }
438
JudgeKeyboardType()439 void Device::JudgeKeyboardType()
440 {
441 CALL_DEBUG_ENTER;
442 if (TestBit(KEY_Q, keyBitmask_)) {
443 keyboardType_ = IDevice::KEYBOARD_TYPE_ALPHABETICKEYBOARD;
444 FI_HILOGD("The keyboard type is standard");
445 } else if (TestBit(KEY_HOME, keyBitmask_) && (GetBus() == BUS_BLUETOOTH)) {
446 keyboardType_ = IDevice::KEYBOARD_TYPE_REMOTECONTROL;
447 FI_HILOGD("The keyboard type is remote control");
448 } else if (TestBit(KEY_KP1, keyBitmask_)) {
449 keyboardType_ = IDevice::KEYBOARD_TYPE_DIGITALKEYBOARD;
450 FI_HILOGD("The keyboard type is digital keyboard");
451 } else if (TestBit(KEY_LEFTCTRL, keyBitmask_) &&
452 TestBit(KEY_RIGHTCTRL, keyBitmask_) &&
453 TestBit(KEY_F20, keyBitmask_)) {
454 keyboardType_ = IDevice::KEYBOARD_TYPE_HANDWRITINGPEN;
455 FI_HILOGD("The keyboard type is handwriting pen");
456 } else {
457 keyboardType_ = IDevice::KEYBOARD_TYPE_UNKNOWN;
458 FI_HILOGD("Undefined keyboard type");
459 }
460 }
461
LoadDeviceConfig()462 void Device::LoadDeviceConfig()
463 {
464 CALL_DEBUG_ENTER;
465 if (ReadTomlFile(MakeConfigFileName()) != RET_OK) {
466 FI_HILOGE("ReadTomlFile failed");
467 keyboardType_ = IDevice::KEYBOARD_TYPE_NONE;
468 }
469 if (IsKeyboard()) {
470 if ((keyboardType_ <= IDevice::KEYBOARD_TYPE_NONE) ||
471 (keyboardType_ >= IDevice::KEYBOARD_TYPE_MAX)) {
472 JudgeKeyboardType();
473 }
474 } else {
475 keyboardType_ = IDevice::KEYBOARD_TYPE_NONE;
476 }
477 FI_HILOGD("keyboard type:%{public}d", keyboardType_);
478 }
479 } // namespace DeviceStatus
480 } // namespace Msdp
481 } // namespace OHOS
482