/*
 * Copyright (c) Hisilicon Technologies Co., Ltd. 2018-2019. All rights reserved.
 * Description: hidl for tee
 * Author: NameMagic
 * Create: 2018-03-10
 */

#define LOG_TAG "LibteecGlobal@3.0"

#include "LibteecGlobal.h"
#include <cstring>
#include <cerrno>
#include <csignal>
#include <pthread.h>
#include <time.h>

#include <log/log.h>
#include <cutils/list.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <securec.h>

#include "tee_client_api.h"
#include "tc_ns_client.h"
#include "tee_ca_daemon.h"
#include "tee_client_msg.h"

using android::hidl::memory::V1_0::IMemory;
extern "C" int getpidcon(pid_t pid, char **context);
extern "C" void freecon(char *con);

namespace vendor {
namespace huanglong {
namespace hardware {
namespace libteec {
namespace V3_0 {
namespace implementation {
using::android::hardware::Void;

#if defined(__LP64__)
const static char * const DLOPEN_LIBTEEC_PATH = "/vendor/lib64/libteec_vendor.so";
#else
const static char * const DLOPEN_LIBTEEC_PATH = "/vendor/lib/libteec_vendor.so";
#endif

const static int DIR_NAME_LENS = 64;

/* DeathNote */
static list_declare(g_teecHidlProcDataList);
static list_declare(g_teecTidList);
static pthread_mutex_t g_mutexTidList = PTHREAD_MUTEX_INITIALIZER;
static sp<ILibteecGlobalNotify> g_teecNotify;

static int32_t TidMutexLock(void)
{
    int lockRet = pthread_mutex_lock(&g_mutexTidList);
    return lockRet;
}

static void TidMutexUnlock(int lockRet)
{
    int unlockRet;
    if (lockRet != 0) {
        ALOGE("%s: not exe, mutex not in lock state. lock_ret = %d\n", __func__, lockRet);
        return;
    }
    unlockRet = pthread_mutex_unlock(&g_mutexTidList);
    if (unlockRet != 0) {
        ALOGE("%s: exe mutexUnlock error, ret = %d\n", __func__, unlockRet);
    }
}

static DaemonProcdata *GetProcdataByPid(int pid)
{
    /* found server procdata */
    DaemonProcdata *procDataInList = nullptr;
    struct listnode *ptr = nullptr;

    /* Paramters right, start execution */
    if (!list_empty(&g_teecHidlProcDataList)) {
        list_for_each(ptr, &g_teecHidlProcDataList) {
            DaemonProcdata *tmp = node_to_item(ptr, DaemonProcdata, procdataHead);
            if (tmp->callingPid == pid) {
                procDataInList = tmp;
                break;
            }
        }
    }
    return procDataInList;
}

static bool CheckProcDataFdFull(DaemonProcdata *procData)
{
    int i;
    DaemonProcdata *tmpProcData = procData;
    for (i = 0; i < MAX_CXTCNT_ONECA; i++) {
        if (tmpProcData->cxtFd[i] == -1) {
            return false;
        }
    }
    return true;
}

static bool CheckProcDataFdEmpty(DaemonProcdata *procData)
{
    int i;
    for (i = 0; i < MAX_CXTCNT_ONECA; i++) {
        if (procData->cxtFd[i] != -1) {
            return false;
        }
    }
    return true;
}

static TEEC_Result SetContextToProcData(DaemonProcdata *outProcData, TEEC_ContextHidl *outContext)
{
    int i;
    for (i = 0; i < MAX_CXTCNT_ONECA; i++) {
        if (outProcData->cxtFd[i] == -1) {
            outProcData->cxtFd[i] = outContext->fd;
            return TEEC_SUCCESS;
        }
    }
    ALOGE("%s: the cnt of contexts in outProcData is already %d, please finalize some of them\n", __func__, i);
    return TEEC_FAIL;
}

static void RemoveContextFromProcData(DaemonProcdata *outProcData, int32_t outContextFd)
{
    int i;
    for (i = 0; i < MAX_CXTCNT_ONECA; i++) {
        if (outContextFd == outProcData->cxtFd[i]) {
            outProcData->cxtFd[i] = -1;
            return;
        }
    }
    ALOGE("%s: can not find context in outProcdata\n", __func__);
}

/* just mkdir sec_storage_data, mount sec_storage partition in init.chip.rc */
static int MakeSecStorageDir(const char *storageDir, int strSize)
{
    struct stat statBuf;
    int ret;

    if (strSize < 0) {
        return TEE_HIDL_FAILURE;
    }

    /* mkdir for sec_storage_data partition */
    if (stat(storageDir, &statBuf)) {
        ALOGE("stat fail, erron=%d\n", errno);

        if (errno == ENOENT) { /* folder not exist */
            ALOGE("stat folder not exist\n");
            ret = mkdir(storageDir, S_IRUSR | S_IWUSR | S_IXUSR);
            if (ret == -1) {
                ALOGE("make dir fail, err %d\n", errno);
                return TEE_HIDL_FAILURE;
            }

            ret = chown(storageDir, AID_SYSTEM, AID_SYSTEM);
            if (ret < 0) {
                ALOGE("chown error");
            }
        } else {
            ALOGE("stat fail else\n");

            if (S_ISDIR(statBuf.st_mode)) {
                ALOGE("ROOT DATA DIR is exist, but not a dir\n");
                /* shell we rm it and mkdir? */
                return TEE_HIDL_FAILURE;
            }
        }
    }

    return TEE_HIDL_SUCCESS;
}

/* symlink user0 when teecd init */
static void SymlinkUser0(const char *oldPath, const char *newPath)
{
    int ret;
    int retChMod;
    int retChOwn;

    ret = symlink(oldPath, newPath);
    if (ret < 0) {
        ALOGE("symlink user0 erro, errno=%d\n", errno);
        return;
    }
    retChMod = chmod(newPath, S_IRUSR | S_IWUSR | S_IXUSR);
    retChOwn = chown(newPath, AID_SYSTEM, AID_SYSTEM);
    int tmpCheckStatus = ((retChMod < 0) || (retChOwn < 0));
    if (tmpCheckStatus) {
        ALOGE("chmod error %d, or chown error %d", retChMod, retChOwn);
    }
    return;
}

/* return 0 when open dir success, others failure */
static int CheckStatAndOpenDir(const char *name)
{
    struct stat st;
    /* is it a file or directory? */
    if (lstat(name, &st) < 0) {
        ALOGE("lstat %s failed, errno is %x\n", name, errno);
        return TEE_HIDL_FAILURE;
    }

    /* a file, so unlink it */
    if (S_ISDIR(st.st_mode) != 1) {
        if (unlink(name) != 0) {
            ALOGE("unlink failed, errno is %d\n", errno);
            return TEE_HIDL_FAILURE;
        }
        return TEE_HIDL_FAILURE;
    }

    return TEE_HIDL_SUCCESS;
}

static int ClearOpenStat(const char *name, DIR *dir)
{
    /* close directory handle */
    if (closedir(dir) < 0) {
        ALOGE("closedir %s failed, errno is %d\n", name, errno);
        return TEE_HIDL_FAILURE;
    }
    /* delete target directory */
    if (rmdir(name) < 0) { /* no perto handle other dirs */
        ALOGE("rmdir %s failed, errno is %d\n", name, errno);
        return TEE_HIDL_FAILURE;
    }
    return TEE_HIDL_SUCCESS;
}

/* return -1 on failure, with errno set to the first error */
static int UnlinkRecursive(const char *name)
{
    DIR *dir = nullptr;
    struct dirent *de = nullptr;
    int fail = 0;
    char dn[PATH_MAX] = {0};
    errno_t rc = EOK;
    int32_t ret;
    int32_t tmpCheckStatus;

    ret = CheckStatAndOpenDir(name);
    if (ret != TEE_HIDL_SUCCESS) {
        return ret;
    }
    /* a directory, so open handle */
    dir = opendir(name); /* teecd has no permission to handle other directorys */
    if (dir == nullptr) {
        ALOGE("dir %s open failed\n", name);
        return TEE_HIDL_FAILURE;
    }
    /* recurse over components */
    errno = 0;

    de = readdir(dir);
    while (de != nullptr) {
        tmpCheckStatus = ((!strncmp(de->d_name, "..", sizeof(".."))) || (!strncmp(de->d_name, ".", sizeof("."))));
        if (tmpCheckStatus) {
            de = readdir(dir);
            continue;
        }

        rc = snprintf_s(dn, sizeof(dn), sizeof(dn) - 1, "%s/%s", name, de->d_name);
        if (rc == -1) {
            ALOGE("snprintf_s failed %d\n", rc);
            fail = 1;
            break;
        }

        if (UnlinkRecursive(dn) < 0) { /* no per to handle other dirs */
            ALOGE("loop UnlinkRecursive() failed, there are read-only file\n");
            fail = 1;
            break;
        }

        errno = 0;
        de = readdir(dir);
    }

    /* in case readdir or UnlinkRecursive failed */
    tmpCheckStatus = (fail || errno < 0);
    if (tmpCheckStatus) {
        int save = errno;
        closedir(dir);
        errno = save;
        ALOGE("fail is %d, errno is %d\n", fail, errno);
        return TEE_HIDL_FAILURE;
    }

    return ClearOpenStat(name, dir);
}

static void SigUsr1Handler(int sign)
{
    sign = 0;
    return;
}

static void RemoveTidFromList(TidData *tidData)
{
    int retMutexLock = TidMutexLock();
    if (retMutexLock)
        ALOGE("tid mutex lock failed\n");

    list_remove(&tidData->tidHead);
    TidMutexUnlock(retMutexLock);
    free(tidData);
    return;
}

static int AddTidData(TidData **tidData, int pid)
{
    int ret = TEE_HIDL_SUCCESS;
    int mutexRet;

    *tidData = reinterpret_cast<TidData *>(malloc(sizeof(TidData)));
    if (*tidData == nullptr) {
        ALOGE("%s: tid_data malloc failed\n", __func__);
        return TEE_HIDL_FAILURE;
    }
    (*tidData)->tid = syscall(SYS_gettid);
    (*tidData)->callingPid = pid;
    list_init(&(*tidData)->tidHead);

    mutexRet = TidMutexLock();
    if (mutexRet) {
        ALOGE("tid mutex lock failed\n");
        free(*tidData);
        *tidData = nullptr;
        return TEE_HIDL_FAILURE;
    }
    list_add_tail(&g_teecTidList, &(*tidData)->tidHead);
    TidMutexUnlock(mutexRet);
    ALOGD("%s: tid %d is sending command to TEE\n", __func__, (*tidData)->tid);
    return ret;
}

static void SendSigToTzdriver(int pid)
{
    int ret;
    int mutexRet;
    struct listnode *ptr = nullptr;

    signal(SIGUSR1, SigUsr1Handler);
    ALOGD("%s: ignore signal SIGUSR1!\n", __func__);

    mutexRet = TidMutexLock();
    if (mutexRet) {
        ALOGE("tid mutex lock failed\n");
        return;
    }
    if (!list_empty(&g_teecTidList)) {
        list_for_each(ptr, &g_teecTidList) {
            TidData *tmp = node_to_item(ptr, TidData, tidHead);
            if (tmp->callingPid == pid) {
                ret = tgkill(getpid(), tmp->tid, SIGUSR1);
                ALOGD("%s: send signal SIGUSR1 to tid: %d! ret = %d\n", __func__, tmp->tid, ret);
            }
        }
    }
    TidMutexUnlock(mutexRet);
    return;
}

static int MakeDirAndLinkUser(int userid, uint32_t userStatus, bool status)
{
    int ret;
    char username[DIR_NAME_LENS] = {0};

    /* create user sec storage dir */
    ret = MakeSecStorageDir(reinterpret_cast<const char *>(SEC_STORAGE_DATA_USERS), strlen(SEC_STORAGE_DATA_USERS));
    if (ret < 0) {
        ALOGE("mkdir fail ,ret=%d\n", ret);
        return ret;
    }
    /* symlink, no matter if error */
    SymlinkUser0(SEC_STORAGE_DATA_DIR, SEC_STORAGE_DATA_USER_0);
    ret = snprintf_s(username, sizeof(username), sizeof(username) - 1,
                     "%s%d", SEC_STORAGE_DATA_USERS, userid);
    if (ret < 0) {
        ALOGE("snprintf ret error\n");
        return ret;
    }
    if (!status) {
        ALOGE("userid %u is not in the status %x range\n", userStatus, userid);
        return TEE_HIDL_FAILURE;
    }
    ret = MakeSecStorageDir(username, sizeof(username));
    if (ret < 0) {
        ALOGE("mkdir fail ,ret=%d\n", ret);
        return ret;
    }
    return TEE_HIDL_SUCCESS;
}

static int UnlinkUser(int userid, uint32_t userStatus, bool status)
{
    int ret;
    char username[DIR_NAME_LENS] = {0};

    /* delete user */
    if (!status) {
        ALOGE("userid %u is not in the status %x range\n", userStatus, userid);
        return TEE_HIDL_FAILURE;
    }
    ret = snprintf_s(username, sizeof(username), sizeof(username) - 1,
                     "%s%d", SEC_STORAGE_DATA_USERS, userid);
    if (ret < 0) {
        ALOGE("snprintf2 ret error\n");
        return ret;
    }
    ret = UnlinkRecursive(username);
    if (ret < 0) {
        ALOGE("rmdir fail ,ret=%d\n", ret);
        return ret;
    }
    return TEE_HIDL_SUCCESS;
}

static void CopyToShareMemory(TEEC_SharedMemory *shareMemBuf, uint8_t *data,
                              uint32_t shmInfoOffset, uint32_t *shmOffset)
{
    shareMemBuf->is_allocated = *reinterpret_cast<bool *>(data + shmInfoOffset);
    shmInfoOffset += sizeof(bool);

    shareMemBuf->flags = *reinterpret_cast<uint32_t *>(data + shmInfoOffset);
    shmInfoOffset += sizeof(uint32_t);

    shareMemBuf->ops_cnt = *reinterpret_cast<uint32_t *>(data + shmInfoOffset);
    shmInfoOffset += sizeof(uint32_t);

    *shmOffset = *reinterpret_cast<uint32_t *>(data + shmInfoOffset);
    shmInfoOffset += sizeof(uint32_t);

    shareMemBuf->size = *reinterpret_cast<uint32_t *>(data + shmInfoOffset);
    shmInfoOffset += sizeof(uint32_t);
}

LibteecGlobal::~LibteecGlobal()
{
    if (mHandle != nullptr) {
        dlclose(mHandle);
        mHandle = nullptr;
    }
    ALOGD("Deinit LibteecGlobal!\n");
}

bool LibteecGlobal::IsValidContextWithoutLock(const TEEC_Context *context, int pid)
{
    int i;
    int tmpCheckStatus;
    DaemonProcdata *outProcData = GetProcdataByPid(pid);

    tmpCheckStatus = (outProcData == nullptr || context == nullptr);
    if (tmpCheckStatus) {
        return false;
    }

    if (context->fd < 0) {
        return false;
    }

    for (i = 0; i < MAX_CXTCNT_ONECA; i++) {
        if (context->fd == outProcData->cxtFd[i]) {
            return true;
        }
    }
    return false;
}

bool LibteecGlobal::IsValidContext(const TEEC_Context *context, int pid)
{
    Mutex::Autolock _l(mProcDataLock);
    return IsValidContextWithoutLock(context, pid);
}

Return<int32_t> LibteecGlobal::CheckAndOpenHandle()
{
    Mutex::Autolock _l(mHandleLock);
    if (mHandle == nullptr) {
        mHandle = dlopen(DLOPEN_LIBTEEC_PATH, RTLD_LAZY);
        if (mHandle == nullptr) {
            return TEE_HIDL_FAILURE;
        }
        initializeContextProxy =
            reinterpret_cast<InitializeContextFunc>(dlsym(mHandle, "TEEC_InitializeContextWithType"));
        openSessionProxy = reinterpret_cast<OpenSessionFunc>(dlsym(mHandle, "TEEC_OpenSessionHidl"));
        invokeCommandProxy = reinterpret_cast<InvokeCommandFunc>(dlsym(mHandle, "TEEC_InvokeCommandHidl"));
        closeSessionProxy = reinterpret_cast<CloseSessionFunc>(dlsym(mHandle, "TEEC_CloseSessionHidl"));
        registerSharedMemoryProxy =
            reinterpret_cast<RegisterSharedMemoryFunc>(dlsym(mHandle, "TEEC_RegisterSharedMemoryHidl"));
        allocateSharedMemoryProxy =
            reinterpret_cast<AllocateSharedMemoryFunc>(dlsym(mHandle, "TEEC_AllocateSharedMemoryHidl"));
        releaseSharedMemoryProxy =
            reinterpret_cast<ReleaseSharedMemoryFunc>(dlsym(mHandle, "TEEC_ReleaseSharedMemoryHidl"));
        extTuiSendEventProxy = reinterpret_cast<ExtTuiSendEventFunc>(dlsym(mHandle, "TEEC_EXT_TuiSendEvent"));
        getTEEVersionProxy = reinterpret_cast<GetTEEVersionFunc>(dlsym(mHandle, "TEEC_GetTEEVersionHidl"));
        extSendSysHashXmlProxy = reinterpret_cast<ExtSendSysHashXmlFunc>(dlsym(mHandle, "SendSysHashXml"));
        getBnContextProxy = reinterpret_cast<GetBnContextFunc>(dlsym(mHandle, "GetBnContext"));
        putBnContextProxy = reinterpret_cast<PutBnContextFunc>(dlsym(mHandle, "PutBnContext"));
        findAndRemoveBnContextProxy =
            reinterpret_cast<FindAndRemoveBnContextFunc>(dlsym(mHandle, "FindAndRemoveBnContext"));
        getBnSessionProxy = reinterpret_cast<GetBnSessionFunc>(dlsym(mHandle, "GetBnSession"));
        putBnSessionProxy = reinterpret_cast<PutBnSessionFunc>(dlsym(mHandle, "PutBnSession"));
        findAndRemoveBnSessionProxy =
            reinterpret_cast<FindAndRemoveBnSessionFunc>(dlsym(mHandle, "FindAndRemoveSession"));
        getBnShmByOffsetProxy = reinterpret_cast<GetBnShmByOffsetFunc>(dlsym(mHandle, "GetBnShmByOffset"));
        putBnShmProxy = reinterpret_cast<PutBnShmFunc>(dlsym(mHandle, "PutBnShrMem"));
        sendSecfileProxy = reinterpret_cast<SendSecfileFunc>(dlsym(mHandle, "TEEC_SendSecfileHidl"));
    }
    return TEE_HIDL_SUCCESS;
}

/**************************************************************************/
/*                          function implements                           */
/**************************************************************************/
Return<void> LibteecGlobal::initializeContext(const hidl_string &name,
    const hidl_vec<uint8_t> &authInfo, initializeContext_cb hidlCallBackPtr)
{
    int32_t ret = (int32_t)TEEC_FAIL;
    hidl_vec<uint8_t> contextOutPtr;
    TEEC_ContextHidl *outContext = nullptr;

    if (hidlCallBackPtr == nullptr) {
        ALOGE("%s: hidlCallBackPtr is nullptr\n", __func__);
        return Void();
    }

    (void)CheckAndOpenHandle();
    if (putBnContextProxy == nullptr) {
        ALOGE("no putBnContext in this handle!\n");
        hidlCallBackPtr(ret, contextOutPtr);
        return Void();
    }

    if ((authInfo.data() == nullptr) || (authInfo.size() != sizeof(CaAuthInfo))) {
        ALOGE("%s: authInfo is nullptr or size is 0.\n", __func__);
        hidlCallBackPtr(ret, contextOutPtr);
        return Void();
    }

    CaAuthInfo *caAuth = reinterpret_cast<CaAuthInfo *>(malloc(sizeof(CaAuthInfo)));
    if (caAuth == nullptr) {
        ALOGE("%s: malloc ca auth failed\n", __func__);
        hidlCallBackPtr(ret, contextOutPtr);
        return Void();
    }
    (void)memcpy_s(caAuth, sizeof(CaAuthInfo), authInfo.data(), sizeof(CaAuthInfo));

    ALOGD("%s: getCallingPid=%d", __func__, caAuth->pid);

    Mutex::Autolock _l(mProcDataLock);
    DaemonProcdata *outProcData = CallGetProcDataPtr(caAuth->pid);
    if (outProcData == nullptr) {
        goto INITEND;
    }

    ret = CallInitializeContextProxy(name, caAuth, &outContext);
    if (ret == (int32_t)TEEC_SUCCESS) {
        if (SetContextToProcData(outProcData, outContext)) {
            ret = TEEC_FAIL;
            putBnContextProxy(outContext); /* pair with ops_cnt++ when add to list */
            putBnContextProxy(outContext); /* pair with initial value 1 */
            goto INITEND;
        }
        contextOutPtr.setToExternal(reinterpret_cast<uint8_t *>(outContext), sizeof(TEEC_ContextHidl));
        putBnContextProxy(outContext); /* pair with ops_cnt++ when add to list */
    }

INITEND:
    hidlCallBackPtr(ret, contextOutPtr);
    free(caAuth);
    return Void();
}

Return<DaemonProcdata *> LibteecGlobal::CallGetProcDataPtr(int pid)
{
    DaemonProcdata *outProcData = GetProcdataByPid(pid);
    if (outProcData != nullptr) {
        if (CheckProcDataFdFull(outProcData)) {
            ALOGE("%s: pid[%d] can not get more context, please finalize some of them\n", __func__, pid);
            return nullptr;
        }
    } else {
        DaemonProcdata *procData = reinterpret_cast<DaemonProcdata *>(malloc(sizeof(DaemonProcdata)));
        if (procData == nullptr) {
            ALOGE("%s: procdata malloc failed\n", __func__);
            return nullptr;
        }
        (void)memset_s(procData, sizeof(DaemonProcdata), 0, sizeof(DaemonProcdata));

        for (int i = 0; i < MAX_CXTCNT_ONECA; i++) {
            procData->cxtFd[i] = -1;
        }
        procData->callingPid = pid;
        list_init(&(procData->procdataHead));
        list_add_tail(&g_teecHidlProcDataList, &procData->procdataHead);

        outProcData = procData;
    }
    return outProcData;
}

Return<int32_t> LibteecGlobal::CallInitializeContextProxy(const hidl_string &name,
    CaAuthInfo *authInfo, TEEC_ContextHidl **outHidlContext)
{
    int ret;
    const int32_t type = TEECD_CONNECT;
    TEEC_ContextHidl *outContext = nullptr;

    if (outHidlContext == nullptr) {
        ALOGE("intialize context proxy: out hidl context is nullptr\n");
        return TEEC_FAIL;
    }

    if (initializeContextProxy == nullptr) {
        ALOGE("no initializeContext in this handle!\n");
        return TEEC_FAIL;
    }

    outContext = reinterpret_cast<TEEC_ContextHidl *>(malloc(sizeof(TEEC_ContextHidl)));
    if (outContext == nullptr) {
        ALOGE("%s: outContext malloc failed\n", __func__);
        return TEEC_FAIL;
    }
    (void)memset_s(outContext, sizeof(TEEC_ContextHidl), 0x00, sizeof(TEEC_ContextHidl));

    ret = initializeContextProxy(reinterpret_cast<const char *>(name.c_str()),
        reinterpret_cast<TEEC_ContextHidl *>(outContext), type, true, authInfo);
    if (ret) {
        ALOGE("%s: TEEC_InitializeContextWithType failed(0x%x)\n", __func__, (TEEC_Result)ret);
        free(outContext);
        outContext = nullptr;
    }
    *outHidlContext = outContext;
    return ret;
}

Return<void> LibteecGlobal::finalizeContext(int32_t pid, const hidl_vec<uint8_t> &halCxtPtr)
{
    ALOGD("%s: getCallingPid=%d", __func__, pid);
    int tmpCheckStatus = ((halCxtPtr.data() == nullptr) ||
                          (halCxtPtr.size() != sizeof(TEEC_Context)));
    if (tmpCheckStatus) {
        ALOGE("%s: invalid context!\n", __func__);
        return Void();
    }

    Mutex::Autolock _l(mProcDataLock);
    if (!IsValidContextWithoutLock(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)) {
        ALOGE("context and procdata have been released by service_died!\n");
        return Void();
    }
    int32_t tempContextFd = CallFinalizeContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (tempContextFd < 0) {
        ALOGE("%s: CallFinalizeContextProxy failed!\n", __func__);
        return Void();
    }

    DaemonProcdata *outProcData = GetProcdataByPid(pid);
    if (outProcData == nullptr) {
        ALOGE("%s: outProcdata is nullptr\n", __func__);
        return Void();
    }
    RemoveContextFromProcData(outProcData, tempContextFd);
    if (CheckProcDataFdEmpty(outProcData)) {
        list_remove(&outProcData->procdataHead);
        free(outProcData);
        outProcData = nullptr;
    } else {
        ALOGD("%s: still have context not finalize in pid[%d]\n", __func__, pid);
    }

    return Void();
}

Return<int32_t> LibteecGlobal::CallFinalizeContextProxy(const TEEC_Context *contextPtr)
{
    TEEC_ContextHidl *outContext = nullptr;
    int32_t contextFd;

    if ((findAndRemoveBnContextProxy == nullptr) ||
        (putBnContextProxy == nullptr)) {
        ALOGE("call finalizeContext proxy:missing proxy in this handle!\n");
        return TEE_HIDL_FAILURE;
    }

    outContext = findAndRemoveBnContextProxy(contextPtr);
    if (outContext == nullptr) {
        ALOGE("%s: no context found in hidl service!\n", __func__);
        return TEE_HIDL_FAILURE;
    }

    contextFd = outContext->fd;
    putBnContextProxy(outContext); /* pair with initialize context */
    return contextFd;
}

Return<void> LibteecGlobal::openSession(int32_t pid, const hidl_vec<uint8_t> &halCxtPtr,
    const android::hardware::hidl_handle &handle, const hidl_string &taPath,
    const hidl_vec<uint8_t> &halUuidPtr, uint32_t halConnMth, const hidl_vec<uint8_t> &haConnData,
    const hidl_vec<uint8_t> &halOptPtr, const android::hardware::hidl_memory &opMem, openSession_cb hidlCallBackPtr)
{
    int32_t ret = (int32_t)TEEC_FAIL;
    hidl_vec<uint8_t> contextOutPtr;
    hidl_vec<uint8_t> sessionOutPtr;
    hidl_vec<uint8_t> optOutPtr;
    int32_t originRet = TEEC_ORIGIN_API;

    if (hidlCallBackPtr == nullptr) {
        ALOGE("%s: hidlCallBackPtr is nullptr\n", __func__);
        return Void();
    }

    (void)CheckAndOpenHandle();
    if (putBnSessionProxy == nullptr || putBnContextProxy == nullptr) {
        ALOGE("open session: missing proxy in this handle!\n");
        hidlCallBackPtr(ret, contextOutPtr, sessionOutPtr, optOutPtr, originRet);
        return Void();
    }

    InOutPara paraInOut; /* just for transfer params */
    paraInOut.cmdId = (int32_t)halConnMth;
    paraInOut.pid = pid;
    ALOGD("%s: getCallingPid=%d ", __func__, paraInOut.pid);

    TEEC_Session *outSession = nullptr;
    TEEC_ContextHidl *outContext = nullptr;
    TEEC_Session retSession;
    (void)memset_s((void *)(&retSession), sizeof(TEEC_Session), 0, sizeof(TEEC_Session));
    int getBnRet = CallGetBnContextProxy(halCxtPtr, paraInOut.pid, &outSession, &outContext);
    if (getBnRet) {
        ret = getBnRet;
        ALOGE("%s: callGetBnProxy failed! ret is %x.\n", __func__, getBnRet);
        hidlCallBackPtr(ret, contextOutPtr, sessionOutPtr, optOutPtr, originRet);
        return Void();
    }

    TaFileInfo taFile = { .taPath = nullptr, .taFp = nullptr };
    taFile.taPath = reinterpret_cast<const uint8_t *>(taPath.c_str());
    native_handle_t *tempHandle = nullptr;
    taFile.taFp = GetFpFromHandle(handle, tempHandle);

    TEEC_Operation operation;
    (void)memset_s(&operation, sizeof(TEEC_Operation), 0, sizeof(TEEC_Operation));

    paraInOut.operationPtr = &operation;
    paraInOut.outContextPtr = outContext;
    paraInOut.outSessionPtr = outSession;

    if (SubOpenSession(&taFile, halOptPtr, opMem, halUuidPtr, haConnData, &paraInOut)) {
        free(outSession);
        goto OPENSESSIONEND;
    }
    retSession.session_id = outSession->session_id;
    retSession.service_id = outSession->service_id;
    retSession.ops_cnt = outSession->ops_cnt;
    contextOutPtr.setToExternal(reinterpret_cast<uint8_t *>(outContext), sizeof(TEEC_ContextHidl));
    sessionOutPtr.setToExternal(reinterpret_cast<uint8_t *>(&retSession), sizeof(TEEC_Session));
    optOutPtr.setToExternal(reinterpret_cast<uint8_t *>(&operation), sizeof(TEEC_Operation));
    putBnSessionProxy(outSession); /* pair with ops_cnt++ when add to list */

OPENSESSIONEND:
    ret = paraInOut.ret;
    originRet = paraInOut.originRet;
    putBnContextProxy(outContext);
    if (taFile.taFp != nullptr) {
        fclose(taFile.taFp);
    }
    native_handle_delete(tempHandle);
    hidlCallBackPtr(ret, contextOutPtr, sessionOutPtr, optOutPtr, originRet);
    return Void();
}

Return<int32_t> LibteecGlobal::CallGetBnContextProxy(const hidl_vec<uint8_t> &halCxtPtr,
    int pid, TEEC_Session **outHidlSession, TEEC_ContextHidl **outHidlContext)
{
    TEEC_ContextHidl *outContext = nullptr;
    int tmpCheckStatus = ((halCxtPtr.data() == nullptr) || (halCxtPtr.size() != sizeof(TEEC_Context)) ||
                          (!IsValidContext(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)));
    if (tmpCheckStatus) {
        ALOGE("%s: invalid context!\n", __func__);
        return TEEC_FAIL;
    }
    if (getBnContextProxy == nullptr || putBnContextProxy == nullptr) {
        ALOGE("call get bn context proxy: missing proxy in this handle!\n");
        return TEEC_FAIL;
    }
    outContext = getBnContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (outContext == nullptr) {
        ALOGE("%s: no context found in hidl service.\n", __func__);
        return TEEC_ERROR_BAD_PARAMETERS;
    }

    TEEC_Session *outSession = reinterpret_cast<TEEC_Session *>(malloc(sizeof(TEEC_Session)));
    if (outSession == nullptr) {
        ALOGE("%s: outSession malloc failed!\n", __func__);
        putBnContextProxy(outContext);
        return TEEC_FAIL;
    }
    (void)memset_s(outSession, sizeof(TEEC_Session), 0x00, sizeof(TEEC_Session));

    *outHidlSession = outSession;
    *outHidlContext = outContext;
    return TEEC_SUCCESS;
}

Return<int32_t> LibteecGlobal::SubOpenSession(const TaFileInfo *taFile,
    const hidl_vec<uint8_t> &halOptPtr, const android::hardware::hidl_memory &opMem,
    const hidl_vec<uint8_t> &halUuidPtr, const hidl_vec<uint8_t> &haConnData, InOutPara *paraInOut)
{
    int tempRet;
    sp<IMemory> memory;
    TEEC_ContextHidl *outContext = paraInOut->outContextPtr;
    TEEC_Session *outSession = paraInOut->outSessionPtr;
    paraInOut->ret = TEEC_FAIL;
    paraInOut->originRet = TEEC_ORIGIN_API;

    TEEC_Operation *operation = paraInOut->operationPtr;
    operation->started = 1;
    TEEC_SharedMemory shm[PARAM_NUM];
    TEEC_SharedMemoryHidl *shmHidl[PARAM_NUM];

    (void)memset_s(&shm, sizeof(shm), 0, sizeof(shm));
    (void)memset_s(&shmHidl, sizeof(shmHidl), 0x00, sizeof(shmHidl));

    int tmpCheckStatus = ((halOptPtr.data() != nullptr) && (halOptPtr.size() == sizeof(TEEC_Operation)));
    int tmpCheckStatus2 = ((opMem.size() != 0) && (opMem.handle() != nullptr));

    if (tmpCheckStatus) {
        tempRet = GetOperationFromHidlVec(halOptPtr, operation);
        if (tempRet != TEE_HIDL_SUCCESS) {
            ALOGE("get oper from hidl vec failed.\n");
            return TEE_HIDL_FAILURE;
        }
        if (tmpCheckStatus2) {
            memory = mapMemory(opMem);
            if (memory == nullptr) {
                ALOGD("%s: memory is nullptr.\n", __func__);
                return TEE_HIDL_FAILURE;
            }
            uint8_t *data = static_cast<uint8_t *>(static_cast<void *>(memory->getPointer()));
            memory->update();
            size_t memSize = (size_t)memory->getSize();

            TEEC_Result ret = DecodeHidlMemory(outContext, operation,
                shm, shmHidl, PARAM_NUM, data, memSize);
            if (ret) {
                paraInOut->ret = ret;
                ALOGE("open session: decode hidl memory failed\n");
                PutAllocShrMem(shmHidl, PARAM_NUM);
                return TEE_HIDL_FAILURE;
            }
        } else {
            ALOGD("%s: opMem is nullptr or size is 0\n", __func__);
        }
    }

    tempRet = CallOpenSessionProxy(halUuidPtr, taFile, outContext, outSession, paraInOut, haConnData);
    PutAllocShrMem(shmHidl, PARAM_NUM);
    if (tempRet != TEE_HIDL_SUCCESS) {
        ALOGE("%s: callInvokeCommandProxy failed, ret is %x.\n", __func__, tempRet);
        return TEE_HIDL_FAILURE;
    }

    int tmpCheckStatus3 = (memory != nullptr);
    tmpCheckStatus = (tmpCheckStatus && tmpCheckStatus2 && tmpCheckStatus3);
    if (tmpCheckStatus) {
        memory->update();
        memory->commit();
    } else {
        ALOGD("%s: memory maybe nullptr, status is %x...\n", __func__, tmpCheckStatus3);
        ALOGD("%s: opMem maybe nullptr or size maybe 0, status is %x...\n", __func__, tmpCheckStatus2);
    }

    return 0;
}

Return<int32_t> LibteecGlobal::CallOpenSessionProxy(const hidl_vec<uint8_t> &halUuidPtr,
    const TaFileInfo *taFile, TEEC_ContextHidl *outContext, TEEC_Session *outSession,
    InOutPara *paraInOut, const hidl_vec<uint8_t> &haConnData)
{
    int ret;
    int32_t originRet = 0;
    TidData *tidData = nullptr;
    uint32_t halConnMth = (uint32_t)paraInOut->cmdId;
    int pid = paraInOut->pid;
    TEEC_Operation *operation = (paraInOut->operationPtr);

    if (openSessionProxy == nullptr) {
        ALOGE("no openSession in this handle!\n");
        return TEE_HIDL_FAILURE;
    }

    ret = AddTidData(&tidData, pid);
    if (ret) {
        ALOGE("%s: AddTidData failed\n", __func__);
        return TEE_HIDL_FAILURE;
    }

    ret = openSessionProxy(pid, taFile, reinterpret_cast<TEEC_ContextHidl *>(outContext),
        reinterpret_cast<TEEC_Session *>(outSession), reinterpret_cast<const TEEC_UUID *>(halUuidPtr.data()),
        halConnMth, reinterpret_cast<const void *>(haConnData.data()), reinterpret_cast<TEEC_Operation *>(operation),
        reinterpret_cast<uint32_t *>(&originRet));
    ALOGD("%s: tid %d return from TEE.\n", __func__, tidData->tid);
    RemoveTidFromList(tidData);
    tidData = nullptr;

    paraInOut->ret = ret; /* return code from teeos or tzdriver, such as TEEC_FAIL */
    paraInOut->originRet = originRet; /* return origin code from teeos or tzdriver, such as TEE_ORIGIN_TEE */
    if (ret != TEEC_SUCCESS) {
        ALOGD("open session proxy return failed from TEE: 0x%x \n", ret);
        return TEE_HIDL_FAILURE;
    }
    return TEE_HIDL_SUCCESS;
}

Return<void> LibteecGlobal::closeSession(int32_t pid, const hidl_vec<uint8_t> &halCxtPtr,
                                         const hidl_vec<uint8_t> &halSessPtr)
{
    ALOGD("%s: get Calling Pid=%d", __func__, pid);
    int tmpCheckStatus = ((halCxtPtr.data() == nullptr) || (halCxtPtr.size() != sizeof(TEEC_Context)) ||
                          (!IsValidContext(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)));
    if (tmpCheckStatus) {
        ALOGE("%s: invalid context!\n", __func__);
        return Void();
    }

    (void)CheckAndOpenHandle();
    if (getBnContextProxy == nullptr ||
        putBnContextProxy == nullptr ||
        putBnSessionProxy == nullptr ||
        findAndRemoveBnSessionProxy == nullptr) {
        ALOGE("close session: missing proxy in this handle!\n");
        return Void();
    }

    TEEC_ContextHidl *outContext = nullptr;
    outContext = getBnContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (outContext == nullptr) {
        ALOGE("%s: no context found in hidl service!\n", __func__);
        return Void();
    }

    TEEC_Session *outSession = nullptr;
    tmpCheckStatus = ((halSessPtr.data() != nullptr) &&
                      (halSessPtr.size() == sizeof(TEEC_Session)));
    if (!tmpCheckStatus) {
        ALOGE("receive session struct failed!\n");
        putBnContextProxy(outContext);
        return Void();
    }

    const TEEC_Session *inSession =
        reinterpret_cast<const TEEC_Session *>(halSessPtr.data());
    outSession = findAndRemoveBnSessionProxy(inSession, outContext);
    if (outSession == nullptr) {
        ALOGE("%s: no session found in hidl service!\n", __func__);
        putBnContextProxy(outContext);
        return Void();
    }

    CallCloseSessionProxy(outSession, outContext, pid);
    putBnSessionProxy(outSession); /* pair with open session */
    putBnContextProxy(outContext);

    return Void();
}

Return<void> LibteecGlobal::CallCloseSessionProxy(TEEC_Session *outSession,
    TEEC_ContextHidl *outContext, int pid)
{
    TidData *tidData = nullptr;

    if (closeSessionProxy == nullptr) {
        ALOGE("no closeSession in this handle!\n");
        return Void();
    }

    int ret = AddTidData(&tidData, pid);
    if (ret) {
        ALOGE("%s: add_tid_data failed\n", __func__);
        return Void();
    }

    closeSessionProxy(reinterpret_cast<TEEC_Session *>(outSession),
        reinterpret_cast<TEEC_ContextHidl *>(outContext));
    ALOGD("%s: tid %d return from TEE\n", __func__, tidData->tid);
    RemoveTidFromList(tidData);
    tidData = nullptr;

    return Void();
}

Return<void> LibteecGlobal::invokeCommandHidl(int32_t pid, const hidl_vec<uint8_t> &halCxtPtr,
    const hidl_vec<uint8_t> &halSessPtr, uint32_t cmdId, const hidl_vec<uint8_t> &halOptPtr,
    const android::hardware::hidl_memory &opMem, invokeCommandHidl_cb hidlCallBackPtr)
{
    int32_t ret = (int32_t)TEEC_FAIL;
    hidl_vec<uint8_t> sessionOutPtr;
    hidl_vec<uint8_t> optOutPtr;
    int32_t originRet = TEEC_ORIGIN_API;
    TEEC_Operation operation;
    TEEC_ContextHidl *outContext = nullptr;
    TEEC_Session *outSession = nullptr;
    InOutPara paraInOut; /* just for transfer params */
    int32_t tempRet;

    if (hidlCallBackPtr == nullptr) {
        ALOGE("%s: hidlCallBackPtr is nullptr\n", __func__);
        return Void();
    }

    (void)CheckAndOpenHandle();
    if (putBnSessionProxy == nullptr || putBnContextProxy == nullptr) {
        ALOGE("invoke command: missing proxy in this handle!\n");
        goto INVOKEEND;
    }

    ALOGD("%s: getCallingPid=%d", __func__, pid);

    (void)memset_s(&operation, sizeof(TEEC_Operation), 0x00, sizeof(TEEC_Operation)); /* clear operation */
    operation.started = 1;

    tempRet = CallGetBnProxy(pid, halCxtPtr, halSessPtr, &outContext, &outSession);
    if (tempRet != 0) {
        ret = tempRet;
        goto INVOKEEND;
    }

    paraInOut.cmdId = (int32_t)cmdId;
    paraInOut.pid = pid;
    paraInOut.operationPtr = &operation;
    paraInOut.outContextPtr = outContext;
    paraInOut.outSessionPtr = outSession;

    tempRet = SubInvokeCommand(halOptPtr, opMem, &paraInOut);
    /* tempRet=0, meas TEEC_SUCCESS */
    if (tempRet == 0) {
        ret = paraInOut.ret;
        originRet = paraInOut.originRet;
        sessionOutPtr.setToExternal(reinterpret_cast<uint8_t *>(outSession), sizeof(TEEC_Session));
        optOutPtr.setToExternal(reinterpret_cast<uint8_t *>(&operation), sizeof(TEEC_Operation));
    } else {
        ALOGE("%s: call SubInvokeCommand return, ret is %x.\n", __func__, tempRet);
    }

    putBnSessionProxy(outSession);
    putBnContextProxy(outContext);

INVOKEEND:
    hidlCallBackPtr(ret, sessionOutPtr, optOutPtr, originRet);
    return Void();
}

Return<int32_t> LibteecGlobal::CallGetBnProxy(int pid, const hidl_vec<uint8_t> &halCxtPtr,
    const hidl_vec<uint8_t> &halSessPtr, TEEC_ContextHidl **outHidlContext, TEEC_Session **outHidlSession)
{
    TEEC_ContextHidl *outContext = nullptr;
    TEEC_Session *outSession = nullptr;

    int tmpCheckStatus = ((halCxtPtr.data() == nullptr) || (halCxtPtr.size() != sizeof(TEEC_Context)) ||
                          (!IsValidContext(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)));
    if (tmpCheckStatus) {
        ALOGE("%s: invalid context!\n", __func__);
        return TEEC_FAIL;
    }
    if (getBnContextProxy == nullptr ||
        putBnContextProxy == nullptr ||
        getBnSessionProxy == nullptr) {
        ALOGE("call get bn proxy: missing proxy in this handle!\n");
        return TEEC_FAIL;
    }

    outContext = getBnContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (outContext == nullptr) {
        ALOGE("%s: no context found in hidl service!\n", __func__);
        return TEEC_ERROR_BAD_PARAMETERS;
    }

    tmpCheckStatus = ((halSessPtr.data() != nullptr) &&
                      (halSessPtr.size() == sizeof(TEEC_Session)));
    if (!tmpCheckStatus) {
        ALOGE("receive session struct failed!\n");
        putBnContextProxy(outContext);
        return TEEC_FAIL;
    }
    outSession = getBnSessionProxy(reinterpret_cast<const TEEC_Session *>(halSessPtr.data()), outContext);
    if (outSession == nullptr) {
        ALOGE("%s: no session found in hidl service!\n", __func__);
        putBnContextProxy(outContext);
        return TEEC_ERROR_BAD_PARAMETERS;
    }

    *outHidlContext = outContext;
    *outHidlSession = outSession;
    return TEEC_SUCCESS;
}

Return<int32_t> LibteecGlobal::SubInvokeCommand(const hidl_vec<uint8_t> &halOptPtr,
    const android::hardware::hidl_memory &opMem, InOutPara *paraInOut)
{
    int tempRet;
    sp<IMemory> memory;
    TEEC_Operation *operation = (paraInOut->operationPtr);
    TEEC_ContextHidl *outContext = paraInOut->outContextPtr;
    TEEC_Session *outSession = paraInOut->outSessionPtr;
    TEEC_SharedMemory shm[PARAM_NUM];
    TEEC_SharedMemoryHidl *shmHidl[PARAM_NUM];

    (void)memset_s(&shm, sizeof(shm), 0x00, sizeof(shm));
    (void)memset_s(&shmHidl, sizeof(shmHidl), 0x00, sizeof(shmHidl));

    int tmpCheckStatus = ((halOptPtr.data() != nullptr) && (halOptPtr.size() == sizeof(TEEC_Operation)));
    int tmpCheckStatus2 = ((opMem.size() != 0) && (opMem.handle() != nullptr));

    if (tmpCheckStatus) {
        tempRet = GetOperationFromHidlVec(halOptPtr, operation);
        if (tempRet != TEE_HIDL_SUCCESS) {
            ALOGE("get oper from hidl vec failed.\n");
            return TEE_HIDL_FAILURE;
        }
        if (tmpCheckStatus2) {
            memory = mapMemory(opMem);
            if (memory == nullptr) {
                ALOGD("%s: memory is nullptr\n", __func__);
                return TEE_HIDL_FAILURE;
            }
            uint8_t *dataPtr = static_cast<uint8_t *>(static_cast<void *>(memory->getPointer()));
            memory->update();
            size_t memSize = (size_t)memory->getSize();

            TEEC_Result ret = DecodeHidlMemory(outContext, operation,
                shm, shmHidl, PARAM_NUM, dataPtr, memSize);
            if (ret) {
                ALOGE("invoke command: decode hidl memory failed\n");
                PutAllocShrMem(shmHidl, PARAM_NUM);
                return TEE_HIDL_FAILURE;
            }
        } else {
            ALOGD("%s: opMem is nullptr or size is 0\n", __func__);
        }
    }

    tempRet = CallInvokeCommandProxy(outContext, outSession, operation, paraInOut);
    PutAllocShrMem(shmHidl, PARAM_NUM);
    if (tempRet != TEE_HIDL_SUCCESS) {
        ALOGE("%s: callInvokeCommandProxy failed, ret is %x.\n", __func__, tempRet);
        return TEE_HIDL_FAILURE;
    }

    int tmpCheckStatus3 = (memory != nullptr);
    tmpCheckStatus = (tmpCheckStatus2 && tmpCheckStatus3 && tmpCheckStatus);
    if (tmpCheckStatus) {
        memory->update();
        memory->commit();
    } else {
        ALOGD("%s: memory maybe nullptr, status is %x.\n", __func__, tmpCheckStatus3);
        ALOGD("%s: opMem maybe nullptr or size maybe 0, status is %x.\n", __func__, tmpCheckStatus2);
    }
    return TEE_HIDL_SUCCESS;
}

Return<int32_t> LibteecGlobal::CallInvokeCommandProxy(TEEC_ContextHidl *outContext,
    TEEC_Session *outSession, TEEC_Operation *operation, InOutPara *paraInOut)
{
    int ret;
    int32_t originRet = 0;
    TidData *tidData = nullptr;

    if (invokeCommandProxy == nullptr) {
        ALOGE("no invoke command in this handle!\n");
        return TEE_HIDL_FAILURE;
    }

    ret = AddTidData(&tidData, paraInOut->pid);
    if (ret) {
        ALOGE("%s: AddTidData failed\n", __func__);
        return TEE_HIDL_FAILURE;
    }

    ret = invokeCommandProxy(reinterpret_cast<TEEC_ContextHidl *>(outContext),
        reinterpret_cast<TEEC_Session *>(outSession), paraInOut->cmdId,
        reinterpret_cast<TEEC_Operation *>(operation), reinterpret_cast<uint32_t *>(&originRet));
    ALOGD("%s: tid %d return from TEE\n", __func__, tidData->tid);
    RemoveTidFromList(tidData);
    tidData = nullptr;

    paraInOut->ret = ret; /* return code from teeos or tzdriver, such as TEEC_FAIL */
    paraInOut->originRet = originRet; /* return origin code from teeos or tzdriver, such as TEE_ORIGIN_TEE */
    return TEE_HIDL_SUCCESS;
}

Return<void> LibteecGlobal::registerSharedMemory(int32_t pid, const hidl_vec<uint8_t> &halCxtPtr,
    const hidl_vec<uint8_t> &halMemPtr, registerSharedMemory_cb hidlCallBackPtr)
{
    int32_t ret = (int32_t)TEEC_FAIL;
    hidl_vec<uint8_t> outShmPtr;

    if (hidlCallBackPtr == nullptr) {
        ALOGE("%s: hidlCallBackPtr is nullptr\n", __func__);
        return Void();
    }

    int tmpCheckStatus = ((halCxtPtr.data() == nullptr) || (halCxtPtr.size() != sizeof(TEEC_Context)) ||
                          (!IsValidContext(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)));
    if (tmpCheckStatus) {
        ALOGE("%s: invalid context!\n", __func__);
        hidlCallBackPtr(ret, outShmPtr);
        return Void();
    }
    (void)CheckAndOpenHandle();

    if (getBnContextProxy == nullptr || putBnContextProxy == nullptr) {
        ALOGE("missing proxy in this handle!\n");
        hidlCallBackPtr(ret, outShmPtr);
        return Void();
    }

    TEEC_ContextHidl *outContext = nullptr;
    outContext = getBnContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (outContext == nullptr) {
        ALOGE("%s: no context found in hidl service!\n", __func__);
        ret = TEEC_ERROR_BAD_PARAMETERS;
        hidlCallBackPtr(ret, outShmPtr);
        return Void();
    }

    TEEC_SharedMemoryHidl outShm;
    (void)memset_s((void *)(&outShm), sizeof(TEEC_SharedMemoryHidl), 0, sizeof(TEEC_SharedMemoryHidl));
    ret = CallRegisterSharedMemoryProxy(halMemPtr, outContext, &outShm);
    if (ret) {
        ALOGE("%s: callRegisterSharedMemoryProxy failed, ret is %x.\n", __func__, ret);
        putBnContextProxy(outContext);
        hidlCallBackPtr(ret, outShmPtr);
        return Void();
    }

    putBnContextProxy(outContext);
    outShmPtr.setToExternal(reinterpret_cast<uint8_t *>(&outShm), sizeof(TEEC_SharedMemoryHidl));
    hidlCallBackPtr(ret, outShmPtr);
    return Void();
}

Return<int32_t> LibteecGlobal::CallRegisterSharedMemoryProxy(const hidl_vec<uint8_t> &halMemPtr,
    TEEC_ContextHidl *outContext, TEEC_SharedMemoryHidl *outRegShm)
{
    int32_t ret;
    TEEC_SharedMemoryHidl *outShm = nullptr;

    if (registerSharedMemoryProxy == nullptr || putBnShmProxy == nullptr) {
        ALOGE("call register shrmem proxy: missing proxy in this handle!\n");
        return TEEC_FAIL;
    }

    outShm = reinterpret_cast<TEEC_SharedMemoryHidl *>(malloc(sizeof(TEEC_SharedMemoryHidl)));
    if (outShm == nullptr) {
        ALOGE("%s: outShm malloc failed.\n", __func__);
        return TEEC_FAIL;
    }
    (void)memset_s(outShm, sizeof(TEEC_SharedMemoryHidl), 0x00, sizeof(TEEC_SharedMemoryHidl));

    int tmpCheckStatus = ((halMemPtr.data() != nullptr) && (halMemPtr.size() == sizeof(TEEC_SharedMemory)));
    if (tmpCheckStatus) {
        if (memcpy_s(outShm, sizeof(TEEC_SharedMemoryHidl), halMemPtr.data(), sizeof(TEEC_SharedMemory))) {
            ALOGE("%s: memcpy failed when copy data to shm[]!\n", __func__);
            free(outShm);
            return TEEC_FAIL;
        }
    }

    ret = registerSharedMemoryProxy(reinterpret_cast<TEEC_ContextHidl *>(outContext),
        reinterpret_cast<TEEC_SharedMemoryHidl *>(outShm));
    if (ret) {
        free(outShm);
        return ret;
    }
    outRegShm->ops_cnt = outShm->ops_cnt;
    outRegShm->is_allocated = outShm->is_allocated;
    outRegShm->offset = outShm->offset;
    putBnShmProxy(outShm); /* pair with ops_cnt++ when add to list */
    return ret; /* maybe ok, maybe failed */
}

Return<void> LibteecGlobal::allocateSharedMemory(int32_t pid, const hidl_vec<uint8_t> &halCxtPtr,
    const hidl_vec<uint8_t> &halMemPtr, allocateSharedMemory_cb hidlCallBackPtr)
{
    int32_t ret = (int32_t)TEEC_ERROR_BAD_PARAMETERS;
    hidl_vec<uint8_t> outShmPtr;
    android::hardware::hidl_handle handle;
    int tempFd = -1;
    TEEC_ContextHidl *outContext = nullptr;

    if (hidlCallBackPtr == nullptr) {
        ALOGE("%s: hidlCallBackPtr is nullptr\n", __func__);
        return Void();
    }

    (void)CheckAndOpenHandle();
    if (putBnContextProxy == nullptr) {
        ALOGE("allocate sharemem : missing proxy in this handle!!!\n");
        ret = TEEC_FAIL;
        hidlCallBackPtr(ret, outShmPtr, handle);
        return Void();
    }

    ret = GetSharedMemoryContextAndFd(halCxtPtr, pid, &outContext, &tempFd);
    if (ret != TEEC_SUCCESS) {
        ALOGE("get shm contex failed , or get fd failed when Ashm\n");
        hidlCallBackPtr(ret, outShmPtr, handle);
        return Void();
    }

    native_handle_t *nativeHandle = native_handle_create(1, 0); /* 2params: means: nFds & nInts */
    if (nativeHandle == nullptr) {
        ALOGE("create nativehandle failed when Ashm\n");
        ret = TEEC_FAIL;
        close(tempFd);
        goto ALLOCEND;
    }
    nativeHandle->data[0] = tempFd;

    TEEC_SharedMemoryHidl outShm;
    (void)memset_s((void *)(&outShm), sizeof(TEEC_SharedMemoryHidl), 0, sizeof(TEEC_SharedMemoryHidl));
    ret = CallAllocateSharedMemoryProxy(halMemPtr, outContext, &outShm);
    if (ret) {
        ALOGE("%s: callAllocateSharedMemoryProxy failed, ret is %x.\n", __func__, ret);
        native_handle_close(nativeHandle);
        native_handle_delete(nativeHandle);
        goto ALLOCEND;
    }

    /* 2nd param: true: means take ownership */
    handle.setTo(nativeHandle, true);

    outShmPtr.setToExternal(reinterpret_cast<uint8_t *>(&outShm), sizeof(TEEC_SharedMemoryHidl));

ALLOCEND:
    hidlCallBackPtr(ret, outShmPtr, handle);
    putBnContextProxy(outContext);
    return Void();
}

Return<int32_t> LibteecGlobal::GetSharedMemoryContextAndFd(const hidl_vec<uint8_t> &halCxtPtr,
    int32_t pid, TEEC_ContextHidl **outContext, int *fd)
{
    TEEC_ContextHidl *shmContext = nullptr;

    int tmpCheckStatus = (getBnContextProxy == nullptr || putBnContextProxy == nullptr);
    if (tmpCheckStatus) {
        ALOGE("allocate sharemem : missing proxy in this handle!!!\n");
        return TEEC_FAIL;
    }

    tmpCheckStatus = ((halCxtPtr.data() == nullptr) || (halCxtPtr.size() != sizeof(TEEC_Context)) ||
                     (!IsValidContext(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)));
    if (tmpCheckStatus) {
        ALOGE("%s: invalid context!\n", __func__);
        return TEEC_FAIL;
    }

    shmContext = getBnContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (shmContext == nullptr) {
        ALOGE("%s: no context found in hidl service!!!\n", __func__);
        return TEEC_ERROR_BAD_PARAMETERS;
    }

    *fd = dup(shmContext->fd);
    if (*fd < 0) {
        ALOGE("get fd failed when Ashm \n");
        putBnContextProxy(shmContext);
        return TEEC_FAIL;
    }
    *outContext = shmContext;
    return TEEC_SUCCESS;
}

Return<int32_t> LibteecGlobal::CallAllocateSharedMemoryProxy(const hidl_vec<uint8_t> &halMemPtr,
    TEEC_ContextHidl *outContext, TEEC_SharedMemoryHidl *outAllocShm)
{
    TEEC_SharedMemoryHidl *outShm = nullptr;
    int checkStat = (allocateSharedMemoryProxy == nullptr || putBnShmProxy == nullptr);
    if (checkStat) {
        ALOGE("call allocate sharemem proxy:missing proxy in this handle!!!\n");
        return TEEC_FAIL;
    }

    outShm = reinterpret_cast<TEEC_SharedMemoryHidl *>(malloc(sizeof(TEEC_SharedMemoryHidl)));
    if (outShm == nullptr) {
        ALOGE("%s: outShm malloc failed\n", __func__);
        return TEEC_FAIL;
    }
    (void)memset_s(outShm, sizeof(TEEC_SharedMemoryHidl), 0x00, sizeof(TEEC_SharedMemoryHidl));

    int tmpCheckStatus = ((halMemPtr.data() != nullptr) && (halMemPtr.size() == sizeof(TEEC_SharedMemory)));
    if (tmpCheckStatus) {
        if (memcpy_s(outShm, sizeof(TEEC_SharedMemoryHidl), halMemPtr.data(), sizeof(TEEC_SharedMemory))) {
            ALOGE("%s: memcpy failed when copy data to shm[]\n", __func__);
            free(outShm);
            return TEEC_FAIL;
        }
    }

    int32_t ret = allocateSharedMemoryProxy(reinterpret_cast<TEEC_ContextHidl *>(outContext),
        reinterpret_cast<TEEC_SharedMemoryHidl *>(outShm));
    if (ret) {
        ALOGE("%s: allocate shared memory failed\n", __func__);
        free(outShm);
        return ret;
    }
    outAllocShm->ops_cnt = outShm->ops_cnt;
    outAllocShm->is_allocated = outShm->is_allocated;
    outAllocShm->offset = outShm->offset;
    putBnShmProxy(outShm); /* pair with ops_cnt++ when add to list */
    return ret; /* maybe ok, maybe failed */
}

Return<void> LibteecGlobal::releaseSharedMemory(int32_t pid, const hidl_vec<uint8_t> &halCxtPtr,
                                                const hidl_vec<uint8_t> &halMemPtr,
                                                uint32_t shmOffset)
{
    int tmpCheckStatus = ((halCxtPtr.data() == nullptr) || (halCxtPtr.size() != sizeof(TEEC_Context)) ||
                          (!IsValidContext(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)));
    if (tmpCheckStatus) {
        ALOGE("%s: invalid context!\n", __func__);
        return Void();
    }
    (void)CheckAndOpenHandle();

    TEEC_SharedMemoryHidl outShm;
    tmpCheckStatus = ((halMemPtr.data() != nullptr) && (halMemPtr.size() == sizeof(TEEC_SharedMemory)));
    if (tmpCheckStatus) {
        if (memcpy_s(&outShm, sizeof(TEEC_SharedMemoryHidl), halMemPtr.data(), sizeof(TEEC_SharedMemory))) {
            ALOGE("%s: memcpy failed when copy data to outShm \n", __func__);
            return Void();
        }
        outShm.offset = shmOffset;
    }

    CallReleaseSharedMemoryProxy(halCxtPtr, &outShm);
    return Void();
}

Return<void> LibteecGlobal::CallReleaseSharedMemoryProxy(const hidl_vec<uint8_t> &halCxtPtr,
                                                         TEEC_SharedMemoryHidl *outShm)
{
    if (getBnContextProxy == nullptr ||
        putBnContextProxy == nullptr ||
        releaseSharedMemoryProxy == nullptr) {
        ALOGE("call release sharemem proxy:missing proxy in this handle!!!\n");
        return Void();
    }

    TEEC_ContextHidl *outContext = nullptr;
    outContext = getBnContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (outContext == nullptr) {
        ALOGE("%s: no context found in hidl service!\n", __func__);
        return Void();
    }

    outShm->context = outContext;
    releaseSharedMemoryProxy(outShm);
    putBnContextProxy(outContext);
    return Void();
}

Return<void> LibteecGlobal::requestCancellation(const hidl_vec<uint8_t> &halOptPtr)
{
    ALOGI("%s: hidl requestCancellation not support\n", __func__);
    (void)halOptPtr;
    return Void();
}

Return<int32_t> LibteecGlobal::extTuiSendEvent(int32_t pid, int32_t uid,
    const hidl_vec<uint8_t> &halTuiPtr)
{
    int32_t ret = (int32_t)TEEC_ERROR_BAD_PARAMETERS;

    (void)CheckAndOpenHandle();
    if (extTuiSendEventProxy == nullptr) {
        ALOGE("no TEEC_EXT_TuiSendEvent in this handle!\n");
        return TEEC_FAIL;
    }

    CaAuthInfo *caAuth = reinterpret_cast<CaAuthInfo *>(malloc(sizeof(CaAuthInfo)));
    if (caAuth == nullptr) {
        ALOGE("%s: malloc ca auth failed\n", __func__);
        return TEEC_FAIL;
    }

    caAuth->uid = (uid_t)uid;
    caAuth->pid = pid;
    caAuth->type = SYSTEM_CA;
    caAuth->fromHidlSide = HIDL_SIDE;
    int tmpCheckStatus = ((halTuiPtr.data() != nullptr) &&
                          (halTuiPtr.size() == sizeof(TEEC_TUI_Parameter)));
    if (!tmpCheckStatus) {
        ALOGE("no TEEC_EXT_TuiSendEvent for this handle!\n");
        goto freeBuffer;
    }
    ret = extTuiSendEventProxy(reinterpret_cast<const TEEC_TUI_Parameter *>(halTuiPtr.data()), caAuth);
freeBuffer:
    free(caAuth);
    return ret;
}

Return<void> LibteecGlobal::setCallBack(const ::android::sp<ILibteecGlobalNotify> &notify)
{
    if (notify == nullptr) {
        ALOGE("%s: Notify is NULL\n", __func__);
        return Void();
    }

    g_teecNotify = notify;
    int pid = android::hardware::IPCThreadState::self()->getCallingPid();
    int result = g_teecNotify->linkToDeath(this, pid);
    if (!result) {
        ALOGE("%s: linkToDeath failed %d\n", __func__, result);
    }
    ALOGW("%s: receive notify from teec service pid=%d\n", __func__, pid);
    return Void();
}

Return<int32_t> LibteecGlobal::extSendSystemHashXml(const hidl_vec<uint8_t> &halXmlPtr,
    const hidl_vec<uint8_t> &authInfo)
{
    int32_t ret = (int32_t)TEEC_ERROR_BAD_PARAMETERS;

    (void)CheckAndOpenHandle();
    if (extSendSysHashXmlProxy == nullptr) {
        ALOGE("no SendSysHashXml for this handle!\n");
        return TEEC_FAIL;
    }

    int tmpCheckStatus = ((authInfo.data() != nullptr) && (authInfo.size() == sizeof(CaAuthInfo)));
    if (!tmpCheckStatus) {
        ALOGE("%s: authInfo is nullptr or size is 0.\n", __func__);
        return ret;
    }

    CaAuthInfo *caAuth = reinterpret_cast<CaAuthInfo *>(malloc(sizeof(CaAuthInfo)));
    if (caAuth == nullptr) {
        ALOGE("%s: malloc ca auth failed\n", __func__);
        return TEEC_ERROR_OUT_OF_MEMORY;
    }

    if (memcpy_s(caAuth, sizeof(CaAuthInfo), authInfo.data(), sizeof(CaAuthInfo))) {
        ALOGE("%s: memcpy failed.\n", __func__);
        free(caAuth);
        return ret;
    }
    if ((halXmlPtr.data() == nullptr) ||
        (halXmlPtr.size() != sizeof(TEEC_XmlParameter))) {
        ALOGE("no TEEC_EXT_Set_Native_CAHash for this handle!\n");
        free(caAuth);
        return ret;
    }
    ret = (int32_t)extSendSysHashXmlProxy(reinterpret_cast<const TEEC_XmlParameter *>(halXmlPtr.data()), caAuth);
    free(caAuth);
    return ret;
}

Return<int32_t> LibteecGlobal::secfileSendEvent(int32_t pid,
    const android::hardware::hidl_handle &handle,
    const hidl_string &libPath, const hidl_vec<uint8_t> &halCxtPtr,
    const hidl_vec<uint8_t> &halSessPtr)
{
    TEEC_ContextHidl *outContext = nullptr;
    FILE *fp = nullptr;

    (void)halSessPtr;
    (void)CheckAndOpenHandle();
    if (sendSecfileProxy == nullptr || getBnContextProxy == nullptr) {
        ALOGE("missing proxy in this handle!\n");
        return TEEC_FAIL;
    }

    int tmpCheckStatus = ((halCxtPtr.data() == nullptr) ||
                          (halCxtPtr.size() != sizeof(TEEC_Context)) ||
                          (!IsValidContext(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()), pid)));
    if (tmpCheckStatus) {
        ALOGE("invalid context!\n");
        return TEEC_FAIL;
    }

