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