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