    outContext = getBnContextProxy(reinterpret_cast<const TEEC_Context *>(halCxtPtr.data()));
    if (outContext == nullptr) {
        ALOGE("no context found in hidl service!\n");
        return TEEC_FAIL;
    }

    native_handle_t *tempHandle = nullptr;
    fp = GetFpFromHandle(handle, tempHandle);

    int32_t ret = sendSecfileProxy(reinterpret_cast<const char *>(libPath.c_str()),
                                   outContext->fd, fp);
    putBnContextProxy(outContext);
    if (fp != nullptr) {
        fclose(fp);
        fp = nullptr;
    }
    native_handle_delete(tempHandle);
    return ret;
}

void LibteecGlobal::serviceDied(uint64_t cookie, const ::android::wp<::android::hidl::base::V1_0::IBase> &who)
{
    (void)who;
    ALOGW("%s: teec service died pid=%d\n", __func__, static_cast<int>(cookie));

    Mutex::Autolock _l(mProcDataLock);
    if (!list_empty(&g_teecHidlProcDataList)) {
        struct listnode *handNode = nullptr;
        struct listnode *tempNode = nullptr;
        list_for_each_safe(handNode, tempNode, &g_teecHidlProcDataList) {
            DaemonProcdata *handProcdata = node_to_item(handNode, DaemonProcdata, procdataHead);
            ALOGW("%s: cleaning pid=%d", __func__, handProcdata->callingPid);
            SendSigToTzdriver(handProcdata->callingPid);
            CleanProcDataForOneCa(handProcdata);
            list_remove(&handProcdata->procdataHead);
            free(handProcdata);
            handProcdata = nullptr;
        }
    }

    ALOGW("%s: clean done", __func__);
    return;
}

Return<uint32_t> LibteecGlobal::iGetTEEVersionHidl()
{
    uint32_t version;

    (void)CheckAndOpenHandle();
    if (getTEEVersionProxy == nullptr) {
        ALOGE("no TEEC_GetTEEVersionHidl for this handle!\n");
        return 0;
    }

    version = getTEEVersionProxy();
    if (version == 0) {
        ALOGE("fail to get tee version\n");
    }
    return version;
}

Return<void> LibteecGlobal::processCaDied(int32_t pid)
{
    ALOGW("%s: getCallingPid=%d\n", __func__, pid);
    DaemonProcdata *outProcData = NULL;
    {
        Mutex::Autolock _l(mProcDataLock);
        outProcData = GetProcdataByPid(pid);
        if (outProcData == nullptr) {
            ALOGW("%s: outProcdata[%d] not in the list\n", __func__, pid);
            return Void();
        }
        list_remove(&outProcData->procdataHead);
    }
    SendSigToTzdriver(pid);
    CleanProcDataForOneCa(outProcData);

    free(outProcData);
    ALOGW("%s: clean done", __func__);
    return Void();
}

Return<int32_t> LibteecGlobal::CheckInputPidUid(int pid, uid_t uid)
{
    char *context = nullptr;
    if (uid != AID_ROOT) {
        ALOGE("invalid access client(uid = %u pid = %d) will be rejected\n", uid, pid);
        return TEEC_FAIL;
    }
    if (::getpidcon(pid, &context) < 0) {
        ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", pid);
        return TEEC_FAIL;
    }
    if (strcmp(context, "u:r:system_teecd:s0")) {
        ALOGE("invalid access client(uid = %u pid = %d SELinux %s) will be rejected\n", uid, pid, context);
        ::freecon(context);
        return TEEC_FAIL;
    }
    ::freecon(context);
    return TEEC_SUCCESS;
}

Return<int32_t> LibteecGlobal::handleMultiUserMsg(const hidl_vec<uint8_t> &multiUserRecvMsg)
{
    int pid = android::hardware::IPCThreadState::self()->getCallingPid();
    uid_t uid = android::hardware::IPCThreadState::self()->getCallingUid();
    if (CheckInputPidUid(pid, uid)) {
        ALOGE("%s: checkInputPidUid failed!!\n", __func__);
        return TEE_HIDL_FAILURE;
    }

    int tmpCheckStatus = ((multiUserRecvMsg.data() == nullptr) || (multiUserRecvMsg.size() != sizeof(RecvMsg)));
    if (tmpCheckStatus) {
        return TEE_HIDL_FAILURE;
    }

    const RecvMsg *multiUserMsg = reinterpret_cast<const RecvMsg *>(multiUserRecvMsg.data());
    uint32_t magic = (unsigned int)multiUserMsg->magic;
    uint32_t status = (unsigned int)multiUserMsg->status;
    int userid = (int)multiUserMsg->userid;

    tmpCheckStatus = (userid > MU_MSG_USERID_OWNER && userid < MU_MSG_USERID_MAX);

    /* check magic, and then status, and userid validate value */
    if (magic != MU_MSG_MAGIC) {
        /* do nothing */
        ALOGE("cmd no define to handle\n\n");
        return TEE_HIDL_FAILURE;
    }
    if (status == MU_MSG_STAT_NEW_USER) {
        return MakeDirAndLinkUser(userid, status, tmpCheckStatus);
    } else if (status == MU_MSG_STAT_RM_USER) {
        return UnlinkUser(userid, status, tmpCheckStatus);
    } else if (status == MU_MSG_STAT_SWITCH_USER) {
        /* switch user */
        ALOGE("switch user cmd do not handle now, status %x.\n", status);
        return TEE_HIDL_SUCCESS;
    }
    /* not in all conditions we can handle, do nothing */
    ALOGE("cmd no define to handle, status is %x.\n", status);
    return TEE_HIDL_FAILURE;
}

static bool CheckSizeStatus(uint32_t shmInfoOffset, uint32_t refSize,
                            uint32_t totalSize, uint32_t memSize)
{
    return ((shmInfoOffset + refSize < shmInfoOffset) || (shmInfoOffset + refSize < refSize) ||
            (shmInfoOffset + refSize > totalSize) || (refSize > memSize));
}

Return<TEEC_Result> LibteecGlobal::DecodeHidlMemory(TEEC_ContextHidl *outContext,
    TEEC_Operation *operation, TEEC_SharedMemory *shm, TEEC_SharedMemoryHidl *shmHidl[],
    uint32_t shmNum, uint8_t *data, size_t memSize)
{
    uint32_t paramType[PARAM_NUM];
    uint32_t shmInfoOffset = 0;
    uint32_t totalHidlMemSize = memSize;
    TEEC_Operation *tmpOperation = operation;

    if (shmNum != PARAM_NUM) {
        return TEEC_FAIL;
    }

    for (uint32_t paramCnt = 0; paramCnt < PARAM_NUM; paramCnt++) {
        paramType[paramCnt] = TEEC_PARAM_TYPE_GET(tmpOperation->paramTypes, paramCnt);
        bool tmpCheckStatus1 = ((paramType[paramCnt] == TEEC_MEMREF_TEMP_INPUT) ||
                                (paramType[paramCnt] == TEEC_MEMREF_TEMP_OUTPUT) ||
                                (paramType[paramCnt] == TEEC_MEMREF_TEMP_INOUT));
        bool tmpCheckStatus2 = ((paramType[paramCnt] == TEEC_MEMREF_WHOLE) ||
                                (paramType[paramCnt] == TEEC_MEMREF_PARTIAL_INPUT) ||
                                (paramType[paramCnt] == TEEC_MEMREF_PARTIAL_OUTPUT) ||
                                (paramType[paramCnt] == TEEC_MEMREF_PARTIAL_INOUT));
        if (tmpCheckStatus1) {
            uint32_t refSize = tmpOperation->params[paramCnt].tmpref.size;
            tmpCheckStatus1 = CheckSizeStatus(shmInfoOffset, refSize, totalHidlMemSize, memSize);
            if (tmpCheckStatus1) {
                ALOGE("%s: temp mem:%x greater than hidl mem:%x:%x:%x\n",
                      __func__, refSize, shmInfoOffset, (uint32_t)memSize, totalHidlMemSize);
                return TEEC_FAIL;
            }
            tmpOperation->params[paramCnt].tmpref.buffer = data + shmInfoOffset;
            memSize -= refSize;
            shmInfoOffset += refSize;
        } else if (tmpCheckStatus2) {
            InputPara tmpInputPara;
            tmpInputPara.paraType = paramType[paramCnt];
            tmpInputPara.offset = shmInfoOffset;
            tmpInputPara.memSize = memSize;
            tmpInputPara.totalSize = totalHidlMemSize;
            TEEC_Result retCode = FillShareMemoryBuffer(&(shm[paramCnt]), &(shmHidl[paramCnt]), data,
                &tmpInputPara, outContext, &(tmpOperation->params[paramCnt]));
            if (retCode) {
                return retCode;
            }
            shmInfoOffset = tmpInputPara.offset;
            memSize = tmpInputPara.memSize;
        }
    }

    return TEEC_SUCCESS;
}

#define STRUCT_SIZE (4 * (sizeof(uint32_t)) + 1 * (sizeof(bool)))
Return<TEEC_Result> LibteecGlobal::FillShareMemoryBuffer(TEEC_SharedMemory *shareMemBuf,
    TEEC_SharedMemoryHidl **shmHidl, uint8_t *data, InputPara *inputPara,
    TEEC_ContextHidl *outContext, TEEC_Parameter *params)
{
    uint32_t shmInfoOffset = inputPara->offset;
    uint32_t memSize = inputPara->memSize;
    uint32_t shmOffset = 0;
    uint32_t refSize = STRUCT_SIZE;

    if (CheckSizeStatus(shmInfoOffset, refSize, inputPara->totalSize, memSize)) {
        goto FILLBUFFEREND;
    }

    CopyToShareMemory(shareMemBuf, data, shmInfoOffset, &shmOffset);
    memSize -= refSize;
    shmInfoOffset += refSize;

    refSize = params->memref.size;
    if (inputPara->paraType == TEEC_MEMREF_WHOLE)
        refSize = shareMemBuf->size;

    if (CheckSizeStatus(shmInfoOffset, refSize, inputPara->totalSize, memSize)) {
        goto FILLBUFFEREND;
    }

    if (!shareMemBuf->is_allocated) {
        shareMemBuf->buffer = data + shmInfoOffset;
        params->memref.offset = 0;
    } else {
        if (getBnShmByOffsetProxy == nullptr) {
            ALOGE("no GetBnShmAddr in this handle!\n");
            return TEEC_FAIL;
        }
        TEEC_SharedMemoryHidl *shmTemp = getBnShmByOffsetProxy(shmOffset, outContext);
        if (shmTemp == nullptr || shmTemp->buffer == nullptr) {
            ALOGE("%s: no shm buffer found in hidl service!\n", __func__);
            return TEEC_ERROR_BAD_PARAMETERS;
        }
        shareMemBuf->buffer = shmTemp->buffer;
        *shmHidl = shmTemp;
    }
    params->memref.parent = shareMemBuf;
    memSize -= refSize;
    shmInfoOffset += refSize;

    inputPara->offset = shmInfoOffset;
    inputPara->memSize = memSize;
    return TEEC_SUCCESS;

FILLBUFFEREND:
    ALOGE("%s: partial mem:%x greater than hidl mem:%x:%x:%x\n",
          __func__, refSize, shmInfoOffset, memSize, inputPara->totalSize);
    return TEEC_FAIL;
}

void LibteecGlobal::PutAllocShrMem(TEEC_SharedMemoryHidl *shmHidl[], uint32_t shmNum)
{
    if (putBnShmProxy == nullptr) {
        ALOGE("no PutBnShm in this handle!\n");
        return;
    }

    uint32_t paramCnt;
    for (paramCnt = 0; paramCnt < shmNum; paramCnt++) {
        if (shmHidl[paramCnt] != nullptr) {
            putBnShmProxy(shmHidl[paramCnt]);
        }
    }
    return;
}

Return<FILE *> LibteecGlobal::GetFpFromHandle(const android::hardware::hidl_handle &handle,
                                              native_handle_t *&tempHandle) const
{
    FILE *fp = nullptr;

    if (handle == nullptr || handle.getNativeHandle() == nullptr) {
        return fp;
    }

    tempHandle = native_handle_clone(handle);
    if (tempHandle == nullptr) {
        ALOGE("get fp failed caused by native handle clone failed!\n");
        return fp;
    }

    int flag = tempHandle->data[1];
    if (flag == 1) {
        int fd = tempHandle->data[0];
        fp = fdopen(fd, "r");
    }
    return fp;
}

Return<void> LibteecGlobal::CleanProcDataForOneCa(DaemonProcdata *procData)
{
    if ((findAndRemoveBnContextProxy == nullptr) ||
        (putBnContextProxy == nullptr)) {
        ALOGE("missing proxy in this handle!\n");
        return Void();
    }

    for (int i = 0; i < MAX_CXTCNT_ONECA; i++) {
        if (procData->cxtFd[i] == -1) {
            continue;
        }

        TEEC_Context context;
        context.fd = procData->cxtFd[i];
        procData->cxtFd[i] = -1;

        TEEC_ContextHidl *outContext = findAndRemoveBnContextProxy(&context);
        if (outContext == nullptr) {
            ALOGE("%s: no context found in hidl service!\n", __func__);
            continue;
        }
        putBnContextProxy(outContext); /* pair with initialize context */
    }

    return Void();
}

Return<int32_t> LibteecGlobal::GetOperationFromHidlVec(const hidl_vec<uint8_t> &halOptPtr,
    TEEC_Operation *operation)
{
    uint32_t paramCnt;
    uint32_t paramType;
    bool tempType = false;
    bool partialType = false;

    if (memcpy_s(operation, sizeof(TEEC_Operation), halOptPtr.data(), sizeof(TEEC_Operation))) {
        ALOGE("memcpy failed...\n");
        return TEE_HIDL_FAILURE;
    }

    /* clear the pointer from ca to avoid access to invalid address */
    operation->session = nullptr;
    for (paramCnt = 0; paramCnt < PARAM_NUM; paramCnt++) {
        paramType = TEEC_PARAM_TYPE_GET(operation->paramTypes, paramCnt);
        tempType = ((paramType == TEEC_MEMREF_TEMP_INPUT) ||
                    (paramType == TEEC_MEMREF_TEMP_OUTPUT) ||
                    (paramType == TEEC_MEMREF_TEMP_INOUT));
        partialType = ((paramType == TEEC_MEMREF_WHOLE) ||
                       (paramType == TEEC_MEMREF_PARTIAL_INPUT) ||
                       (paramType == TEEC_MEMREF_PARTIAL_OUTPUT) ||
                       (paramType == TEEC_MEMREF_PARTIAL_INOUT));
        if (tempType) {
            operation->params[paramCnt].tmpref.buffer = nullptr;
        } else if (partialType) {
            operation->params[paramCnt].memref.parent = nullptr;
        }
    }
    return TEE_HIDL_SUCCESS;
}

/**************************************************************************/
/*                                 fetch method                           */
/**************************************************************************/
using::vendor::huanglong::hardware::libteec::V3_0::ILibteecGlobal;
ILibteecGlobal *HIDL_FETCH_ILibteecGlobal(const char *)
{
    ALOGI("------------------ ILibteecGlobal ------------------\n");
    LibteecGlobal *libteecGp = new (std::nothrow) LibteecGlobal();
    if (libteecGp == nullptr) {
        ALOGE("cannot allocate for libteecGp! \n");
    }

    /* ignore SIGPIPE(when teecd is killed, libteec hidl will not restart). */
    signal(SIGPIPE, SIG_IGN);
    return libteecGp;
}
}  // namespace implementation
}  // namespace V3_0
}  // namespace libteec
}  // namespace hardware
}  // namespace huanglong
}  // namespace vendor