1 /*
2 * Copyright (c) 2021-2022 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 "util.h"
17
18 #include <array>
19 #include <chrono>
20 #include <cinttypes>
21 #include <cstdarg>
22 #include <fstream>
23
24 #include <sys/prctl.h>
25 #include <sys/stat.h>
26 #include <sys/syscall.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 #include "config_multimodal.h"
32 #include "define_multimodal.h"
33 #include "error_multimodal.h"
34 #include "mmi_log.h"
35 #include "securec.h"
36
37 namespace OHOS {
38 namespace MMI {
39 namespace {
40 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "Util" };
41 constexpr int32_t FILE_SIZE_MAX = 0x6C445;
42 constexpr int32_t MAX_PRO_FILE_SIZE = 128000;
43 constexpr int32_t INVALID_FILE_SIZE = -1;
44 constexpr int32_t MIN_INTERVALTIME = 36;
45 constexpr int32_t MAX_INTERVALTIME = 100;
46 constexpr int32_t MIN_DELAYTIME = 300;
47 constexpr int32_t MAX_DELAYTIME = 1000;
48 constexpr int32_t COMMENT_SUBSCRIPT = 0;
49 const std::string CONFIG_ITEM_REPEAT = "Key.autorepeat";
50 const std::string CONFIG_ITEM_DELAY = "Key.autorepeat.delaytime";
51 const std::string CONFIG_ITEM_INTERVAL = "Key.autorepeat.intervaltime";
52 const std::string CONFIG_ITEM_TYPE = "Key.keyboard.type";
53 const std::string CURSORSTYLE_PATH = "/system/etc/multimodalinput/mouse_icon/";
54 const std::string DATA_PATH = "/data";
55 const std::string INPUT_PATH = "/system/";
56 const std::string KEY_PATH = "/vendor/etc/keymap/";
57 constexpr size_t BUF_TID_SIZE = 10;
58 constexpr size_t BUF_CMD_SIZE = 512;
59 constexpr size_t PROGRAM_NAME_SIZE = 256;
60 } // namespace
61
GetSysClockTime()62 int64_t GetSysClockTime()
63 {
64 struct timespec ts = { 0, 0 };
65 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
66 MMI_HILOGD("clock_gettime failed:%{public}d", errno);
67 return 0;
68 }
69 return (ts.tv_sec * 1000 * 1000) + (ts.tv_nsec / 1000);
70 }
71
GetMillisTime()72 int64_t GetMillisTime()
73 {
74 auto timeNow = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now());
75 auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(timeNow.time_since_epoch());
76 return tmp.count();
77 }
78
GetThisThreadIdOfString()79 static std::string GetThisThreadIdOfString()
80 {
81 thread_local std::string threadLocalId;
82 if (threadLocalId.empty()) {
83 long tid = syscall(SYS_gettid);
84 char buf[BUF_TID_SIZE] = {};
85 const int32_t ret = sprintf_s(buf, BUF_TID_SIZE, "%06d", tid);
86 if (ret < 0) {
87 printf("ERR: in %s, #%d, call sprintf_s failed, ret = %d.", __func__, __LINE__, ret);
88 return threadLocalId;
89 }
90 buf[BUF_TID_SIZE - 1] = '\0';
91 threadLocalId = buf;
92 }
93
94 return threadLocalId;
95 }
96
GetThisThreadId()97 uint64_t GetThisThreadId()
98 {
99 std::string stid = GetThisThreadIdOfString();
100 auto tid = std::stoull(stid);
101 return tid;
102 }
103
StringToken(std::string & str,const std::string & sep,std::string & token)104 static size_t StringToken(std::string &str, const std::string &sep, std::string &token)
105 {
106 token = "";
107 if (str.empty()) {
108 return str.npos;
109 }
110 size_t pos = str.npos;
111 size_t tmp = 0;
112 for (auto &item : sep) {
113 tmp = str.find(item);
114 if (str.npos != tmp) {
115 pos = (std::min)(pos, tmp);
116 }
117 }
118 if (str.npos != pos) {
119 token = str.substr(0, pos);
120 if (str.npos != pos + 1) {
121 str = str.substr(pos + 1, str.npos);
122 }
123 if (pos == 0) {
124 return StringToken(str, sep, token);
125 }
126 } else {
127 token = str;
128 str = "";
129 }
130 return token.size();
131 }
132
StringSplit(const std::string & str,const std::string & sep,std::vector<std::string> & vecList)133 size_t StringSplit(const std::string &str, const std::string &sep, std::vector<std::string> &vecList)
134 {
135 size_t size;
136 auto strs = str;
137 std::string token;
138 while (str.npos != (size = StringToken(strs, sep, token))) {
139 vecList.push_back(token);
140 }
141 return vecList.size();
142 }
143
IdsListToString(const std::vector<int32_t> & list,const std::string & sep)144 std::string IdsListToString(const std::vector<int32_t> &list, const std::string &sep)
145 {
146 std::string str;
147 for (const auto &it : list) {
148 str += std::to_string(it) + sep;
149 }
150 if (str.size() > 0) {
151 str.resize(str.size() - sep.size());
152 }
153 return str;
154 }
155
GetPid()156 int32_t GetPid()
157 {
158 return static_cast<int32_t>(getpid());
159 }
160
GetFileName(const std::string & strPath)161 static std::string GetFileName(const std::string &strPath)
162 {
163 size_t nPos = strPath.find_last_of('/');
164 if (strPath.npos == nPos) {
165 nPos = strPath.find_last_of('\\');
166 }
167 if (strPath.npos == nPos) {
168 return strPath;
169 }
170
171 return strPath.substr(nPos + 1, strPath.npos);
172 }
173
GetProgramName()174 const char *GetProgramName()
175 {
176 static char programName[PROGRAM_NAME_SIZE] = {};
177 if (programName[0] != '\0') {
178 return programName;
179 }
180
181 char buf[BUF_CMD_SIZE] = { 0 };
182 if (sprintf_s(buf, BUF_CMD_SIZE, "/proc/%d/cmdline", static_cast<int32_t>(getpid())) == -1) {
183 KMSG_LOGE("GetProcessInfo sprintf_s /proc/.../cmdline error");
184 return "";
185 }
186 FILE *fp = fopen(buf, "rb");
187 if (fp == nullptr) {
188 KMSG_LOGE("The fp is nullptr, filename = %s.", buf);
189 return "";
190 }
191 static constexpr size_t bufLineSize = 512;
192 char bufLine[bufLineSize] = { 0 };
193 if ((fgets(bufLine, bufLineSize, fp) == nullptr)) {
194 KMSG_LOGE("fgets failed.");
195 if (fclose(fp) != 0) {
196 KMSG_LOGW("Close file:%s failed", buf);
197 }
198 fp = nullptr;
199 return "";
200 }
201 if (fclose(fp) != 0) {
202 KMSG_LOGW("Close file:%s failed", buf);
203 }
204 fp = nullptr;
205
206 std::string tempName(bufLine);
207 tempName = GetFileName(tempName);
208 if (tempName.empty()) {
209 KMSG_LOGE("tempName is empty.");
210 return "";
211 }
212 const size_t copySize = std::min(tempName.size(), PROGRAM_NAME_SIZE - 1);
213 if (copySize == 0) {
214 KMSG_LOGE("The copySize is 0.");
215 return "";
216 }
217 errno_t ret = memcpy_s(programName, PROGRAM_NAME_SIZE, tempName.c_str(), copySize);
218 if (ret != EOK) {
219 return "";
220 }
221 KMSG_LOGI("GetProgramName success. programName = %s", programName);
222
223 return programName;
224 }
225
SetThreadName(const std::string & name)226 void SetThreadName(const std::string &name)
227 {
228 prctl(PR_SET_NAME, name.c_str());
229 }
230
IsFileExists(const std::string & fileName)231 static bool IsFileExists(const std::string &fileName)
232 {
233 return (access(fileName.c_str(), F_OK) == 0);
234 }
235
CheckFileExtendName(const std::string & filePath,const std::string & checkExtension)236 static bool CheckFileExtendName(const std::string &filePath, const std::string &checkExtension)
237 {
238 std::string::size_type pos = filePath.find_last_of('.');
239 if (pos == std::string::npos) {
240 MMI_HILOGE("File is not find extension");
241 return false;
242 }
243 return (filePath.substr(pos + 1, filePath.npos) == checkExtension);
244 }
245
GetFileSize(const std::string & filePath)246 static int32_t GetFileSize(const std::string &filePath)
247 {
248 struct stat statbuf = { 0 };
249 if (stat(filePath.c_str(), &statbuf) != 0) {
250 MMI_HILOGE("Get file size error");
251 return INVALID_FILE_SIZE;
252 }
253 return statbuf.st_size;
254 }
255
ReadFile(const std::string & filePath)256 static std::string ReadFile(const std::string &filePath)
257 {
258 FILE *fp = fopen(filePath.c_str(), "r");
259 CHKPS(fp);
260 std::string dataStr;
261 char buf[256] = {};
262 while (fgets(buf, sizeof(buf), fp) != nullptr) {
263 dataStr += buf;
264 }
265 if (fclose(fp) != 0) {
266 MMI_HILOGW("Close file failed");
267 }
268 return dataStr;
269 }
270
IsValidPath(const std::string & rootDir,const std::string & filePath)271 static bool IsValidPath(const std::string &rootDir, const std::string &filePath)
272 {
273 return (filePath.compare(0, rootDir.size(), rootDir) == 0);
274 }
275
IsValidJsonPath(const std::string & filePath)276 bool IsValidJsonPath(const std::string &filePath)
277 {
278 return IsValidPath(DATA_PATH, filePath) || IsValidPath(INPUT_PATH, filePath);
279 }
280
IsValidProPath(const std::string & filePath)281 static bool IsValidProPath(const std::string &filePath)
282 {
283 return IsValidPath(KEY_PATH, filePath);
284 }
285
IsValidTomlPath(const std::string & filePath)286 static bool IsValidTomlPath(const std::string &filePath)
287 {
288 return IsValidPath(KEY_PATH, filePath);
289 }
290
ReadProFile(const std::string & filePath,int32_t deviceId,std::map<int32_t,std::map<int32_t,int32_t>> & configMap)291 void ReadProFile(const std::string &filePath, int32_t deviceId,
292 std::map<int32_t, std::map<int32_t, int32_t>> &configMap)
293 {
294 CALL_DEBUG_ENTER;
295 if (filePath.empty()) {
296 MMI_HILOGE("FilePath is empty");
297 return;
298 }
299 char realPath[PATH_MAX] = {};
300 if (realpath(filePath.c_str(), realPath) == nullptr) {
301 MMI_HILOGI("The realpath return nullptr");
302 return;
303 }
304 if (!IsValidProPath(realPath)) {
305 MMI_HILOGE("File path is error");
306 return;
307 }
308 if (!IsFileExists(realPath)) {
309 MMI_HILOGE("File is not existent");
310 return;
311 }
312 if (!CheckFileExtendName(realPath, "pro")) {
313 MMI_HILOGE("Unable to parse files other than json format");
314 return;
315 }
316 auto fileSize = GetFileSize(realPath);
317 if ((fileSize == INVALID_FILE_SIZE) || (fileSize >= MAX_PRO_FILE_SIZE)) {
318 MMI_HILOGE("The configuration file size is incorrect");
319 return;
320 }
321 ReadProConfigFile(realPath, deviceId, configMap);
322 }
323
IsNum(const std::string & str)324 static inline bool IsNum(const std::string &str)
325 {
326 std::istringstream sin(str);
327 double num;
328 return (sin >> num) && sin.eof();
329 }
330
ReadProConfigFile(const std::string & realPath,int32_t deviceId,std::map<int32_t,std::map<int32_t,int32_t>> & configKey)331 void ReadProConfigFile(const std::string &realPath, int32_t deviceId,
332 std::map<int32_t, std::map<int32_t, int32_t>> &configKey)
333 {
334 CALL_DEBUG_ENTER;
335 std::ifstream reader(realPath);
336 if (!reader.is_open()) {
337 MMI_HILOGE("Failed to open config file");
338 return;
339 }
340 std::string strLine;
341 int32_t sysKeyValue;
342 int32_t nativeKeyValue;
343 int32_t elementKey = 0;
344 int32_t elementValue = 0;
345 std::map<int32_t, int32_t> tmpConfigKey;
346 while (std::getline(reader, strLine)) {
347 const char* line = strLine.c_str();
348 int32_t len = strlen(line);
349 char* realLine = static_cast<char*>(malloc(len + 1));
350 if (realLine == nullptr) {
351 MMI_HILOGE("Malloc failed");
352 return;
353 }
354 if (strcpy_s(realLine, len + 1, line) != EOK) {
355 MMI_HILOGE("strcpy_s error");
356 free(realLine);
357 realLine = nullptr;
358 return;
359 }
360 *(realLine + len + 1) = '\0';
361 int32_t ret = ReadConfigInfo(realLine, len, &elementKey, &elementValue);
362 free(realLine);
363 realLine = nullptr;
364 if (ret != RET_OK) {
365 MMI_HILOGE("Failed to read from line of config info");
366 reader.close();
367 return;
368 }
369 nativeKeyValue = elementKey;
370 sysKeyValue = elementValue;
371 MMI_HILOGD("The nativeKeyValue is:%{public}d, sysKeyValue is:%{public}d", nativeKeyValue, sysKeyValue);
372 tmpConfigKey.insert(std::pair<int32_t, int32_t>(nativeKeyValue, sysKeyValue));
373 }
374 reader.close();
375 auto iter = configKey.insert(std::make_pair(deviceId, tmpConfigKey));
376 if (!iter.second) {
377 MMI_HILOGE("The file name is duplicated");
378 return;
379 }
380 }
381
ReadJsonFile(const std::string & filePath)382 std::string ReadJsonFile(const std::string &filePath)
383 {
384 if (filePath.empty()) {
385 MMI_HILOGE("FilePath is empty");
386 return "";
387 }
388 char realPath[PATH_MAX] = {};
389 if (realpath(filePath.c_str(), realPath) == nullptr) {
390 MMI_HILOGE("Path is error");
391 return "";
392 }
393 if (!IsValidJsonPath(realPath)) {
394 MMI_HILOGE("File path is error");
395 return "";
396 }
397 if (!CheckFileExtendName(realPath, "json")) {
398 MMI_HILOGE("Unable to parse files other than json format");
399 return "";
400 }
401 if (!IsFileExists(realPath)) {
402 MMI_HILOGE("File is not existent");
403 return "";
404 }
405 int32_t fileSize = GetFileSize(realPath);
406 if ((fileSize <= 0) || (fileSize > FILE_SIZE_MAX)) {
407 MMI_HILOGE("File size out of read range");
408 return "";
409 }
410 return ReadFile(filePath);
411 }
412
ConfigItemSwitch(const std::string & configItem,const std::string & value,DeviceConfig & devConf)413 static int32_t ConfigItemSwitch(const std::string &configItem, const std::string &value, DeviceConfig &devConf)
414 {
415 CALL_DEBUG_ENTER;
416 if (configItem.empty() || value.empty()) {
417 MMI_HILOGE("Get key config item is invalid");
418 return RET_ERR;
419 }
420 if (!IsNum(value)) {
421 MMI_HILOGE("Get key config item is invalid");
422 return RET_ERR;
423 }
424 if (configItem == CONFIG_ITEM_REPEAT) {
425 devConf.autoSwitch = stoi(value);
426 } else if (configItem == CONFIG_ITEM_DELAY) {
427 devConf.delayTime = stoi(value);
428 if (devConf.delayTime < MIN_DELAYTIME || devConf.delayTime > MAX_DELAYTIME) {
429 MMI_HILOGE("Unusual the delaytime");
430 return RET_ERR;
431 }
432 } else if (configItem == CONFIG_ITEM_INTERVAL) {
433 devConf.intervalTime = stoi(value);
434 if (devConf.intervalTime < MIN_INTERVALTIME || devConf.intervalTime > MAX_INTERVALTIME) {
435 MMI_HILOGE("Unusual the intervaltime");
436 return RET_ERR;
437 }
438 } else if (configItem == CONFIG_ITEM_TYPE) {
439 devConf.keyboardType = stoi(value);
440 }
441 return RET_OK;
442 }
443
ReadConfigFile(const std::string & realPath,DeviceConfig & devConf)444 static int32_t ReadConfigFile(const std::string &realPath, DeviceConfig &devConf)
445 {
446 CALL_DEBUG_ENTER;
447 std::ifstream cfgFile(realPath);
448 if (!cfgFile.is_open()) {
449 MMI_HILOGE("Failed to open config file");
450 return FILE_OPEN_FAIL;
451 }
452 std::string tmp;
453 while (std::getline(cfgFile, tmp)) {
454 RemoveSpace(tmp);
455 size_t pos = tmp.find('#');
456 if (pos != tmp.npos && pos != COMMENT_SUBSCRIPT) {
457 MMI_HILOGE("File format is error");
458 cfgFile.close();
459 return RET_ERR;
460 }
461 if (tmp.empty() || tmp.front() == '#') {
462 continue;
463 }
464 pos = tmp.find('=');
465 if (pos == (tmp.size() - 1) || pos == tmp.npos) {
466 MMI_HILOGE("Find config item error");
467 cfgFile.close();
468 return RET_ERR;
469 }
470 std::string configItem = tmp.substr(0, pos);
471 std::string value = tmp.substr(pos + 1);
472 if (ConfigItemSwitch(configItem, value, devConf) == RET_ERR) {
473 MMI_HILOGE("Configuration item error");
474 cfgFile.close();
475 return RET_ERR;
476 }
477 }
478 cfgFile.close();
479 return RET_OK;
480 }
481
ReadTomlFile(const std::string & filePath,DeviceConfig & devConf)482 int32_t ReadTomlFile(const std::string &filePath, DeviceConfig &devConf)
483 {
484 if (filePath.empty()) {
485 MMI_HILOGE("FilePath is empty");
486 return RET_ERR;
487 }
488 char realPath[PATH_MAX] = {};
489 if (realpath(filePath.c_str(), realPath) == nullptr) {
490 MMI_HILOGI("The realpath return nullptr");
491 return RET_ERR;
492 }
493 if (!IsValidTomlPath(realPath)) {
494 MMI_HILOGE("File path is error");
495 return RET_ERR;
496 }
497 if (!IsFileExists(realPath)) {
498 MMI_HILOGE("File is not existent");
499 return RET_ERR;
500 }
501 if (!CheckFileExtendName(realPath, "TOML")) {
502 MMI_HILOGE("Unable to parse files other than json format");
503 return RET_ERR;
504 }
505 int32_t fileSize = GetFileSize(realPath);
506 if ((fileSize <= 0) || (fileSize > FILE_SIZE_MAX)) {
507 MMI_HILOGE("File size out of read range");
508 return RET_ERR;
509 }
510 if (ReadConfigFile(realPath, devConf) == RET_ERR) {
511 MMI_HILOGE("Read device config file failed");
512 return RET_ERR;
513 }
514 return RET_OK;
515 }
516
ReadCursorStyleFile(const std::string & filePath)517 int32_t ReadCursorStyleFile(const std::string &filePath)
518 {
519 CALL_DEBUG_ENTER;
520 if (filePath.empty()) {
521 MMI_HILOGE("FilePath is empty");
522 return RET_ERR;
523 }
524 if (!IsFileExists(filePath)) {
525 MMI_HILOGE("File is not existent");
526 return RET_ERR;
527 }
528 char realPath[PATH_MAX] = {};
529 if (realpath(filePath.c_str(), realPath) == nullptr) {
530 MMI_HILOGE("Path is error");
531 return RET_ERR;
532 }
533 int32_t fileSize = GetFileSize(realPath);
534 if ((fileSize <= 0) || (fileSize > FILE_SIZE_MAX)) {
535 MMI_HILOGE("File size out of read range");
536 return RET_ERR;
537 }
538 return RET_OK;
539 }
540
StringPrintf(const char * format,...)541 std::string StringPrintf(const char *format, ...)
542 {
543 char space[1024];
544
545 va_list ap;
546 va_start(ap, format);
547 std::string result;
548 int32_t ret = vsnprintf_s(space, sizeof(space), sizeof(space) - 1, format, ap);
549 if (ret >= RET_OK && (size_t)ret < sizeof(space)) {
550 result = space;
551 } else {
552 MMI_HILOGE("The buffer is overflow");
553 }
554 va_end(ap);
555 return result;
556 }
557
FileVerification(std::string & filePath,const std::string & checkExtension)558 std::string FileVerification(std::string &filePath, const std::string &checkExtension)
559 {
560 if (filePath.empty()) {
561 MMI_HILOGE("FilePath is empty");
562 return "";
563 }
564 char realPath[PATH_MAX] = {};
565 if (realpath(filePath.c_str(), realPath) == nullptr) {
566 MMI_HILOGI("The realpath return nullptr");
567 return "";
568 }
569 if (!IsFileExists(realPath)) {
570 MMI_HILOGE("File is not existent");
571 return "";
572 }
573 if (!CheckFileExtendName(realPath, checkExtension)) {
574 MMI_HILOGE("Unable to parse files other than json format");
575 return "";
576 }
577 int32_t fileSize = GetFileSize(realPath);
578 if ((fileSize <= 0) || (fileSize > FILE_SIZE_MAX)) {
579 MMI_HILOGE("File size out of read range");
580 return "";
581 }
582 return realPath;
583 }
584 } // namespace MMI
585 } // namespace OHOS
586