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