• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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