1 /*
2  * Copyright (c) 2021 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 "osal_sysevent.h"
17 #include "hdf_io_service_if.h"
18 #include "hdf_log.h"
19 #include "osal_mem.h"
20 #include "osal_mutex.h"
21 
22 #define HDF_LOG_TAG usysevent
23 
24 #define KEVENT_IOSERVICE_NAME "hdf_kevent"
25 
26 #define KEVENT_COMPLETE_EVENT 1
27 
28 struct HdfSysEventNotifier {
29     struct OsalMutex mutex;
30     struct DListHead notifyNodeList;
31     struct DListHead waitList;
32     struct HdfDevEventlistener ioServiceListener;
33     struct HdfIoService *keventIoService;
34 };
35 
HdfSysEventNotifierGetInstance(void)36 static struct HdfSysEventNotifier *HdfSysEventNotifierGetInstance(void)
37 {
38     static struct HdfSysEventNotifier *hdfSysEventNotifier = NULL;
39     if (hdfSysEventNotifier != NULL) {
40         return hdfSysEventNotifier;
41     }
42 
43     struct HdfSysEventNotifier *notifier = OsalMemCalloc(sizeof(struct HdfSysEventNotifier));
44     if (notifier == NULL) {
45         return NULL;
46     }
47 
48     int ret = OsalMutexInit(&notifier->mutex);
49     if (ret != HDF_SUCCESS) {
50         OsalMemFree(notifier);
51         return NULL;
52     }
53 
54     DListHeadInit(&notifier->notifyNodeList);
55 
56     hdfSysEventNotifier = notifier;
57 
58     return notifier;
59 }
60 
FinishEvent(struct HdfIoService * service,const struct HdfSysEvent * event)61 static int FinishEvent(struct HdfIoService *service, const struct HdfSysEvent *event)
62 {
63     struct HdfSBuf *sbuf = HdfSbufObtain(sizeof(uint64_t));
64 
65     if (sbuf == NULL) {
66         return HDF_ERR_MALLOC_FAIL;
67     }
68 
69     if (!HdfSbufWriteUint64(sbuf, event->syncToken)) {
70         HdfSbufRecycle(sbuf);
71         return HDF_FAILURE;
72     }
73 
74     int ret = service->dispatcher->Dispatch(&service->object, KEVENT_COMPLETE_EVENT, sbuf, NULL);
75     if (ret != HDF_SUCCESS) {
76         HDF_LOGE("failed to finish sysevent, %{public}d", ret);
77     }
78 
79     HdfSbufRecycle(sbuf);
80     return ret;
81 }
82 
OnKEventReceived(struct HdfDevEventlistener * listener,struct HdfIoService * service,uint32_t id,struct HdfSBuf * data)83 static int OnKEventReceived(
84     struct HdfDevEventlistener *listener, struct HdfIoService *service, uint32_t id, struct HdfSBuf *data)
85 {
86     struct HdfSysEventNotifier *notifier = (struct HdfSysEventNotifier *)listener->priv;
87     if (notifier == NULL) {
88         return HDF_ERR_INVALID_PARAM;
89     }
90 
91     if (id != HDF_SYSEVENT) {
92         return HDF_ERR_INVALID_OBJECT;
93     }
94 
95     struct HdfSysEvent *receivedEvent = NULL;
96     uint32_t receivedEventLen = 0;
97 
98     if (!HdfSbufReadBuffer(data, (const void **)&receivedEvent, &receivedEventLen) ||
99         receivedEventLen != sizeof(struct HdfSysEvent)) {
100         HDF_LOGE("failed to read kevent object");
101         return HDF_FAILURE;
102     }
103 
104     const char *eventContent = HdfSbufReadString(data);
105     eventContent = eventContent == NULL ? "" : eventContent;
106     OsalMutexLock(&notifier->mutex);
107 
108     struct HdfSysEventNotifyNode *notifyNode = NULL;
109     DLIST_FOR_EACH_ENTRY(notifyNode, &notifier->notifyNodeList, struct HdfSysEventNotifyNode, listNode) {
110         if (receivedEvent->eventClass & notifyNode->classFilter) {
111             (void)notifyNode->callback(
112                 notifyNode, receivedEvent->eventClass, receivedEvent->eventid, eventContent);
113         }
114     }
115 
116     if (receivedEvent->syncToken != 0) {
117         (void)FinishEvent(service, receivedEvent);
118     }
119 
120     OsalMutexUnlock(&notifier->mutex);
121 
122     return HDF_SUCCESS;
123 }
124 
InitKeventIoServiceListenerLocked(struct HdfSysEventNotifier * notifier)125 static int InitKeventIoServiceListenerLocked(struct HdfSysEventNotifier *notifier)
126 {
127     if (notifier->keventIoService == NULL) {
128         notifier->keventIoService = HdfIoServiceBind(KEVENT_IOSERVICE_NAME);
129     }
130     if (notifier->keventIoService == NULL) {
131         HDF_LOGE(" ioservice %{public}s is invalid", KEVENT_IOSERVICE_NAME);
132         return HDF_DEV_ERR_NO_DEVICE;
133     }
134 
135     notifier->ioServiceListener.onReceive = OnKEventReceived;
136     notifier->ioServiceListener.priv = notifier;
137     int ret = HdfDeviceRegisterEventListener(notifier->keventIoService, &notifier->ioServiceListener);
138     if (ret != HDF_SUCCESS) {
139         HDF_LOGE(" ioservice %{public}s is invalid", KEVENT_IOSERVICE_NAME);
140         HdfIoServiceRecycle(notifier->keventIoService);
141         notifier->keventIoService = NULL;
142     }
143 
144     return ret;
145 }
146 
DeInitKeventIoServiceListenerLocked(struct HdfSysEventNotifier * notifier)147 static void DeInitKeventIoServiceListenerLocked(struct HdfSysEventNotifier *notifier)
148 {
149     if (notifier->keventIoService == NULL) {
150         return;
151     }
152 
153     (void)HdfDeviceUnregisterEventListener(notifier->keventIoService, &notifier->ioServiceListener);
154     HdfIoServiceRecycle(notifier->keventIoService);
155     notifier->keventIoService = NULL;
156 }
157 
HdfSysEventNotifyRegister(struct HdfSysEventNotifyNode * notifierNode,uint64_t classSet)158 int32_t HdfSysEventNotifyRegister(struct HdfSysEventNotifyNode *notifierNode, uint64_t classSet)
159 {
160     if (notifierNode == NULL) {
161         return HDF_ERR_INVALID_PARAM;
162     }
163 
164     struct HdfSysEventNotifier *notifier = HdfSysEventNotifierGetInstance();
165 
166     if (notifier == NULL) {
167         return HDF_DEV_ERR_NO_MEMORY;
168     }
169 
170     OsalMutexLock(&notifier->mutex);
171     DListInsertTail(&notifierNode->listNode, &notifier->notifyNodeList);
172     notifierNode->classFilter = classSet;
173     int32_t ret = InitKeventIoServiceListenerLocked(notifier);
174     if (ret != HDF_SUCCESS) {
175         DListRemove(&notifierNode->listNode);
176     }
177     OsalMutexUnlock(&notifier->mutex);
178 
179     return ret;
180 }
181 
HdfSysEventNotifyUnregister(struct HdfSysEventNotifyNode * notifierNode)182 void HdfSysEventNotifyUnregister(struct HdfSysEventNotifyNode *notifierNode)
183 {
184     if (notifierNode == NULL) {
185         return;
186     }
187 
188     struct HdfSysEventNotifier *notifier = HdfSysEventNotifierGetInstance();
189 
190     if (notifier == NULL) {
191         return;
192     }
193     OsalMutexLock(&notifier->mutex);
194 
195     DListRemove(&notifierNode->listNode);
196     if (DListIsEmpty(&notifier->notifyNodeList)) {
197         DeInitKeventIoServiceListenerLocked(notifier);
198     }
199     OsalMutexUnlock(&notifier->mutex);
200 }
201