• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 <errno.h>
17 #include <linux/netlink.h>
18 #include <poll.h>
19 #include <stdlib.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22 
23 #include "devmgr_service.h"
24 #include "hdf_dlist.h"
25 #include "hdf_core_log.h"
26 #include "osal_mem.h"
27 #include "osal_thread.h"
28 #include "osal_time.h"
29 #include "securec.h"
30 
31 #define HDF_LOG_TAG devmgr_uevent
32 
33 #define UEVENT_SOCKET_BUFF_SIZE (256 * 1024)
34 
35 #ifndef LINE_MAX
36 #define LINE_MAX 4096
37 #endif
38 
39 #define ACTION_STR          "ACTION=="
40 #define PNP_EVENT_STR       "HDF_PNP_EVENT="
41 #define KEY_VALUE_DELIMITER "==\""
42 #define KEY_DELIMITER       "\","
43 #define UEVENT_DELIMITER    "="
44 
45 enum DEVMGR_ACTION_TYPE {
46     DEVMGR_ACTION_LOAD,
47     DEVMGR_ACTION_UNLOAD,
48     DEVMGR_ACTION_MAX,
49 };
50 
51 struct DevMgrUeventRuleCfg {
52     char *serviceName;
53     enum DEVMGR_ACTION_TYPE action;
54     struct DListHead matchKeyList;
55     struct DListHead entry;
56 };
57 
58 struct DevMgrMatchKey {
59     char *key;
60     char *value;
61     struct DListHead entry;
62 };
63 
DevMgrUeventRuleCfgList(void)64 static struct DListHead *DevMgrUeventRuleCfgList(void)
65 {
66     static struct DListHead ruleCfgList;
67     static bool initFlag = false;
68 
69     if (!initFlag) {
70         DListHeadInit(&ruleCfgList);
71         initFlag = true;
72     }
73 
74     return &ruleCfgList;
75 }
76 
DevMgrUeventReleaseKeyList(struct DListHead * keyList)77 static void DevMgrUeventReleaseKeyList(struct DListHead *keyList)
78 {
79     struct DevMgrMatchKey *matchKey = NULL;
80     struct DevMgrMatchKey *matchKeyTmp = NULL;
81 
82     if (keyList == NULL) {
83         HDF_LOGE("keyList is null");
84         return;
85     }
86     DLIST_FOR_EACH_ENTRY_SAFE(matchKey, matchKeyTmp, keyList, struct DevMgrMatchKey, entry) {
87         DListRemove(&matchKey->entry);
88         OsalMemFree(matchKey->key);
89         OsalMemFree(matchKey->value);
90         OsalMemFree(matchKey);
91     }
92 }
93 
DevMgrUeventReleaseRuleCfgList(void)94 static void DevMgrUeventReleaseRuleCfgList(void)
95 {
96     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
97     struct DevMgrUeventRuleCfg *ruleCfgTmp = NULL;
98     struct DListHead *ruleCfgList = DevMgrUeventRuleCfgList();
99 
100     DLIST_FOR_EACH_ENTRY_SAFE(ruleCfg, ruleCfgTmp, ruleCfgList, struct DevMgrUeventRuleCfg, entry) {
101         DListRemove(&ruleCfg->entry);
102         DevMgrUeventReleaseKeyList(&ruleCfg->matchKeyList);
103         OsalMemFree(ruleCfg->serviceName);
104         OsalMemFree(ruleCfg);
105     }
106 }
107 
108 // replace substrings "\n" or "\r" in a string with characters '\n' or '\r'
DevMgrUeventReplaceLineFeed(char * str,const char * subStr,char c)109 static void DevMgrUeventReplaceLineFeed(char *str, const char *subStr, char c)
110 {
111     char *ptr = NULL;
112 
113     while ((ptr = strstr(str, subStr)) != NULL) {
114         ptr[0] = c;
115         uint32_t i = 1;
116         if (strlen(ptr) < 1 || strlen(ptr) > SIZE_MAX) {
117             HDF_LOGE("strlen(ptr) overflows");
118             return;
119         }
120         const size_t len = strlen(ptr) - 1;
121         for (; i < len; i++) {
122             ptr[i] = ptr[i + 1];
123         }
124         ptr[i] = '\0';
125     }
126 
127     return;
128 }
129 
DevMgrUeventParseKeyValue(char * str,struct DevMgrMatchKey * matchKey,const char * sep)130 static int32_t DevMgrUeventParseKeyValue(char *str, struct DevMgrMatchKey *matchKey, const char *sep)
131 {
132     char *subPtr = strstr(str, sep);
133     if (subPtr == NULL) {
134         if (strstr(str, "@/") == NULL) {
135             HDF_LOGD("parse Key value failed:[%{public}s]", str);
136         }
137         return HDF_FAILURE;
138     }
139 
140     if (strlen(subPtr) < (strlen(sep) + 1)) {
141         HDF_LOGE("value part invalid:[%{public}s]", str);
142         return HDF_FAILURE;
143     }
144 
145     char *value = subPtr + strlen(sep);
146     *subPtr = '\0';
147     HDF_LOGD("key:%{private}s,value:[%{private}s]", str, value);
148     matchKey->key = strdup(str);
149     matchKey->value = strdup(value);
150     if (matchKey->key == NULL || matchKey->value == NULL) {
151         HDF_LOGE("invalid param : matchKey->key or matchKey->value");
152         return HDF_FAILURE;
153     }
154 
155     return HDF_SUCCESS;
156 }
157 
DevMgrUeventCheckRuleValid(const char * line)158 static bool DevMgrUeventCheckRuleValid(const char *line)
159 {
160     if (strlen(line) < strlen(PNP_EVENT_STR) || line[0] == '#') {
161         return false;
162     }
163 
164     if (strstr(line, PNP_EVENT_STR) == NULL) {
165         HDF_LOGE("%{public}s invalid rule: %{public}s", __func__, line);
166         return false;
167     }
168 
169     return true;
170 }
171 
DevMgrUeventParseMatchKey(char * subStr,struct DListHead * matchKeyList)172 static int32_t DevMgrUeventParseMatchKey(char *subStr, struct DListHead *matchKeyList)
173 {
174     if (subStr == NULL || strlen(subStr) == 0) {
175         HDF_LOGE("match key invalid [%{public}s]", subStr);
176         return HDF_FAILURE;
177     }
178 
179     struct DevMgrMatchKey *matchKey = (struct DevMgrMatchKey *)OsalMemCalloc(sizeof(*matchKey));
180     if (matchKey == NULL) {
181         HDF_LOGE("%{public}s OsalMemCalloc matchKey failed", __func__);
182         return HDF_FAILURE;
183     }
184     if (matchKey->value == NULL || matchKey->key == NULL) {
185         HDF_LOGW("%{public}s OsalMemCalloc matchKey->value or matchKey->key failed", __func__);
186     }
187     DListHeadInit(&matchKey->entry);
188 
189     if (DevMgrUeventParseKeyValue(subStr, matchKey, KEY_VALUE_DELIMITER) == HDF_SUCCESS) {
190         DevMgrUeventReplaceLineFeed(matchKey->value, "\\n", '\n');
191         DevMgrUeventReplaceLineFeed(matchKey->value, "\\r", '\r');
192         DListInsertTail(&matchKey->entry, matchKeyList);
193         return HDF_SUCCESS;
194     } else {
195         OsalMemFree(matchKey);
196         return HDF_FAILURE;
197     }
198 }
199 
DevMgrUeventParseHdfEvent(char * subStr,struct DevMgrUeventRuleCfg * ruleCfg)200 static int32_t DevMgrUeventParseHdfEvent(char *subStr, struct DevMgrUeventRuleCfg *ruleCfg)
201 {
202     if (strncmp(subStr, PNP_EVENT_STR, strlen(PNP_EVENT_STR)) != 0 || strlen(subStr) < strlen(PNP_EVENT_STR) + 1) {
203         HDF_LOGE("parse hdf event %{public}s failed", subStr);
204         return HDF_FAILURE;
205     }
206 
207     char *event = subStr + strlen(PNP_EVENT_STR);
208     char *ptr = strchr(event, ':');
209     if (ptr == NULL) {
210         HDF_LOGE("parse event %{public}s fail, no action", subStr);
211         return HDF_FAILURE;
212     }
213 
214     if (strlen(ptr) < strlen(":load")) {
215         HDF_LOGE("event action part invalid [%{public}s]", ptr);
216         return HDF_FAILURE;
217     }
218 
219     *ptr = '\0';
220     char *action = ptr + 1;
221 
222     // replace line feed
223     ptr = strchr(action, '\n');
224     if (ptr != NULL) {
225         *ptr = '\0';
226     }
227 
228     // replace carriage return
229     ptr = strchr(action, '\r');
230     if (ptr != NULL) {
231         *ptr = '\0';
232     }
233 
234     if (strcmp(action, "load") == 0) {
235         ruleCfg->action = DEVMGR_ACTION_LOAD;
236     } else if (strcmp(action, "unload") == 0) {
237         ruleCfg->action = DEVMGR_ACTION_UNLOAD;
238     } else {
239         HDF_LOGE("parse event action fail [%{public}s]", action);
240         return HDF_FAILURE;
241     }
242 
243     HDF_LOGD("event:%{public}s:%{public}d\n", event, ruleCfg->action);
244     ruleCfg->serviceName = strdup(event);
245     if (ruleCfg->serviceName == NULL) {
246         HDF_LOGE("ruleCfg->serviceName is NULL");
247         return HDF_FAILURE;
248     }
249     if (DListGetCount(&ruleCfg->matchKeyList) == 0) {
250         HDF_LOGE("parse failed, no match key");
251         return HDF_FAILURE;
252     }
253 
254     return HDF_SUCCESS;
255 }
256 
DevMgrUeventParseRule(char * line)257 static int32_t DevMgrUeventParseRule(char *line)
258 {
259     if (!DevMgrUeventCheckRuleValid(line)) {
260         return HDF_FAILURE;
261     }
262 
263     struct DevMgrUeventRuleCfg *ruleCfg = (struct DevMgrUeventRuleCfg *)OsalMemCalloc(sizeof(*ruleCfg));
264     if (ruleCfg == NULL) {
265         HDF_LOGE("%{public}s OsalMemCalloc ruleCfg failed", __func__);
266         return HDF_FAILURE;
267     }
268     if (ruleCfg->serviceName == NULL) {
269         HDF_LOGW("%{public}s OsalMemCalloc ruleCfg->serviceName failed", __func__);
270     }
271     DListHeadInit(&ruleCfg->matchKeyList);
272 
273     char *ptr = line;
274     char *subStr = line;
275     while (ptr != NULL && *ptr != '\0') {
276         ptr = strstr(ptr, KEY_DELIMITER);
277         if (ptr != NULL) {
278             *ptr = '\0';
279             if (DevMgrUeventParseMatchKey(subStr, &ruleCfg->matchKeyList) != HDF_SUCCESS) {
280                 goto FAIL;
281             }
282             ptr += strlen(KEY_DELIMITER);
283             subStr = ptr;
284         } else {
285             if (DevMgrUeventParseHdfEvent(subStr, ruleCfg) != HDF_SUCCESS) {
286                 goto FAIL;
287             }
288             DListInsertTail(&ruleCfg->entry, DevMgrUeventRuleCfgList());
289         }
290     }
291 
292     return HDF_SUCCESS;
293 
294 FAIL:
295     DevMgrUeventReleaseKeyList(&ruleCfg->matchKeyList);
296     OsalMemFree(ruleCfg->serviceName);
297     OsalMemFree(ruleCfg);
298     return HDF_FAILURE;
299 }
300 
DevMgrUeventDisplayRuleCfgList(void)301 static void DevMgrUeventDisplayRuleCfgList(void)
302 {
303     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
304     struct DevMgrMatchKey *matchKey = NULL;
305     struct DListHead *ruleCfgList = DevMgrUeventRuleCfgList();
306 
307     DLIST_FOR_EACH_ENTRY(ruleCfg, ruleCfgList, struct DevMgrUeventRuleCfg, entry) {
308         HDF_LOGD("service:%{public}s action:%{public}d", ruleCfg->serviceName, ruleCfg->action);
309         DLIST_FOR_EACH_ENTRY(matchKey, &ruleCfg->matchKeyList, struct DevMgrMatchKey, entry) {
310             HDF_LOGD("key:%{public}s value:%{public}s", matchKey->key, matchKey->value);
311         }
312     }
313 }
314 
DevMgrUeventParseConfig(void)315 static int32_t DevMgrUeventParseConfig(void)
316 {
317     char path[PATH_MAX] = {0};
318     int ret = sprintf_s(path, PATH_MAX - 1, "%s/hdf_pnp.cfg", HDF_CONFIG_DIR);
319     if (ret < 0) {
320         HDF_LOGE("%{public}s generate file path failed", __func__);
321         return HDF_FAILURE;
322     }
323 
324     char resolvedPath[PATH_MAX] = {0};
325     if (realpath(path, resolvedPath) == NULL) {
326         HDF_LOGE("realpath file: %{public}s failed, errno:%{public}d", path, errno);
327         return HDF_FAILURE;
328     }
329     if (strncmp(resolvedPath, HDF_CONFIG_DIR, strlen(HDF_CONFIG_DIR)) != 0) {
330         HDF_LOGE("%{public}s invalid path %{public}s", __func__, resolvedPath);
331         return HDF_FAILURE;
332     }
333     FILE *file = fopen(resolvedPath, "r");
334     if (file == NULL) {
335         HDF_LOGE("%{public}s fopen %{public}s failed:%{public}d", __func__, resolvedPath, errno);
336         return HDF_FAILURE;
337     }
338 
339     char line[LINE_MAX] = {0};
340     while (fgets(line, sizeof(line), file) != NULL) {
341         HDF_LOGD("%{public}s, %{public}s", __func__, line);
342         DevMgrUeventParseRule(line);
343         (void)memset_s(line, sizeof(line), 0, sizeof(line));
344     }
345 
346     (void)fclose(file);
347     DevMgrUeventDisplayRuleCfgList();
348 
349     return HDF_SUCCESS;
350 }
351 
DevMgrUeventSocketInit(void)352 static int32_t DevMgrUeventSocketInit(void)
353 {
354     struct sockaddr_nl addr;
355     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
356     addr.nl_family = AF_NETLINK;
357     addr.nl_pid = (__u32)getpid();
358     addr.nl_groups = 0xffffffff;
359 
360     int32_t sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
361     if (sockfd < 0) {
362         HDF_LOGE("create socket failed, err = %{public}d", errno);
363         return HDF_FAILURE;
364     }
365     fdsan_exchange_owner_tag(sockfd, 0, LOG_DOMAIN);
366 
367     int32_t buffSize = UEVENT_SOCKET_BUFF_SIZE;
368     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &buffSize, sizeof(buffSize)) != 0) {
369         HDF_LOGE("setsockopt: SO_RCVBUF failed err = %{public}d", errno);
370         fdsan_close_with_tag(sockfd, LOG_DOMAIN);
371         sockfd = -1;
372         return HDF_FAILURE;
373     }
374 
375     const int32_t on = 1;
376     if (setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) != 0) {
377         HDF_LOGE("setsockopt: SO_PASSCRED failed, err = %{public}d", errno);
378         fdsan_close_with_tag(sockfd, LOG_DOMAIN);
379         sockfd = -1;
380         return HDF_FAILURE;
381     }
382 
383     if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
384         HDF_LOGE("bind socket failed, err = %{public}d", errno);
385         fdsan_close_with_tag(sockfd, LOG_DOMAIN);
386         sockfd = -1;
387         return HDF_FAILURE;
388     }
389 
390     return sockfd;
391 }
392 
DevMgrReadUeventMessage(int sockFd,char * buffer,size_t length)393 static ssize_t DevMgrReadUeventMessage(int sockFd, char *buffer, size_t length)
394 {
395     struct sockaddr_nl addr;
396     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
397 
398     struct iovec iov;
399     iov.iov_base = buffer;
400     iov.iov_len = length;
401 
402     char credMsg[CMSG_SPACE(sizeof(struct ucred))] = {0};
403     struct msghdr msghdr = {0};
404     msghdr.msg_name = &addr;
405     msghdr.msg_namelen = sizeof(addr);
406     msghdr.msg_iov = &iov;
407     msghdr.msg_iovlen = 1;
408     msghdr.msg_control = credMsg;
409     msghdr.msg_controllen = sizeof(credMsg);
410 
411     ssize_t n = recvmsg(sockFd, &msghdr, 0);
412     if (n <= 0) {
413         return HDF_FAILURE;
414     }
415 
416     struct cmsghdr *hdr = CMSG_FIRSTHDR(&msghdr);
417     if (hdr == NULL || hdr->cmsg_type != SCM_CREDENTIALS) {
418         HDF_LOGI("Unexpected control message, ignored");
419         // drop this message
420         *buffer = '\0';
421         return HDF_FAILURE;
422     }
423 
424     return n;
425 }
426 
DevMgrUeventMsgCheckValid(const char * msg,ssize_t msgLen)427 static bool DevMgrUeventMsgCheckValid(const char *msg, ssize_t msgLen)
428 {
429     (void)msgLen;
430     if (strncmp(msg, "libudev", strlen("libudev")) == 0) {
431         return false;
432     }
433     return true;
434 }
435 
DevMgrUeventMatchRule(struct DListHead * keyList,struct DListHead * ruleKeyList)436 static bool DevMgrUeventMatchRule(struct DListHead *keyList, struct DListHead *ruleKeyList)
437 {
438     struct DevMgrMatchKey *key = NULL;
439     struct DevMgrMatchKey *keyMsg = NULL;
440 
441     DLIST_FOR_EACH_ENTRY(key, ruleKeyList, struct DevMgrMatchKey, entry) {
442         bool match = false;
443         DLIST_FOR_EACH_ENTRY(keyMsg, keyList, struct DevMgrMatchKey, entry) {
444             if (strcmp(key->key, keyMsg->key) == 0) {
445                 if (strcmp(key->value, keyMsg->value) == 0) {
446                     match = true;
447                     break;
448                 } else {
449                     return false;
450                 }
451             }
452         }
453         if (!match) {
454             return false;
455         }
456     }
457 
458     return true;
459 }
460 
DevMgrUeventProcessPnPEvent(const struct DevMgrUeventRuleCfg * ruleCfg)461 static void DevMgrUeventProcessPnPEvent(const struct DevMgrUeventRuleCfg *ruleCfg)
462 {
463     struct IDevmgrService *instance = DevmgrServiceGetInstance();
464 
465     if (instance == NULL) {
466         HDF_LOGE("Getting DevmgrService instance failed");
467         return;
468     }
469 
470     if (ruleCfg->action == DEVMGR_ACTION_LOAD) {
471         instance->LoadDevice(instance, ruleCfg->serviceName);
472     } else {
473         instance->UnloadDevice(instance, ruleCfg->serviceName);
474     }
475 }
476 
DevMgrUeventMatchRules(struct DListHead * keyList,struct DListHead * ruleList)477 static bool DevMgrUeventMatchRules(struct DListHead *keyList, struct DListHead *ruleList)
478 {
479     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
480 
481     DLIST_FOR_EACH_ENTRY(ruleCfg, ruleList, struct DevMgrUeventRuleCfg, entry) {
482         if (DevMgrUeventMatchRule(keyList, &ruleCfg->matchKeyList)) {
483             HDF_LOGI("%{public}s %{public}s %{public}d", __func__, ruleCfg->serviceName, ruleCfg->action);
484             DevMgrUeventProcessPnPEvent(ruleCfg);
485             return true;
486         }
487     }
488 
489     return false;
490 }
491 
DevMgrParseUevent(char * msg,ssize_t msgLen)492 static int32_t DevMgrParseUevent(char *msg, ssize_t msgLen)
493 {
494     if (!DevMgrUeventMsgCheckValid(msg, msgLen)) {
495         return HDF_FAILURE;
496     }
497 
498     struct DListHead keyList;
499     DListHeadInit(&keyList);
500     struct DevMgrMatchKey *key = NULL;
501 
502     for (char *ptr = msg; ptr < (msg + msgLen);) {
503         if (*ptr == '0') {
504             ptr++;
505             continue;
506         }
507 
508         if (key == NULL) {
509             key = (struct DevMgrMatchKey *)OsalMemCalloc(sizeof(*key));
510             if (key == NULL) {
511                 DevMgrUeventReleaseKeyList(&keyList);
512                 return HDF_FAILURE;
513             }
514             DListHeadInit(&key->entry);
515         }
516 
517         uint32_t subStrLen = (uint32_t)strlen(ptr) + 1;
518         HDF_LOGD("%{public}s %{public}d [%{private}s]", __func__, subStrLen, ptr);
519         if (DevMgrUeventParseKeyValue(ptr, key, UEVENT_DELIMITER) == HDF_SUCCESS) {
520             DListInsertHead(&key->entry, &keyList);
521             key = NULL;
522         }
523         ptr += subStrLen;
524     }
525 
526     HDF_LOGD("%{public}s {%{public}s} %{public}zd", __func__, msg, msgLen);
527     DevMgrUeventMatchRules(&keyList, DevMgrUeventRuleCfgList());
528     DevMgrUeventReleaseKeyList(&keyList);
529 
530     return HDF_SUCCESS;
531 }
532 
533 #define DEVMGR_UEVENT_MSG_SIZE  2048
534 #define DEVMGR_UEVENT_WAIT_TIME 1000
DevMgrUeventThread(void * arg)535 static int32_t DevMgrUeventThread(void *arg)
536 {
537     (void)arg;
538     int32_t sfd = DevMgrUeventSocketInit();
539     if (sfd < 0) {
540         HDF_LOGE("DevMgrUeventSocketInit get sfd error");
541         return HDF_FAILURE;
542     }
543 
544     char msg[DEVMGR_UEVENT_MSG_SIZE + 1] = {0};
545     ssize_t msgLen;
546     struct pollfd fd;
547     (void)memset_s(&fd, sizeof(fd), 0, sizeof(fd));
548     fd.fd = sfd;
549     fd.events = POLLIN | POLLERR;
550     while (true) {
551         if (poll(&fd, 1, -1) <= 0) {
552             HDF_LOGE("%{public}s poll fail %{public}d", __func__, errno);
553             OsalMSleep(DEVMGR_UEVENT_WAIT_TIME);
554             continue;
555         }
556         if (((uint32_t)fd.revents & (POLLIN | POLLERR)) != 0) {
557             int backErrno = errno;
558             msgLen = DevMgrReadUeventMessage(sfd, msg, DEVMGR_UEVENT_MSG_SIZE);
559             if (((uint32_t)fd.revents & POLLERR) != 0) {
560                 HDF_LOGE("%{public}s poll error", __func__);
561             }
562             if (msgLen <= 0) {
563                 HDF_LOGE("%{public}s recv errno: %{public}d", __func__, backErrno);
564                 continue;
565             }
566             DevMgrParseUevent(msg, msgLen);
567             (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
568         }
569     }
570 
571     DevMgrUeventReleaseRuleCfgList();
572     fdsan_close_with_tag(sfd, LOG_DOMAIN);
573     sfd = -1;
574     return HDF_SUCCESS;
575 }
576 
577 #define DEVMGR_UEVENT_STACK_SIZE 100000
578 
DevMgrUeventReceiveStart(void)579 int32_t DevMgrUeventReceiveStart(void)
580 {
581     HDF_LOGI("DevMgrUeventReceiveStart");
582     if (DevMgrUeventParseConfig() == HDF_FAILURE) {
583         return HDF_FAILURE;
584     }
585 
586     struct OsalThreadParam threadCfg;
587     (void)memset_s(&threadCfg, sizeof(threadCfg), 0, sizeof(threadCfg));
588     threadCfg.name = "DevMgrUevent";
589     threadCfg.priority = OSAL_THREAD_PRI_HIGH;
590     threadCfg.stackSize = DEVMGR_UEVENT_STACK_SIZE;
591 
592     OSAL_DECLARE_THREAD(thread);
593     (void)OsalThreadCreate(&thread, (OsalThreadEntry)DevMgrUeventThread, NULL);
594     (void)OsalThreadStart(&thread, &threadCfg);
595 
596     return HDF_SUCCESS;
597 }
598