1/*
2 * Copyright (c) 2022-2023 Shenzhen Kaihong DID 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#include "codec_component_manager_service.h"
16#include <hdf_base.h>
17#include <osal_mem.h>
18#include <securec.h>
19#include <unistd.h>
20#include "codec_adapter_interface.h"
21#include "codec_component_capability_config.h"
22#include "codec_component_manager_stub.h"
23#include "codec_component_type_service.h"
24#include "codec_death_recipient.h"
25#include "codec_log_wrapper.h"
26
27#define MAX_COMPONENT_SIZE 32
28struct CodecComponentManagerSerivce *g_service = NULL;
29uint32_t g_componentId = 0;
30
31static void OnRemoteServiceDied(struct HdfDeathRecipient *deathRecipient, struct HdfRemoteService *remote)
32{
33    CleanRemoteServiceResource(deathRecipient, remote);
34}
35
36static struct RemoteServiceDeathRecipient g_deathRecipient = {
37    .recipient = {
38        .OnRemoteDied = OnRemoteServiceDied,
39    }
40};
41
42static void AddDeathRecipientForService(struct CodecCallbackType *callbacks, uint32_t componentId,
43                                        struct CodecComponentNode *codecNode)
44{
45    if (callbacks == NULL) {
46        CODEC_LOGE("invalid parameter");
47        return;
48    }
49    bool needAdd = RegisterService(callbacks, componentId, codecNode);
50    if (needAdd) {
51        CODEC_LOGI("add deathRecipient for remoteService!");
52        HdfRemoteServiceAddDeathRecipient(callbacks->remote, &g_deathRecipient.recipient);
53    }
54}
55
56static uint32_t GetNextComponentId()
57{
58    uint32_t tempId = 0;
59    if (g_service == NULL) {
60        return tempId;
61    }
62    struct ComponentTypeNode *pos = NULL;
63    struct ComponentTypeNode *next = NULL;
64    bool find = false;
65
66    do {
67        tempId = ++g_componentId;
68        find = false;
69        DLIST_FOR_EACH_ENTRY_SAFE(pos, next, &g_service->head, struct ComponentTypeNode, node)
70        {
71            if (pos != NULL && tempId == pos->componentId) {
72                find = true;
73                break;
74            }
75        }
76    } while (find);
77    return tempId;
78}
79
80static int32_t OmxManagerGetComponentNum()
81{
82    int32_t num = 0;
83    if (GetComponentNum(&num) != HDF_SUCCESS) {
84        CODEC_LOGE("GetComponentNum error!");
85    }
86    return num;
87}
88
89static int32_t OmxManagerGetComponentCapabilityList(CodecCompCapability *capList, int32_t count)
90{
91    int32_t err = GetComponentCapabilityList(capList, count);
92    if (err != HDF_SUCCESS) {
93        CODEC_LOGE("GetComponentNum error!");
94    }
95    return err;
96}
97
98static int32_t OmxManagerDestroyComponent(uint32_t componentId)
99{
100    CODEC_LOGI("service impl, %{public}d!", componentId);
101    if (g_service == NULL) {
102        CODEC_LOGE("g_service is not init!");
103        return HDF_ERR_INVALID_PARAM;
104    }
105
106    struct ComponentTypeNode *pos = NULL;
107    struct ComponentTypeNode *next = NULL;
108    int32_t err = HDF_SUCCESS;
109    pthread_mutex_lock(&g_service->listMute);
110
111    DLIST_FOR_EACH_ENTRY_SAFE(pos, next, &g_service->head, struct ComponentTypeNode, node)
112    {
113        if (pos == NULL || componentId != pos->componentId) {
114            continue;
115        }
116
117        struct CodecComponentNode *codecNode = CodecComponentTypeServiceGetCodecNode(pos->service);
118        if (codecNode != NULL) {
119            err = OmxAdapterDestroyComponent(codecNode);
120            if (err != HDF_SUCCESS) {
121                CODEC_LOGE("OmxAdapterDestroyComponent ret err[%{public}d]!", err);
122                break;
123            }
124            RemoveDestoryedComponent(componentId);
125        }
126
127        DListRemove(&pos->node);
128        CodecComponentTypeServiceRelease(pos->service);
129        OsalMemFree(pos);
130        pos = NULL;
131        break;
132    }
133
134    pthread_mutex_unlock(&g_service->listMute);
135    return err;
136}
137
138static int32_t OmxManagerCreateComponent(struct CodecComponentType **component, uint32_t *componentId, char *compName,
139                                         int64_t appData, struct CodecCallbackType *callbacks)
140{
141    CODEC_LOGI("service impl!");
142    if (g_service == NULL) {
143        CODEC_LOGE("g_service is not init!");
144        return HDF_ERR_INVALID_PARAM;
145    }
146
147    struct CodecComponentType *comp = CodecComponentTypeServiceGet();
148    if (comp == NULL) {
149        CODEC_LOGE("CodecComponentTypeServiceGet ret null!");
150        return HDF_ERR_INVALID_PARAM;
151    }
152
153    struct ComponentTypeNode *node = (struct ComponentTypeNode *)OsalMemCalloc(sizeof(struct ComponentTypeNode));
154    if (node == NULL) {
155        CODEC_LOGE("CodecComponentTypeServiceGet ret null!");
156        CodecComponentTypeServiceRelease(comp);
157        return HDF_ERR_INVALID_PARAM;
158    }
159
160    struct CodecComponentNode *codecNode = NULL;
161    int32_t err = OMXAdapterCreateComponent(&codecNode, compName, appData, callbacks);
162    if (err != HDF_SUCCESS) {
163        CODEC_LOGE("OMXAdapterCreateComponent err [%{public}x]", err);
164        CodecComponentTypeServiceRelease(comp);
165        OsalMemFree(node);
166        return HDF_ERR_INVALID_PARAM;
167    }
168    *component = comp;
169    pthread_mutex_lock(&g_service->listMute);
170    *componentId = GetNextComponentId();
171    CodecComponentTypeServiceSetCodecNode(comp, codecNode);
172    DListInsertTail(&node->node, &g_service->head);
173    pthread_mutex_unlock(&g_service->listMute);
174    node->componentId = *componentId;
175    node->service = comp;
176#ifdef SUPPORT_ROLE
177    err = OmxAdapterSetComponentRole(codecNode, compName);
178    if (err != HDF_SUCCESS) {
179        CODEC_LOGE("OMXAdapterSetComponentRole err [%{public}x]", err);
180        OmxManagerDestroyComponent(*componentId);
181        CodecComponentTypeServiceRelease(comp);
182        OsalMemFree(node);
183        return HDF_ERR_INVALID_PARAM;
184    }
185#endif
186    CODEC_LOGI("componentId:%{public}d", node->componentId);
187    AddDeathRecipientForService(callbacks, *componentId, codecNode);
188    return err;
189}
190
191static void CodecComponentManagerServiceConstruct(struct CodecComponentManager *manager)
192{
193    if (manager != NULL) {
194        manager->GetComponentNum = OmxManagerGetComponentNum;
195        manager->GetComponentCapabilityList = OmxManagerGetComponentCapabilityList;
196        manager->CreateComponent = OmxManagerCreateComponent;
197        manager->DestroyComponent = OmxManagerDestroyComponent;
198    }
199}
200
201struct CodecComponentManagerSerivce *CodecComponentManagerSerivceGet(void)
202{
203    if (g_service == NULL) {
204        g_service = (struct CodecComponentManagerSerivce *)OsalMemCalloc(sizeof(struct CodecComponentManagerSerivce));
205        if (g_service == NULL) {
206            CODEC_LOGE("malloc OmxComponentManagerService obj failed!");
207            return NULL;
208        }
209        DListHeadInit(&g_service->head);
210        if (!CodecComponentManagerStubConstruct(&g_service->stub)) {
211            CODEC_LOGE("construct SampleStub obj failed!");
212            OmxComponentManagerSeriveRelease(g_service);
213            g_service = NULL;
214        }
215        CodecComponentManagerServiceConstruct(&g_service->stub.interface);
216    }
217    return g_service;
218}
219
220void OmxComponentManagerSeriveRelease(struct CodecComponentManagerSerivce *instance)
221{
222    if (instance == NULL) {
223        return;
224    }
225    if (g_service == instance) {
226        g_service = NULL;
227    }
228    OsalMemFree(instance);
229}
230
231void CleanRemoteServiceResource(struct HdfDeathRecipient *deathRecipient, struct HdfRemoteService *remote)
232{
233    uint32_t compIds[MAX_COMPONENT_SIZE];
234    uint32_t size = 0;
235    int32_t ret = CleanMapperOfDiedService(remote, compIds, &size);
236    if (ret != HDF_SUCCESS) {
237        CODEC_LOGE("clearn remote resource error!");
238        return;
239    }
240
241    if (size == 0) {
242        CODEC_LOGE("remoteService no componment resource need to be release!");
243        return;
244    }
245    for (uint32_t i = 0; i < size; i++) {
246        OmxManagerDestroyComponent(compIds[i]);
247        CODEC_LOGI("destroyComponent done, compId=[%{public}d]", compIds[i]);
248    }
249
250    CODEC_LOGI("remote service died , clean resource success!");
251}