/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "osal_sysevent.h" #include "hdf_io_service_if.h" #include "hdf_log.h" #include "osal_mem.h" #include "osal_mutex.h" #define HDF_LOG_TAG usysevent #define KEVENT_IOSERVICE_NAME "hdf_kevent" #define KEVENT_COMPLETE_EVENT 1 struct HdfSysEventNotifier { struct OsalMutex mutex; struct DListHead notifyNodeList; struct DListHead waitList; struct HdfDevEventlistener ioServiceListener; struct HdfIoService *keventIoService; }; static struct HdfSysEventNotifier *HdfSysEventNotifierGetInstance(void) { static struct HdfSysEventNotifier *hdfSysEventNotifier = NULL; if (hdfSysEventNotifier != NULL) { return hdfSysEventNotifier; } struct HdfSysEventNotifier *notifier = OsalMemCalloc(sizeof(struct HdfSysEventNotifier)); if (notifier == NULL) { return NULL; } int ret = OsalMutexInit(¬ifier->mutex); if (ret != HDF_SUCCESS) { OsalMemFree(notifier); return NULL; } DListHeadInit(¬ifier->notifyNodeList); hdfSysEventNotifier = notifier; return notifier; } static int FinishEvent(struct HdfIoService *service, const struct HdfSysEvent *event) { struct HdfSBuf *sbuf = HdfSbufObtain(sizeof(uint64_t)); if (sbuf == NULL) { return HDF_ERR_MALLOC_FAIL; } if (!HdfSbufWriteUint64(sbuf, event->syncToken)) { HdfSbufRecycle(sbuf); return HDF_FAILURE; } int ret = service->dispatcher->Dispatch(&service->object, KEVENT_COMPLETE_EVENT, sbuf, NULL); if (ret != HDF_SUCCESS) { HDF_LOGE("failed to finish sysevent, %{public}d", ret); } HdfSbufRecycle(sbuf); return ret; } static int OnKEventReceived( struct HdfDevEventlistener *listener, struct HdfIoService *service, uint32_t id, struct HdfSBuf *data) { struct HdfSysEventNotifier *notifier = (struct HdfSysEventNotifier *)listener->priv; if (notifier == NULL) { return HDF_ERR_INVALID_PARAM; } if (id != HDF_SYSEVENT) { return HDF_ERR_INVALID_OBJECT; } struct HdfSysEvent *receivedEvent = NULL; uint32_t receivedEventLen = 0; if (!HdfSbufReadBuffer(data, (const void **)&receivedEvent, &receivedEventLen) || receivedEventLen != sizeof(struct HdfSysEvent)) { HDF_LOGE("failed to read kevent object"); return HDF_FAILURE; } const char *eventContent = HdfSbufReadString(data); eventContent = eventContent == NULL ? "" : eventContent; OsalMutexLock(¬ifier->mutex); struct HdfSysEventNotifyNode *notifyNode = NULL; DLIST_FOR_EACH_ENTRY(notifyNode, ¬ifier->notifyNodeList, struct HdfSysEventNotifyNode, listNode) { if (receivedEvent->eventClass & notifyNode->classFilter) { (void)notifyNode->callback( notifyNode, receivedEvent->eventClass, receivedEvent->eventid, eventContent); } } if (receivedEvent->syncToken != 0) { (void)FinishEvent(service, receivedEvent); } OsalMutexUnlock(¬ifier->mutex); return HDF_SUCCESS; } static int InitKeventIoServiceListenerLocked(struct HdfSysEventNotifier *notifier) { if (notifier->keventIoService == NULL) { notifier->keventIoService = HdfIoServiceBind(KEVENT_IOSERVICE_NAME); } if (notifier->keventIoService == NULL) { HDF_LOGE(" ioservice %{public}s is invalid", KEVENT_IOSERVICE_NAME); return HDF_DEV_ERR_NO_DEVICE; } notifier->ioServiceListener.onReceive = OnKEventReceived; notifier->ioServiceListener.priv = notifier; int ret = HdfDeviceRegisterEventListener(notifier->keventIoService, ¬ifier->ioServiceListener); if (ret != HDF_SUCCESS) { HDF_LOGE(" ioservice %{public}s is invalid", KEVENT_IOSERVICE_NAME); HdfIoServiceRecycle(notifier->keventIoService); notifier->keventIoService = NULL; } return ret; } static void DeInitKeventIoServiceListenerLocked(struct HdfSysEventNotifier *notifier) { if (notifier->keventIoService == NULL) { return; } (void)HdfDeviceUnregisterEventListener(notifier->keventIoService, ¬ifier->ioServiceListener); HdfIoServiceRecycle(notifier->keventIoService); notifier->keventIoService = NULL; } int32_t HdfSysEventNotifyRegister(struct HdfSysEventNotifyNode *notifierNode, uint64_t classSet) { if (notifierNode == NULL) { return HDF_ERR_INVALID_PARAM; } struct HdfSysEventNotifier *notifier = HdfSysEventNotifierGetInstance(); if (notifier == NULL) { return HDF_DEV_ERR_NO_MEMORY; } OsalMutexLock(¬ifier->mutex); DListInsertTail(¬ifierNode->listNode, ¬ifier->notifyNodeList); notifierNode->classFilter = classSet; int32_t ret = InitKeventIoServiceListenerLocked(notifier); if (ret != HDF_SUCCESS) { DListRemove(¬ifierNode->listNode); } OsalMutexUnlock(¬ifier->mutex); return ret; } void HdfSysEventNotifyUnregister(struct HdfSysEventNotifyNode *notifierNode) { if (notifierNode == NULL) { return; } struct HdfSysEventNotifier *notifier = HdfSysEventNotifierGetInstance(); if (notifier == NULL) { return; } OsalMutexLock(¬ifier->mutex); DListRemove(¬ifierNode->listNode); if (DListIsEmpty(¬ifier->notifyNodeList)) { DeInitKeventIoServiceListenerLocked(notifier); } OsalMutexUnlock(¬ifier->mutex); }