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(¬ifier->mutex);
49 if (ret != HDF_SUCCESS) {
50 OsalMemFree(notifier);
51 return NULL;
52 }
53
54 DListHeadInit(¬ifier->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(¬ifier->mutex);
107
108 struct HdfSysEventNotifyNode *notifyNode = NULL;
109 DLIST_FOR_EACH_ENTRY(notifyNode, ¬ifier->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(¬ifier->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, ¬ifier->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, ¬ifier->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(¬ifier->mutex);
171 DListInsertTail(¬ifierNode->listNode, ¬ifier->notifyNodeList);
172 notifierNode->classFilter = classSet;
173 int32_t ret = InitKeventIoServiceListenerLocked(notifier);
174 if (ret != HDF_SUCCESS) {
175 DListRemove(¬ifierNode->listNode);
176 }
177 OsalMutexUnlock(¬ifier->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(¬ifier->mutex);
194
195 DListRemove(¬ifierNode->listNode);
196 if (DListIsEmpty(¬ifier->notifyNodeList)) {
197 DeInitKeventIoServiceListenerLocked(notifier);
198 }
199 OsalMutexUnlock(¬ifier->mutex);
200 }
201