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 "dinput_utils_tool.h"
17
18 #include <algorithm>
19 #include <climits>
20 #include <cstdarg>
21 #include <cstdio>
22 #include <random>
23
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <openssl/sha.h>
31
32 #include "nlohmann/json.hpp"
33 #include "securec.h"
34
35 #include "softbus_bus_center.h"
36
37 #include "constants_dinput.h"
38 #include "dinput_errcode.h"
39 #include "dinput_softbus_define.h"
40
41 namespace OHOS {
42 namespace DistributedHardware {
43 namespace DistributedInput {
44 namespace {
45 constexpr int32_t HEX_TO_UINT8 = 2;
46 constexpr size_t INT32_SHORT_ID_LENGTH = 20;
47 constexpr size_t INT32_PLAINTEXT_LENGTH = 4;
48 constexpr size_t INT32_MIN_ID_LENGTH = 3;
49 constexpr int32_t WIDTH = 4;
50 constexpr unsigned char MASK = 0x0F;
51 constexpr int32_t DOUBLE_TIMES = 2;
52 constexpr int32_t INT32_STRING_LENGTH = 40;
53 constexpr uint32_t ERROR_MSG_MAX_LEN = 256;
54 constexpr int32_t MAX_RETRY_COUNT = 3;
55 constexpr uint32_t SLEEP_TIME_US = 10 * 1000;
56 constexpr char DHID_SPLIT = '.';
57 }
GetLocalDeviceInfo()58 DevInfo GetLocalDeviceInfo()
59 {
60 DevInfo devInfo{"", "", 0};
61 auto info = std::make_unique<NodeBasicInfo>();
62 auto ret = GetLocalNodeDeviceInfo(DINPUT_PKG_NAME.c_str(), info.get());
63 if (ret != 0) {
64 DHLOGE("GetLocalNodeDeviceInfo failed, errCode = %d", ret);
65 return devInfo;
66 }
67
68 devInfo.networkId = info->networkId;
69 devInfo.deviceName = info->deviceName;
70 devInfo.deviceType = info->deviceTypeId;
71
72 return devInfo;
73 }
74
GetLocalNetworkId()75 std::string GetLocalNetworkId()
76 {
77 std::string localNetworkId = GetLocalDeviceInfo().networkId;
78 if (localNetworkId.empty()) {
79 DHLOGE("local networkId is empty!");
80 }
81 DHLOGI("GetLocalNetworkId, device local networkId is %s", GetAnonyString(localNetworkId).c_str());
82 return localNetworkId;
83 }
84
GetUUIDBySoftBus(const std::string & networkId)85 std::string GetUUIDBySoftBus(const std::string &networkId)
86 {
87 if (networkId.empty()) {
88 return "";
89 }
90 char uuid[UUID_BUF_LEN] = {0};
91 auto ret = GetNodeKeyInfo(DINPUT_PKG_NAME.c_str(), networkId.c_str(), NodeDeviceInfoKey::NODE_KEY_UUID,
92 reinterpret_cast<uint8_t *>(uuid), UUID_BUF_LEN);
93 return (ret == DH_SUCCESS) ? std::string(uuid) : "";
94 }
95
GetCurrentTimeUs()96 uint64_t GetCurrentTimeUs()
97 {
98 constexpr int32_t usOneSecond = 1000 * 1000;
99 struct timeval tv;
100 gettimeofday(&tv, nullptr);
101 return tv.tv_sec * usOneSecond + tv.tv_usec;
102 }
103
SetAnonyId(const std::string & message)104 std::string SetAnonyId(const std::string &message)
105 {
106 nlohmann::json jsonObj = nlohmann::json::parse(message, nullptr, false);
107 if (jsonObj.is_discarded()) {
108 DHLOGE("jsonObj parse failed!");
109 return "";
110 }
111 if (IsString(jsonObj, DINPUT_SOFTBUS_KEY_DEVICE_ID)) {
112 jsonObj[DINPUT_SOFTBUS_KEY_DEVICE_ID] = GetAnonyString(jsonObj[DINPUT_SOFTBUS_KEY_DEVICE_ID]);
113 }
114 if (IsString(jsonObj, DESCRIPTOR)) {
115 jsonObj[DESCRIPTOR] = GetAnonyString(jsonObj[DESCRIPTOR]);
116 }
117 if (IsString(jsonObj, DINPUT_SOFTBUS_KEY_INPUT_DATA)) {
118 jsonObj[DINPUT_SOFTBUS_KEY_INPUT_DATA] = GetAnonyString(jsonObj[DINPUT_SOFTBUS_KEY_INPUT_DATA]);
119 }
120 if (IsString(jsonObj, DINPUT_SOFTBUS_KEY_VECTOR_DHID)) {
121 std::string dhidStr = jsonObj[DINPUT_SOFTBUS_KEY_VECTOR_DHID];
122 dhidStr.append(".");
123 size_t pos = dhidStr.find(".");
124 std::string anonyDhidStr = "";
125 while (pos != dhidStr.npos) {
126 anonyDhidStr += GetAnonyString(dhidStr.substr(0, pos)) + ".";
127 dhidStr = dhidStr.substr(pos + 1, dhidStr.size());
128 pos = dhidStr.find(".");
129 }
130 jsonObj[DINPUT_SOFTBUS_KEY_VECTOR_DHID] = anonyDhidStr.substr(0, anonyDhidStr.length() - 1);
131 }
132 if (IsString(jsonObj, DINPUT_SOFTBUS_KEY_SRC_DEV_ID)) {
133 jsonObj[DINPUT_SOFTBUS_KEY_SRC_DEV_ID] = GetAnonyString(jsonObj[DINPUT_SOFTBUS_KEY_SRC_DEV_ID]);
134 }
135 if (IsString(jsonObj, DINPUT_SOFTBUS_KEY_SINK_DEV_ID)) {
136 jsonObj[DINPUT_SOFTBUS_KEY_SINK_DEV_ID] = GetAnonyString(jsonObj[DINPUT_SOFTBUS_KEY_SINK_DEV_ID]);
137 }
138 return jsonObj.dump();
139 }
140
IsBoolean(const nlohmann::json & jsonObj,const std::string & key)141 bool IsBoolean(const nlohmann::json &jsonObj, const std::string &key)
142 {
143 return jsonObj.contains(key) && jsonObj[key].is_boolean();
144 }
145
IsString(const nlohmann::json & jsonObj,const std::string & key)146 bool IsString(const nlohmann::json &jsonObj, const std::string &key)
147 {
148 return jsonObj.contains(key) && jsonObj[key].is_string();
149 }
150
IsInt32(const nlohmann::json & jsonObj,const std::string & key)151 bool IsInt32(const nlohmann::json &jsonObj, const std::string &key)
152 {
153 return jsonObj.contains(key) && jsonObj[key].is_number_integer() && INT32_MIN <= jsonObj[key] &&
154 jsonObj[key] <= INT32_MAX;
155 }
156
IsInt64(const nlohmann::json & jsonObj,const std::string & key)157 bool IsInt64(const nlohmann::json &jsonObj, const std::string &key)
158 {
159 return jsonObj.contains(key) && jsonObj[key].is_number_integer() && INT64_MIN <= jsonObj[key] &&
160 jsonObj[key] <= INT64_MAX;
161 }
162
IsUInt16(const nlohmann::json & jsonObj,const std::string & key)163 bool IsUInt16(const nlohmann::json &jsonObj, const std::string &key)
164 {
165 return jsonObj.contains(key) && jsonObj[key].is_number_unsigned() && jsonObj[key] <= UINT16_MAX;
166 }
167
IsUInt32(const nlohmann::json & jsonObj,const std::string & key)168 bool IsUInt32(const nlohmann::json &jsonObj, const std::string &key)
169 {
170 return jsonObj.contains(key) && jsonObj[key].is_number_unsigned() && jsonObj[key] <= UINT32_MAX;
171 }
172
IsUInt64(const nlohmann::json & jsonObj,const std::string & key)173 bool IsUInt64(const nlohmann::json &jsonObj, const std::string &key)
174 {
175 return jsonObj.contains(key) && jsonObj[key].is_number_unsigned() && jsonObj[key] <= UINT64_MAX;
176 }
177
IsArray(const nlohmann::json & jsonObj,const std::string & key)178 bool IsArray(const nlohmann::json &jsonObj, const std::string &key)
179 {
180 return jsonObj.contains(key) && jsonObj[key].is_array();
181 }
182
GetNodeDesc(std::string parameters)183 std::string GetNodeDesc(std::string parameters)
184 {
185 nlohmann::json parObj = nlohmann::json::parse(parameters, nullptr, false);
186 if (parObj.is_discarded()) {
187 DHLOGE("parObj parse failed!");
188 return "";
189 }
190 std::string nodeName = "N/A";
191 std::string physicalPath = "N/A";
192 int32_t classes = -1;
193
194 if (IsString(parObj, DEVICE_NAME) && IsString(parObj, PHYSICAL_PATH) && IsInt32(parObj, CLASSES)) {
195 nodeName = parObj.at(DEVICE_NAME).get<std::string>();
196 physicalPath = parObj.at(PHYSICAL_PATH).get<std::string>();
197 classes = parObj.at(CLASSES).get<int32_t>();
198 }
199
200 return "{ nodeName: " + nodeName + ", physicalPath: " + physicalPath + ", classes: " +
201 std::to_string(classes) + " }";
202 }
203
GetAnonyString(const std::string & value)204 std::string GetAnonyString(const std::string &value)
205 {
206 std::string res;
207 std::string tmpStr("******");
208 size_t strLen = value.length();
209 if (strLen < INT32_MIN_ID_LENGTH) {
210 return tmpStr;
211 }
212
213 if (strLen <= INT32_SHORT_ID_LENGTH) {
214 res += value[0];
215 res += tmpStr;
216 res += value[strLen - 1];
217 } else {
218 res.append(value, 0, INT32_PLAINTEXT_LENGTH);
219 res += tmpStr;
220 res.append(value, strLen - INT32_PLAINTEXT_LENGTH, INT32_PLAINTEXT_LENGTH);
221 }
222
223 return res;
224 }
225
GetAnonyInt32(const int32_t value)226 std::string GetAnonyInt32(const int32_t value)
227 {
228 char tempBuffer[INT32_STRING_LENGTH] = "";
229 int32_t secRet = sprintf_s(tempBuffer, INT32_STRING_LENGTH, "%d", value);
230 if (secRet <= 0) {
231 std::string nullString("");
232 return nullString;
233 }
234 size_t length = strlen(tempBuffer);
235 for (size_t i = 1; i <= length - 1; i++) {
236 tempBuffer[i] = '*';
237 }
238 if (length == 0x01) {
239 tempBuffer[0] = '*';
240 }
241
242 std::string tempString(tempBuffer);
243 return tempString;
244 }
245
Sha256(const std::string & in)246 std::string Sha256(const std::string &in)
247 {
248 unsigned char out[SHA256_DIGEST_LENGTH * HEX_TO_UINT8 + 1] = {0};
249 SHA256_CTX ctx;
250 SHA256_Init(&ctx);
251 SHA256_Update(&ctx, in.data(), in.size());
252 SHA256_Final(&out[SHA256_DIGEST_LENGTH], &ctx);
253 // here we translate sha256 hash to hexadecimal. each 8-bit char will be presented by two characters([0-9a-f])
254 const char* hexCode = "0123456789abcdef";
255 for (int32_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
256 unsigned char value = out[SHA256_DIGEST_LENGTH + i];
257 // uint8_t is 2 digits in hexadecimal.
258 out[i * DOUBLE_TIMES] = hexCode[(value >> WIDTH) & MASK];
259 out[i * DOUBLE_TIMES + 1] = hexCode[value & MASK];
260 }
261 out[SHA256_DIGEST_LENGTH * DOUBLE_TIMES] = 0;
262 return reinterpret_cast<char*>(out);
263 }
264
CloseFd(int fd)265 void CloseFd(int fd)
266 {
267 if (fd < 0) {
268 DHLOGE("No fd need to beclosed.");
269 return;
270 }
271 close(fd);
272 fd = UN_INIT_FD_VALUE;
273 }
274
BitIsSet(const unsigned long * array,int bit)275 int BitIsSet(const unsigned long *array, int bit)
276 {
277 return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
278 }
279
SplitStringToVector(const std::string & str,const char split,std::vector<std::string> & vecStr)280 void SplitStringToVector(const std::string &str, const char split, std::vector<std::string> &vecStr)
281 {
282 if (str.empty()) {
283 DHLOGE("SplitStringToVector param str is error.");
284 return;
285 }
286 std::string strTmp = str + split;
287 size_t pos = strTmp.find(split);
288 while (pos != strTmp.npos) {
289 std::string matchTmp = strTmp.substr(0, pos);
290 vecStr.push_back(matchTmp);
291 strTmp = strTmp.substr(pos + 1, strTmp.size());
292 pos = strTmp.find(split);
293 }
294 }
295
OpenInputDeviceFdByPath(const std::string & devicePath)296 int OpenInputDeviceFdByPath(const std::string &devicePath)
297 {
298 chmod(devicePath.c_str(), S_IWRITE | S_IREAD);
299 char canonicalDevicePath[PATH_MAX] = {0x00};
300 if (devicePath.length() == 0 || devicePath.length() >= PATH_MAX ||
301 realpath(devicePath.c_str(), canonicalDevicePath) == nullptr) {
302 DHLOGE("path check fail, error path: %s", devicePath.c_str());
303 return -1;
304 }
305 struct stat s;
306 if ((stat(canonicalDevicePath, &s) == 0) && (s.st_mode & S_IFDIR)) {
307 DHLOGI("path: %s is a dir.", devicePath.c_str());
308 return -1;
309 }
310 int fd = open(canonicalDevicePath, O_RDWR | O_CLOEXEC);
311 int32_t count = 0;
312 while ((fd < 0) && (count < MAX_RETRY_COUNT)) {
313 ++count;
314 usleep(SLEEP_TIME_US);
315 fd = open(canonicalDevicePath, O_RDWR | O_CLOEXEC);
316 DHLOGE("could not open the path: %s, errno: %s; retry: %d", devicePath.c_str(), ConvertErrNo().c_str(), count);
317 }
318 if (count >= MAX_RETRY_COUNT) {
319 DHLOGE("could not open the path: %s, errno: %s.", devicePath.c_str(), ConvertErrNo().c_str());
320 CloseFd(fd);
321 return -1;
322 }
323 return fd;
324 }
325
ConvertErrNo()326 std::string ConvertErrNo()
327 {
328 char errMsg[ERROR_MSG_MAX_LEN] = {0};
329 strerror_r(errno, errMsg, ERROR_MSG_MAX_LEN);
330 std::string errNoMsg(errMsg);
331 return errNoMsg;
332 }
333
ScanInputDevicesPath(const std::string & dirName,std::vector<std::string> & vecInputDevPath)334 void ScanInputDevicesPath(const std::string &dirName, std::vector<std::string> &vecInputDevPath)
335 {
336 DIR *dir;
337 struct dirent *de;
338 dir = opendir(dirName.c_str());
339 if (dir == nullptr) {
340 DHLOGE("error opendir /dev/input :%{public}s\n", ConvertErrNo().c_str());
341 return;
342 }
343 size_t dirNameFirstPos = 0;
344 size_t dirNameSecondPos = 1;
345 size_t dirNameThirdPos = 2;
346 while ((de = readdir(dir))) {
347 if (de->d_name[dirNameFirstPos] == '.' && (de->d_name[dirNameSecondPos] == '\0' ||
348 (de->d_name[dirNameSecondPos] == '.' && de->d_name[dirNameThirdPos] == '\0'))) {
349 continue;
350 }
351 std::string tmpDevName = dirName + "/" + std::string(de->d_name);
352 vecInputDevPath.push_back(tmpDevName);
353 }
354 closedir(dir);
355 }
356
RecordEventLog(const input_event & event)357 void RecordEventLog(const input_event &event)
358 {
359 std::string eventType = "";
360 switch (event.type) {
361 case EV_KEY:
362 eventType = "EV_KEY";
363 break;
364 case EV_SYN:
365 eventType = "EV_SYN";
366 break;
367 default:
368 eventType = "other type " + std::to_string(event.type);
369 break;
370 }
371 DHLOGD("5.E2E-Test Source write event into input driver, EventType: %s, Code: %d, Value: %d",
372 eventType.c_str(), event.code, event.value);
373 }
374
WriteEventToDevice(const int fd,const input_event & event)375 void WriteEventToDevice(const int fd, const input_event &event)
376 {
377 if (write(fd, &event, sizeof(event)) < static_cast<ssize_t>(sizeof(event))) {
378 DHLOGE("could not inject event, fd: %d", fd);
379 return;
380 }
381 RecordEventLog(event);
382 }
383
ResetVirtualDevicePressedKeys(const std::vector<std::string> & nodePaths)384 void ResetVirtualDevicePressedKeys(const std::vector<std::string> &nodePaths)
385 {
386 unsigned long keyState[NLONGS(KEY_CNT)] = { 0 };
387 for (const auto &path : nodePaths) {
388 DHLOGI("Check and reset key state, path: %s", path.c_str());
389 std::vector<uint32_t> pressedKeys;
390 int fd = OpenInputDeviceFdByPath(path);
391 if (fd == -1) {
392 DHLOGE("Open virtual keyboard node failed, path: %s", path.c_str());
393 continue;
394 }
395
396 int rc = ioctl(fd, EVIOCGKEY(sizeof(keyState)), keyState);
397 if (rc < 0) {
398 DHLOGE("Read all key state failed, rc: %d, path: %s", rc, path.c_str());
399 continue;
400 }
401
402 for (int32_t keyIndex = 0; keyIndex < KEY_MAX; keyIndex++) {
403 if (BitIsSet(keyState, keyIndex)) {
404 DHLOGI("key index: %d pressed.", keyIndex);
405 pressedKeys.push_back(keyIndex);
406 }
407 }
408
409 if (pressedKeys.empty()) {
410 continue;
411 }
412
413 struct input_event event = {
414 .type = EV_KEY,
415 .code = 0,
416 .value = KEY_UP_STATE
417 };
418 for (auto &code : pressedKeys) {
419 event.type = EV_KEY;
420 event.code = code;
421 WriteEventToDevice(fd, event);
422 event.type = EV_SYN;
423 event.code = 0;
424 WriteEventToDevice(fd, event);
425 }
426 }
427 }
428
GetString(const std::vector<std::string> & vec)429 std::string GetString(const std::vector<std::string> &vec)
430 {
431 std::string retStr = "[";
432 for (uint32_t i = 0; i < vec.size(); i++) {
433 if (i != (vec.size() - 1)) {
434 retStr += vec[i] + ", ";
435 } else {
436 retStr += vec[i];
437 }
438 }
439 retStr += "]";
440 return retStr;
441 }
442
GetRandomInt32()443 int32_t GetRandomInt32()
444 {
445 std::default_random_engine engine(time(nullptr));
446
447 std::uniform_int_distribution<int> distribution(0, INT32_MAX);
448 return distribution(engine);
449 }
450
JointDhIds(const std::vector<std::string> & dhids)451 std::string JointDhIds(const std::vector<std::string> &dhids)
452 {
453 if (dhids.size() <= 0) {
454 return "";
455 }
456 auto dotFold = [](std::string a, std::string b) {return std::move(a) + DHID_SPLIT + std::move(b);};
457 return std::accumulate(std::next(dhids.begin()), dhids.end(), dhids[0], dotFold);
458 }
459
SplitDhIdString(const std::string & dhIdsString)460 std::vector<std::string> SplitDhIdString(const std::string &dhIdsString)
461 {
462 std::vector<std::string> dhIdsVec;
463 SplitStringToVector(dhIdsString, DHID_SPLIT, dhIdsVec);
464 return dhIdsVec;
465 }
466 } // namespace DistributedInput
467 } // namespace DistributedHardware
468 } // namespace OHOS