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