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