fbfa6fe4创建于 2025年3月22日历史提交
/*

 * Copyright (c) 2020 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 "message_inner.h"

#include <ohos_errno.h>

#include <log.h>

#include "memory_adapter.h"

#include "queue_adapter.h"

#include "securec.h"

#include "task_manager.h"



#undef LOG_TAG

#undef LOG_DOMAIN

#define LOG_TAG "Samgr"

#define LOG_DOMAIN 0xD001800



#define DONT_WAIT 0

#define WAIT_FOREVER (-1)

static int32 SharedSend(MQueueId queueId, Exchange *exchange, int initRef);

static BOOL FreeReference(Exchange *exchange);



int32 SAMGR_SendRequest(const Identity *identity, const Request *request, Handler handler)

{

    if (request == NULL || identity == NULL) {

        return EC_INVALID;

    }



    Exchange exchange = {*identity, *request, {NULL, 0, NULL}, MSG_NON, handler, NULL};

    exchange.id.queueId = NULL;

    if (handler != NULL) {

        exchange.id.queueId = SAMGR_GetCurrentQueueID();

        exchange.type = MSG_CON;

    }



    return QUEUE_Put(identity->queueId, &exchange, 0, DONT_WAIT);

}



int32 SAMGR_SendResponse(const Request *request, const Response *response)

{

    // we need send the default the con message or not?

    if (request == NULL) {

        return EC_INVALID;

    }



    Exchange *exchange = GET_OBJECT(request, Exchange, request);

    if (exchange->type != MSG_CON) {

        return EC_INVALID;

    }



    if (exchange->handler == NULL) {

        return EC_SUCCESS;

    }



    exchange->type = MSG_ACK;

    exchange->response.data = NULL;

    exchange->response.len = 0;

    if (response != NULL) {

        exchange->response = *response;

    }



    // If there is no task queue, we will call the response processor in current task.

    if (exchange->id.queueId == NULL) {

        exchange->handler(&exchange->request, &exchange->response);

        return EC_SUCCESS;

    }



    // Send back to the origin to process the task.

    int32 ret = SharedSend(exchange->id.queueId, exchange, 1);

    if (ret != EC_SUCCESS) {

        exchange->handler(&exchange->request, &exchange->response);

        (void)FreeReference(exchange);

    }

    return EC_SUCCESS;

}



int32 SAMGR_MsgRecv(MQueueId queueId, uint8 *interMsg, uint32 size)

{

    if (queueId == NULL || interMsg == NULL || size == 0) {

        return EC_INVALID;

    }



    if (memset_s(interMsg, size, 0x00, size) != EOK) {

        return EC_FAILURE;

    }



    return QUEUE_Pop(queueId, interMsg, 0, WAIT_FOREVER);

}



int32 SAMGR_FreeMsg(Exchange *exchange)

{

    if (!FreeReference(exchange)) {

        return EC_SUCCESS;

    }



    if (exchange->request.len > 0) {

        SAMGR_Free(exchange->request.data);

        exchange->request.data = NULL;

    }



    if (exchange->response.len > 0) {

        SAMGR_Free(exchange->response.data);

        exchange->response.data = NULL;

    }

    return EC_SUCCESS;

}



uint32 *SAMGR_SendSharedRequest(const Identity *identity, const Request *request, uint32 *token, Handler handler)

{

    if (identity == NULL || request == NULL) {

        return NULL;

    }

    Exchange exchange = {*identity, *request, {NULL, 0, NULL}, MSG_NON, handler, token};

    exchange.type = (handler == NULL) ? MSG_NON : MSG_CON;

    exchange.id.queueId = NULL;

    int32 err = SharedSend(identity->queueId, &exchange, 0);

    if (err != EC_SUCCESS) {

        HILOG_ERROR(HILOG_MODULE_SAMGR, "SharedSend failed(%d)!", err);

        (void)FreeReference(&exchange);

    }

    return exchange.sharedRef;

}



int32 SAMGR_SendSharedDirectRequest(const Identity *id, const Request *req, const Response *resp, uint32 **ref,

                                    Handler handler)

{

    if (handler == NULL || ref == NULL) {

        return EC_INVALID;

    }



    Exchange exchange = {0};

    if (req != NULL) {

        exchange.request = *req;

    }



    if (resp != NULL) {

        exchange.response = *resp;

    }



    exchange.handler = handler;

    exchange.sharedRef = *ref;

    exchange.type = MSG_DIRECT;

    exchange.id = *id;

    exchange.id.queueId = NULL;

    int32 err = SharedSend(id->queueId, &exchange, 0);

    if (err != EC_SUCCESS) {

        HILOG_ERROR(HILOG_MODULE_SAMGR, "SharedSend failed(%d)!", err);

        (void)FreeReference(&exchange);

    }

    *ref = exchange.sharedRef;

    return err;

}



int32 SAMGR_SendResponseByIdentity(const Identity *id, const Request *request, const Response *response)

{

    // we need send the default the con message or not?

    if (request == NULL || id == NULL) {

        return EC_INVALID;

    }



    Exchange *exchange = GET_OBJECT(request, Exchange, request);

    if (exchange->type == MSG_NON) {

        return EC_INVALID;

    }

    exchange->id.queueId = id->queueId;



    return SAMGR_SendResponse(request, response);

}



static int32 SharedSend(MQueueId queueId, Exchange *exchange, int initRef)

{

    /* if the msg data and response is NULL, we just direct copy, no need shared the message. */

    if ((exchange->request.data == NULL || exchange->request.len <= 0) &&

        (exchange->response.data == NULL || exchange->response.len <= 0)) {

        return QUEUE_Put(queueId, exchange, 0, DONT_WAIT);

    }



    /* 1.add reference */

    MUTEX_GlobalLock();

    if (exchange->sharedRef == NULL) {

        exchange->sharedRef = (uint32*)SAMGR_Malloc(sizeof(uint32));

        if (exchange->sharedRef == NULL) {

            MUTEX_GlobalUnlock();

            return EC_NOMEMORY;

        }

        *(exchange->sharedRef) = initRef;

    }

    (*(exchange->sharedRef))++;

    MUTEX_GlobalUnlock();



    return QUEUE_Put(queueId, exchange, 0, DONT_WAIT);

}



static BOOL FreeReference(Exchange *exchange)

{

    if (exchange == NULL) {

        return FALSE;

    }



    BOOL needFree = TRUE;

    /* 1. check the shared reference */

    MUTEX_GlobalLock();

    if (exchange->sharedRef != NULL) {

        if (*(exchange->sharedRef) > 0) {

            (*(exchange->sharedRef))--;

        }



        if (*(exchange->sharedRef) > 0) {

            needFree = FALSE;

        }

    }

    MUTEX_GlobalUnlock();



    if (needFree) {

        SAMGR_Free(exchange->sharedRef);

        exchange->sharedRef = NULL;

    }

    return needFree;

}