• 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("Unable to open device \'%{public}s\':%{public}s", 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 device \'%{public}s\'", buf);
87             } else {
88                 return RET_ERR;
89             }
90         } else {
91             FI_HILOGD("Opening \'%{public}s\' successfully", 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:%{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:%{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:%{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:%{public}s", strerror(errno));
163     } else {
164         uniq_.assign(buffer);
165     }
166 }
167 
QuerySupportedEvents()168 void Device::QuerySupportedEvents()
169 {
170     CALL_DEBUG_ENTER;
171     int32_t rc = ioctl(fd_, EVIOCGBIT(0, sizeof(evBitmask_)), evBitmask_);
172     if (rc < 0) {
173         FI_HILOGE("Could not get events mask:%{public}s", strerror(errno));
174     }
175     rc = ioctl(fd_, EVIOCGBIT(EV_KEY, sizeof(keyBitmask_)), keyBitmask_);
176     if (rc < 0) {
177         FI_HILOGE("Could not get key events mask:%{public}s", strerror(errno));
178     }
179     rc = ioctl(fd_, EVIOCGBIT(EV_ABS, sizeof(absBitmask_)), absBitmask_);
180     if (rc < 0) {
181         FI_HILOGE("Could not get abs events mask:%{public}s", strerror(errno));
182     }
183     rc = ioctl(fd_, EVIOCGBIT(EV_REL, sizeof(relBitmask_)), relBitmask_);
184     if (rc < 0) {
185         FI_HILOGE("Could not get rel events mask:%{public}s", strerror(errno));
186     }
187     rc = ioctl(fd_, EVIOCGPROP(sizeof(propBitmask_)), propBitmask_);
188     if (rc < 0) {
189         FI_HILOGE("Could not get properties mask:%{public}s", strerror(errno));
190     }
191 }
192 
UpdateCapability()193 void Device::UpdateCapability()
194 {
195     CALL_DEBUG_ENTER;
196     CheckPointers();
197     CheckPencilMouse();
198     CheckKeys();
199 }
200 
HasMouseButton() const201 bool Device::HasMouseButton() const
202 {
203     for (size_t button = BTN_MOUSE; button < BTN_JOYSTICK; ++button) {
204         if (TestBit(button, keyBitmask_)) {
205             return true;
206         }
207     }
208     return false;
209 }
210 
HasJoystickAxesOrButtons() const211 bool Device::HasJoystickAxesOrButtons() const
212 {
213     if (!TestBit(BTN_JOYSTICK - 1, keyBitmask_)) {
214         for (size_t button = BTN_JOYSTICK; button < BTN_DIGI; ++button) {
215             if (TestBit(button, keyBitmask_)) {
216                 return true;
217             }
218         }
219         for (size_t button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40; ++button) {
220             if (TestBit(button, keyBitmask_)) {
221                 return true;
222             }
223         }
224         for (size_t button = BTN_DPAD_UP; button <= BTN_DPAD_RIGHT; ++button) {
225             if (TestBit(button, keyBitmask_)) {
226                 return true;
227             }
228         }
229     }
230     for (size_t axis = ABS_RX; axis < ABS_PRESSURE; ++axis) {
231         if (TestBit(axis, absBitmask_)) {
232             return true;
233         }
234     }
235     return false;
236 }
237 
PrintCapsDevice() const238 void Device::PrintCapsDevice() const
239 {
240     std::map<int32_t, std::string> deviceComparisonTable {
241         {DEVICE_CAP_KEYBOARD, "keyboard"},
242         {DEVICE_CAP_TOUCH, "touch device"},
243         {DEVICE_CAP_POINTER, "pointer"},
244         {DEVICE_CAP_TABLET_TOOL, "tablet tool"},
245         {DEVICE_CAP_TABLET_PAD, "pad"},
246         {DEVICE_CAP_GESTURE, "gesture"},
247         {DEVICE_CAP_SWITCH, "switch"},
248         {DEVICE_CAP_JOYSTICK, "joystick"}};
249     for (int32_t i = 0; i < DEVICE_CAP_MAX; ++i) {
250         if (caps_[i] == 1) {
251             FI_HILOGD("This is %{public}s", deviceComparisonTable[i].c_str());
252         }
253     }
254 }
255 
CheckPointers()256 void Device::CheckPointers()
257 {
258     CALL_DEBUG_ENTER;
259     bool hasAbsCoords { TestBit(ABS_X, absBitmask_) && TestBit(ABS_Y, absBitmask_) };
260     bool hasMtCoords { TestBit(ABS_MT_POSITION_X, absBitmask_) && TestBit(ABS_MT_POSITION_Y, absBitmask_) };
261     bool isDirect { TestBit(INPUT_PROP_DIRECT, propBitmask_) };
262     bool hasTouch { TestBit(BTN_TOUCH, keyBitmask_) };
263     bool hasRelCoords { TestBit(REL_X, relBitmask_) && TestBit(REL_Y, relBitmask_) };
264     bool stylusOrPen { TestBit(BTN_STYLUS, keyBitmask_) || TestBit(BTN_TOOL_PEN, keyBitmask_) };
265     bool fingerButNoPen { TestBit(BTN_TOOL_FINGER, keyBitmask_) && !TestBit(BTN_TOOL_PEN, keyBitmask_) };
266     bool hasMouseBtn { HasMouseButton() };
267     bool hasJoystickFeature { HasJoystickAxesOrButtons() };
268 
269     if (hasAbsCoords) {
270         if (stylusOrPen) {
271             caps_.set(DEVICE_CAP_TABLET_TOOL);
272         } else if (fingerButNoPen && !isDirect) {
273             caps_.set(DEVICE_CAP_POINTER);
274         } else if (hasMouseBtn) {
275             caps_.set(DEVICE_CAP_POINTER);
276         } else if (hasTouch || isDirect) {
277             caps_.set(DEVICE_CAP_TOUCH);
278         } else if (hasJoystickFeature) {
279             caps_.set(DEVICE_CAP_JOYSTICK);
280         }
281     } else if (hasJoystickFeature) {
282         caps_.set(DEVICE_CAP_JOYSTICK);
283     }
284     if (hasMtCoords) {
285         if (stylusOrPen) {
286             caps_.set(DEVICE_CAP_TABLET_TOOL);
287         } else if (fingerButNoPen && !isDirect) {
288             caps_.set(DEVICE_CAP_POINTER);
289         } else if (hasTouch || isDirect) {
290             caps_.set(DEVICE_CAP_TOUCH);
291         }
292     }
293     if (!caps_.test(DEVICE_CAP_TABLET_TOOL) && !caps_.test(DEVICE_CAP_POINTER) &&
294         !caps_.test(DEVICE_CAP_JOYSTICK) && hasMouseBtn && (hasRelCoords || !hasAbsCoords)) {
295         caps_.set(DEVICE_CAP_POINTER);
296     }
297     PrintCapsDevice();
298 }
299 
CheckPencilMouse()300 void Device::CheckPencilMouse()
301 {
302     CALL_DEBUG_ENTER;
303     if (name_ == "M-Pencil Mouse") {
304         caps_.set(DEVICE_CAP_POINTER, 0);
305     }
306 }
307 
CheckKeys()308 void Device::CheckKeys()
309 {
310     CALL_DEBUG_ENTER;
311     if (!TestBit(EV_KEY, evBitmask_)) {
312         FI_HILOGD("No EV_KEY capability");
313         return;
314     }
315     size_t length = sizeof(KEY_BLOCKS) / sizeof(struct Range);
316     for (size_t block { 0U }; block < length; ++block) {
317         for (size_t key = KEY_BLOCKS[block].start; key < KEY_BLOCKS[block].end; ++key) {
318             if (TestBit(key, keyBitmask_)) {
319                 FI_HILOGD("Found key:%{public}zx", key);
320                 caps_.set(DEVICE_CAP_KEYBOARD);
321                 return;
322             }
323         }
324     }
325 }
326 
MakeConfigFileName() const327 std::string Device::MakeConfigFileName() const
328 {
329     std::ostringstream ss;
330     ss << GetVendor() << "_" << GetProduct() << "_" << GetVersion() << "_" << GetName();
331     std::string fname { ss.str() };
332     Utility::RemoveSpace(fname);
333 
334     std::ostringstream sp;
335     sp << "/vendor/etc/keymap/" << fname << ".TOML";
336     return sp.str();
337 }
338 
ReadConfigFile(const std::string & filePath)339 int32_t Device::ReadConfigFile(const std::string &filePath)
340 {
341     CALL_DEBUG_ENTER;
342     std::ifstream cfgFile(filePath);
343     if (!cfgFile.is_open()) {
344         FI_HILOGE("Failed to open config file");
345         return FILE_OPEN_FAIL;
346     }
347     std::string tmp;
348     while (std::getline(cfgFile, tmp)) {
349         Utility::RemoveSpace(tmp);
350         size_t pos = tmp.find('#');
351         if ((pos != tmp.npos) && (pos != COMMENT_SUBSCRIPT)) {
352             FI_HILOGE("File format is error");
353             cfgFile.close();
354             return RET_ERR;
355         }
356         if (tmp.empty() || (tmp.front() == '#')) {
357             continue;
358         }
359         pos = tmp.find('=');
360         if ((pos == (tmp.size() - 1)) || (pos == tmp.npos)) {
361             FI_HILOGE("Find config item error");
362             cfgFile.close();
363             return RET_ERR;
364         }
365         std::string configItem = tmp.substr(0, pos);
366         std::string value = tmp.substr(pos + 1);
367         if (ConfigItemSwitch(configItem, value) == RET_ERR) {
368             FI_HILOGE("Configuration item error");
369             cfgFile.close();
370             return RET_ERR;
371         }
372     }
373     cfgFile.close();
374     return RET_OK;
375 }
376 
ConfigItemSwitch(const std::string & configItem,const std::string & value)377 int32_t Device::ConfigItemSwitch(const std::string &configItem, const std::string &value)
378 {
379     CALL_DEBUG_ENTER;
380     const std::string CONFIG_ITEM_KEYBOARD_TYPE { "Key.keyboard.type" };
381     if (configItem.empty() || value.empty() || !Utility::IsInteger(value)) {
382         FI_HILOGE("Invalid configuration encountered");
383         return RET_ERR;
384     }
385     if (configItem == CONFIG_ITEM_KEYBOARD_TYPE) {
386         keyboardType_ = static_cast<IDevice::KeyboardType>(stoi(value));
387     }
388     return RET_OK;
389 }
390 
ReadTomlFile(const std::string & filePath)391 int32_t Device::ReadTomlFile(const std::string &filePath)
392 {
393     CALL_DEBUG_ENTER;
394     char temp[PATH_MAX] {};
395     if (realpath(filePath.c_str(), temp) == nullptr) {
396         FI_HILOGE("Not real path (\'%{public}s\'):%{public}s", filePath.c_str(), strerror(errno));
397         return RET_ERR;
398     }
399     FI_HILOGD("Config file path:%{public}s", temp);
400 
401     if (!Utility::DoesFileExist(temp)) {
402         FI_HILOGE("File does not exist:%{public}s", temp);
403         return RET_ERR;
404     }
405     if (Utility::GetFileSize(temp) > MAX_FILE_SIZE_ALLOWED) {
406         FI_HILOGE("File size is out of range");
407         return RET_ERR;
408     }
409     if (ReadConfigFile(std::string(temp)) != RET_OK) {
410         FI_HILOGE("ReadConfigFile failed");
411         return RET_ERR;
412     }
413     return RET_OK;
414 }
415 
JudgeKeyboardType()416 void Device::JudgeKeyboardType()
417 {
418     CALL_DEBUG_ENTER;
419     if (TestBit(KEY_Q, keyBitmask_)) {
420         keyboardType_ = IDevice::KEYBOARD_TYPE_ALPHABETICKEYBOARD;
421         FI_HILOGD("The keyboard type is standard");
422     } else if (TestBit(KEY_HOME, keyBitmask_) && (GetBus() == BUS_BLUETOOTH)) {
423         keyboardType_ = IDevice::KEYBOARD_TYPE_REMOTECONTROL;
424         FI_HILOGD("The keyboard type is remote control");
425     } else if (TestBit(KEY_KP1, keyBitmask_)) {
426         keyboardType_ = IDevice::KEYBOARD_TYPE_DIGITALKEYBOARD;
427         FI_HILOGD("The keyboard type is digital keyboard");
428     } else if (TestBit(KEY_LEFTCTRL, keyBitmask_) &&
429                TestBit(KEY_RIGHTCTRL, keyBitmask_) &&
430                TestBit(KEY_F20, keyBitmask_)) {
431         keyboardType_ = IDevice::KEYBOARD_TYPE_HANDWRITINGPEN;
432         FI_HILOGD("The keyboard type is handwriting pen");
433     } else {
434         keyboardType_ = IDevice::KEYBOARD_TYPE_UNKNOWN;
435         FI_HILOGD("Undefined keyboard type");
436     }
437 }
438 
LoadDeviceConfig()439 void Device::LoadDeviceConfig()
440 {
441     CALL_DEBUG_ENTER;
442     if (ReadTomlFile(MakeConfigFileName()) != RET_OK) {
443         FI_HILOGE("ReadTomlFile failed");
444         keyboardType_ = IDevice::KEYBOARD_TYPE_NONE;
445     }
446     if (IsKeyboard()) {
447         if ((keyboardType_ <= IDevice::KEYBOARD_TYPE_NONE) ||
448             (keyboardType_ >= IDevice::KEYBOARD_TYPE_MAX)) {
449             JudgeKeyboardType();
450         }
451     } else {
452         keyboardType_ = IDevice::KEYBOARD_TYPE_NONE;
453     }
454     FI_HILOGD("keyboard type:%{public}d", keyboardType_);
455 }
456 } // namespace DeviceStatus
457 } // namespace Msdp
458 } // namespace OHOS
459