• 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 <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