/*
* Copyright (c) 2009-2020, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file        mos_utilities_specific.cpp
//! \brief        This module implements the MOS wrapper functions for Linux/Android
//!

#include "mos_utilities_specific.h"
#include "mos_utilities.h"
#include "mos_util_debug.h"
#include <fcntl.h>     // open
#include <stdlib.h>    // atoi
#include <string.h>    // strlen, strcat, etc.
#include <errno.h>     // strerror(errno)
#include <time.h>      // get_clocktime
#include <sys/stat.h>  // fstat
#include <dlfcn.h>     // dlopen, dlsym, dlclose
#include <sys/types.h>
#include <unistd.h>
#if _MEDIA_RESERVED
#include "codechal_user_settings_mgr_ext.h"
#include "vphal_user_settings_mgr_ext.h"
#endif // _MEDIA_RESERVED

#include <sys/ipc.h>   // System V IPC
#include <sys/types.h>
#include <sys/sem.h>
#include <signal.h>
#include <unistd.h>    // fork
#include "mos_utilities_specific_next.h"
static const char* szUserFeatureFile = USER_FEATURE_FILE;

#if _MEDIA_RESERVED
static MediaUserSettingsMgr *codecUserFeatureExt = nullptr;
static MediaUserSettingsMgr *vpUserFeatureExt    = nullptr;
#endif


#ifdef __cplusplus

void PerfUtility::startTick(std::string tag)
{
    std::lock_guard<std::mutex> lock(perfMutex);
    Tick newTick = {};
    struct timespec ts = {};

    // get start tick count
    clock_gettime(CLOCK_REALTIME, &ts);
    newTick.start = int(ts.tv_sec * 1000000) + int(ts.tv_nsec / 1000); // us

    std::vector<Tick> *perf = nullptr;
    std::map<std::string, std::vector<Tick>*>::iterator it;
    it = records.find(tag);
    if (it == records.end())
    {
        perf = new std::vector<Tick>;
        perf->push_back(newTick);
        records[tag] = perf;
    }
    else
    {
        it->second->push_back(newTick);
    }
}

void PerfUtility::stopTick(std::string tag)
{
    std::lock_guard<std::mutex> lock(perfMutex);
    struct timespec ts = {};
    std::map<std::string, std::vector<Tick>*>::iterator it;
    it = records.find(tag);
    if (it == records.end())
    {
        // should not happen
        return;
    }

    // get stop tick count
    clock_gettime(CLOCK_REALTIME, &ts);
    it->second->back().stop = int(ts.tv_sec * 1000000) + int(ts.tv_nsec / 1000); // us

    // calculate time interval
    it->second->back().time = double(it->second->back().stop - it->second->back().start) / 1000.0; // ms
}

#endif // __cplusplus

//!
//! \brief Linux specific user feature define, used in MOS_UserFeature_ParsePath
//!        They can be unified with the win definitions, since they are identical.
//!
#define MOS_UF_SEPARATOR  "\\"
#define MOS_UFKEY_EXT     "UFKEY_EXTERNAL"
#define MOS_UFKEY_INT     "UFKEY_INTERNAL"
PUFKEYOPS pUFKeyOps = nullptr;

//!
//! \brief Linux specific trace entry path and file description.
//!
const char * const MosTracePath = "/sys/kernel/debug/tracing/trace_marker";
static int32_t MosTraceFd = -1;

//!
//! \brief for int64_t/uint64_t format print warning
//!
#if __WORDSIZE == 64
#define __MOS64_PREFIX    "l"
#else
#define __MOS64_PREFIX    "ll"
#endif

#define MOSd64     __MOS64_PREFIX "d"
#define MOSu64     __MOS64_PREFIX "u"

//!
//! \brief mutex for mos utilities multi-threading protection
//!
MOS_MUTEX gMosUtilMutex = PTHREAD_MUTEX_INITIALIZER;

static uint32_t uiMOSUtilInitCount = 0; // number count of mos utilities init

MOS_STATUS MOS_SecureStrcat(char  *strDestination, size_t numberOfElements, const char * const strSource)
{
    if ( (strDestination == nullptr) || (strSource == nullptr) )
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if(strnlen(strDestination, numberOfElements) == numberOfElements) // Not null terminated
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if((strlen(strDestination) + strlen(strSource)) >= numberOfElements) // checks space for null termination.
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    strcat(strDestination, strSource);
    return MOS_STATUS_SUCCESS;
}

char  *MOS_SecureStrtok(
    char                *strToken,
    const char          *strDelimit,
    char                **contex)
{
    return strtok_r(strToken, strDelimit, contex);
}

MOS_STATUS MOS_SecureStrcpy(char  *strDestination, size_t numberOfElements, const char * const strSource)
{
    if ( (strDestination == nullptr) || (strSource == nullptr) )
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if ( numberOfElements <= strlen(strSource) ) // checks if there is space for null termination after copy.
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    strcpy(strDestination, strSource);

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_SecureMemcpy(void  *pDestination, size_t dstLength, PCVOID pSource, size_t srcLength)
{
    if ( (pDestination == nullptr) || (pSource == nullptr) )
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if ( dstLength < srcLength )
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }
    if(pDestination != pSource)
    {
        memcpy(pDestination, pSource, srcLength);
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_SecureFileOpen(
    FILE       **ppFile,
    const char *filename,
    const char *mode)
{
    PFILE fp;

    if ((ppFile == nullptr) || (filename == nullptr) || (mode == nullptr))
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    fp = fopen(filename, mode);

    if (fp == nullptr)
    {
        *ppFile = nullptr;
        return MOS_STATUS_FILE_OPEN_FAILED;
    }
    else
    {
        *ppFile = fp;
        return MOS_STATUS_SUCCESS;
    }
}

int32_t MOS_SecureStringPrint(char  *buffer, size_t bufSize, size_t length, const char * const format, ...)
{
    int32_t iRet = -1;
    va_list var_args;

    if((buffer == nullptr) || (format == nullptr) || (bufSize < length))
    {
        return iRet;
    }

    va_start(var_args, format);

    iRet = vsnprintf(buffer, length, format, var_args);

    va_end(var_args);

    return iRet;
}

MOS_STATUS MOS_SecureVStringPrint(char  *buffer, size_t bufSize, size_t length, const char * const format, va_list var_args)
{
    if((buffer == nullptr) || (format == nullptr) || (bufSize < length))
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    vsnprintf(buffer, length, format, var_args);

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_GetFileSize(
    HANDLE              hFile,
    uint32_t            *lpFileSizeLow,
    uint32_t            *lpFileSizeHigh)
{
    struct stat     Buf;
    MOS_UNUSED(lpFileSizeHigh);

    if((hFile == nullptr) || (lpFileSizeLow == nullptr))
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if ( (fstat((intptr_t)hFile, &Buf)) < 0 )
    {
        *lpFileSizeLow = 0;
        return MOS_STATUS_INVALID_FILE_SIZE;
    }
    *lpFileSizeLow  = (uint32_t)Buf.st_size;

    //to-do, lpFileSizeHigh store high 32-bit of File size
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_CreateDirectory(
    char * const       lpPathName)
{
    uint32_t   mode;
    MOS_STATUS eStatus = MOS_STATUS_UNKNOWN;

    MOS_OS_CHK_NULL(lpPathName);

    // Set read/write access right for usr/group.
    mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP;
    if (mkdir(lpPathName, mode) < 0 &&
        errno != EEXIST) // Directory already exists, don't return failure in this case.
    {
        MOS_OS_ASSERTMESSAGE("Failed to create the directory '%s'. Error = %s", lpPathName, strerror(errno));
        eStatus = MOS_STATUS_DIR_CREATE_FAILED;
        goto finish;
    }

    eStatus = MOS_STATUS_SUCCESS;

finish:
    return eStatus;
}

MOS_STATUS MOS_CreateFile(
    PHANDLE             pHandle,
    char * const        lpFileName,
    uint32_t            iOpenFlag)
{
    int32_t             iFileDescriptor;
    uint32_t            mode;

    if((lpFileName == nullptr) || (pHandle == nullptr))
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }
    //set read/write access right for usr/group, mMode only takes effect when
    //O_CREAT is set
    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
    if ( (iFileDescriptor = open(lpFileName, iOpenFlag, mode)) < 0 )
    {
        *pHandle = (HANDLE)((intptr_t) iFileDescriptor);
        return MOS_STATUS_INVALID_HANDLE;
    }

    *pHandle = (HANDLE)((intptr_t) iFileDescriptor);
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_ReadFile(
    HANDLE  hFile,
    void    *lpBuffer,
    uint32_t bytesToRead,
    uint32_t *pBytesRead,
    void    *lpOverlapped)
{
    size_t  nNumBytesToRead;
    ssize_t nNumBytesRead;
    MOS_UNUSED(lpOverlapped);

    if((hFile == nullptr) || (lpBuffer == nullptr) || (pBytesRead == nullptr))
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    nNumBytesToRead   = (size_t)bytesToRead;
    nNumBytesRead     = 0;

    //To-do: process lpOverlapped

    if ((nNumBytesRead = read((intptr_t)hFile, lpBuffer, nNumBytesToRead)) < 0)
    {
        *pBytesRead = 0;
        return MOS_STATUS_FILE_READ_FAILED;
    }

    *pBytesRead = (uint32_t)nNumBytesRead;
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_WriteFile(
    HANDLE    hFile,
    void      *lpBuffer,
    uint32_t  bytesToWrite,
    uint32_t  *pbytesWritten,
    void      *lpOverlapped)
{
    size_t    nNumBytesToWrite;
    ssize_t   nNumBytesWritten;
    MOS_UNUSED(lpOverlapped);

    if((hFile == nullptr) || (lpBuffer == nullptr) || (pbytesWritten == nullptr))
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    nNumBytesToWrite = (size_t)bytesToWrite;
    nNumBytesWritten = 0;

    //To-do, process lpOverlapped

    if ((nNumBytesWritten = write((intptr_t)hFile, lpBuffer, nNumBytesToWrite)) < 0)
    {
        *pbytesWritten = 0;
        return MOS_STATUS_FILE_WRITE_FAILED;
    }

    *pbytesWritten = (uint32_t)nNumBytesWritten;
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_SetFilePointer(
    HANDLE        hFile,
    int32_t       lDistanceToMove,
    int32_t       *lpDistanceToMoveHigh,
    int32_t       dwMoveMethod)
{
    int32_t     iOffSet;
    int32_t     iCurPos;

    if(hFile == nullptr)
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if (lpDistanceToMoveHigh == nullptr)
    {
        iOffSet = lDistanceToMove;
    }
    else
    {
        //to-do, let lpDistanceToMoveHigh and lDistanceToMove form a 64-bit iOffSet
        iOffSet = (int32_t)lDistanceToMove;
    }

    if ((iCurPos = lseek((intptr_t)hFile, iOffSet, dwMoveMethod)) < 0)
    {
        return MOS_STATUS_SET_FILE_POINTER_FAILED;
    }

    return MOS_STATUS_SUCCESS;
}

int32_t MOS_CloseHandle(HANDLE hObject)
{
    int32_t iRet = false;

    if(hObject != nullptr)
    {
        close((intptr_t)hObject);
        iRet = true;
    }

    return iRet;
}

//library
MOS_STATUS MOS_LoadLibrary(const char * const lpLibFileName, PHMODULE phModule)
{
    if (lpLibFileName == nullptr)
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    *phModule = dlopen((const char *)lpLibFileName, RTLD_LAZY);

    return ((*phModule != nullptr) ? MOS_STATUS_SUCCESS : MOS_STATUS_LOAD_LIBRARY_FAILED);
}

int32_t MOS_FreeLibrary (HMODULE hLibModule)
{
    uint32_t iRet = 10;   // Initialize to some non-zero value

    if(hLibModule != nullptr)
    {
        iRet = dlclose(hLibModule);
    }
    return (iRet == 0) ? true : false;
}

void  *MOS_GetProcAddress(HMODULE hModule, const char *lpProcName)
{
    void  *pSym = nullptr;

    if (hModule    == nullptr ||
        lpProcName == nullptr)
    {
        MOS_OS_ASSERTMESSAGE("Invalid parameter.");
    }
    else
    {
        pSym = dlsym(hModule, lpProcName);
    }

    return pSym;
}

int32_t MOS_GetPid()
{
    return(getpid());
}

//Performace
int32_t MOS_QueryPerformanceFrequency(uint64_t *pFrequency)
{
    struct timespec  Res;
    int32_t          iRet;

    if(pFrequency == nullptr)
    {
        return false;
    }

    if ( (iRet = clock_getres(CLOCK_MONOTONIC, &Res)) != 0 )
    {
        return false;
    }

    // resolution (precision) can't be in seconds for current machine and OS
    if (Res.tv_sec != 0)
    {
        return false;
    }
    *pFrequency = (uint64_t)((1000 * 1000 * 1000) / Res.tv_nsec);

    return true;
}

int32_t MOS_QueryPerformanceCounter(uint64_t *pPerformanceCount)
{
    struct timespec     Res;
    struct timespec     t;
    int32_t             iRet;

    if(pPerformanceCount == nullptr)
    {
        return false;
    }
    if ( (iRet = clock_getres (CLOCK_MONOTONIC, &Res)) != 0 )
    {
        return false;
    }
    if (Res.tv_sec != 0)
    { // resolution (precision) can't be in seconds for current machine and OS
        return false;
    }
    if( (iRet = clock_gettime(CLOCK_MONOTONIC, &t)) != 0)
    {
        return false;
    }
    *pPerformanceCount = (uint64_t)((1000 * 1000 * 1000 * t.tv_sec + t.tv_nsec) / Res.tv_nsec);

    return true;
}

void MOS_Sleep(uint32_t mSec)
{
    usleep(1000 * mSec);
}

//User Feature
/*----------------------------------------------------------------------------
| Name      : _UserFeature_FindKey
| Purpose   : This function finds a key in keys linked list according to key
|             name.
| Arguments : pKeyList   [in] Key Linked list.
|             pcKeyName  [in] Name to the key to find.
| Returns   : Matched uf_key data. otherwise return NULL.
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_UF_KEY* _UserFeature_FindKey(MOS_PUF_KEYLIST pKeyList, char * const pcKeyName)
{
    int32_t           iResult;
    MOS_PUF_KEYLIST   pTempNode;

    iResult = -1;

    for(pTempNode = pKeyList; pTempNode; pTempNode = pTempNode->pNext)
    {
        iResult = strcmp(pTempNode->pElem->pcKeyName, pcKeyName);
        if ( iResult == 0 )
        {
            return pTempNode->pElem;
        }
    }
    return nullptr; //not found
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_FindValue
| Purpose   : Find a value in values array of a key. Return position in values
|             array
| Arguments : UFKey        [in] Searched Key node.
|             pcValueName  [in] Value name.
| Returns   : Matched value No. if it can be found, otherwise, return
|             NOT_FOUND(-1);
| Comments  :
\---------------------------------------------------------------------------*/
static int32_t _UserFeature_FindValue(MOS_UF_KEY UFKey, char * const pcValueName)
{
    int32_t iResult;
    int32_t i;

    iResult = -1;

    for ( i = 0; i < (int32_t)UFKey.ulValueNum; i++ )
    {
        iResult = strcmp(UFKey.pValueArray[i].pcValueName, pcValueName);
        if ( iResult == 0 )
        {
            return i;
        }
    }
    return NOT_FOUND;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_Add
| Purpose   : Add new key to keys' linked list.
| Arguments : pKeyList       [in] Key linked list.
|             NewKey         [in] Added new key.
| Returns   : MOS_STATUS_SUCCESS            success
|             MOS_STATUS_INVALID_PARAMETER  invalid NewKey
|             MOS_STATUS_NO_SPACE           no space left for allocate
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_Add(MOS_PUF_KEYLIST *pKeyList, MOS_UF_KEY *NewKey)
{
    MOS_UF_KEYNODE  *pNewNode;
    MOS_UF_KEYNODE  *pTempNode;
    MOS_UF_KEYNODE  *pStartNode;

    pNewNode   =  nullptr;
    pTempNode  =  nullptr;
    pStartNode =  *pKeyList;

    if ( NewKey == nullptr )
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    pNewNode = (MOS_UF_KEYNODE*)MOS_AllocMemory(sizeof(MOS_UF_KEYNODE));
    if (pNewNode == nullptr)
    {
        return MOS_STATUS_NO_SPACE;
    }
    pNewNode->pElem = NewKey;

    if (*pKeyList == nullptr ) // the key list is empty
    {
        pNewNode->pNext = nullptr;
        (*pKeyList) = pNewNode;
    }
    else // the key list is not empty, append to the front
    {
        pTempNode = pStartNode->pNext;
        pStartNode->pNext = pNewNode;
        pNewNode->pNext = pTempNode;
    }
    return MOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_Set
| Purpose   : This function set a key to the key list.
| Arguments : pKeyList          [in] Key linked list.
|             NewKey            [in] Set key content.
| Returns   : MOS_STATUS_SUCCESS      Operation success.
|             MOS_STATUS_UNKNOWN      Can't find key in User Feature File.
|             MOS_STATUS_NO_SPACE     no space left for allocate
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_Set(MOS_PUF_KEYLIST *pKeyList, MOS_UF_KEY NewKey)
{
    int32_t       iPos;
    MOS_UF_VALUE  *pValueArray;
    MOS_UF_KEY    *Key;
    void          *ulValueBuf;

    iPos         = -1;
    pValueArray  = nullptr;

    if ( (Key = _UserFeature_FindKey(*pKeyList, NewKey.pcKeyName)) == nullptr )
    {
        // can't find key in File
        return MOS_STATUS_UNKNOWN;
    }

    // Prepare the ValueBuff of the NewKey
    if ((ulValueBuf = MOS_AllocMemory(NewKey.pValueArray[0].ulValueLen)) == nullptr)
    {
         return MOS_STATUS_NO_SPACE;
    }

    if ( (iPos = _UserFeature_FindValue(*Key, NewKey.pValueArray[0].pcValueName)) == NOT_FOUND)
    {
        //not found, add a new value to key struct.
        //reallocate memory for appending this value.
        pValueArray = (MOS_UF_VALUE*)MOS_AllocMemory(sizeof(MOS_UF_VALUE)*(Key->ulValueNum+1));
        if (pValueArray == nullptr)
        {
            MOS_FreeMemory(ulValueBuf);
            return MOS_STATUS_NO_SPACE;
        }

        MOS_SecureMemcpy(pValueArray,
                        sizeof(MOS_UF_VALUE)*(Key->ulValueNum),
                        Key->pValueArray,
                        sizeof(MOS_UF_VALUE)*(Key->ulValueNum));

        MOS_FreeMemory(Key->pValueArray);

        Key->pValueArray = pValueArray;

        iPos = Key->ulValueNum;
        MOS_SecureStrcpy(Key->pValueArray[Key->ulValueNum].pcValueName,
            MAX_USERFEATURE_LINE_LENGTH,
            NewKey.pValueArray[0].pcValueName);
        Key->ulValueNum ++;
    }
    else
    {
        //if found, the previous value buffer needs to be freed before reallocating
        MOS_FreeMemory(Key->pValueArray[iPos].ulValueBuf);
    }

    Key->pValueArray[iPos].ulValueLen  = NewKey.pValueArray[0].ulValueLen;
    Key->pValueArray[iPos].ulValueType = NewKey.pValueArray[0].ulValueType;
    Key->pValueArray[iPos].ulValueBuf  = ulValueBuf;

    MOS_ZeroMemory(Key->pValueArray[iPos].ulValueBuf, NewKey.pValueArray[0].ulValueLen);

    MOS_SecureMemcpy(Key->pValueArray[iPos].ulValueBuf,
                     NewKey.pValueArray[0].ulValueLen,
                     NewKey.pValueArray[0].ulValueBuf,
                     NewKey.pValueArray[0].ulValueLen);

    return MOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_Query
| Purpose   : This function query a key's value and return matched key node
|             content just with matched value content.
| Arguments : pKeyList      [in] Key linked list.
|             NewKey        [in] New key content with matched value.
| Returns   : MOS_STATUS_SUCCESS         Operation success.
|             MOS_STATUS_UNKNOWN         Can't find key or value in User Feature File.
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_Query(MOS_PUF_KEYLIST pKeyList, MOS_UF_KEY *NewKey)
{
    int32_t       iPos;
    MOS_UF_VALUE  *pValueArray;
    MOS_UF_KEY    *Key;

    iPos         = -1;
    pValueArray  = nullptr;

    // can't find key in user feature
    if ( (Key = _UserFeature_FindKey(pKeyList, NewKey->pcKeyName)) == nullptr )
    {
        return MOS_STATUS_UNKNOWN;
    }

    // can't find Value in the key
    if ( (iPos = _UserFeature_FindValue(*Key, NewKey->pValueArray[0].pcValueName)) == NOT_FOUND)
    {
        return MOS_STATUS_UNKNOWN;
    }

    //get key content from user feature
    MOS_SecureMemcpy(NewKey->pValueArray[0].ulValueBuf,
                     Key->pValueArray[iPos].ulValueLen,
                     Key->pValueArray[iPos].ulValueBuf,
                     Key->pValueArray[iPos].ulValueLen);

    NewKey->pValueArray[0].ulValueLen    =  Key->pValueArray[iPos].ulValueLen;
    NewKey->pValueArray[0].ulValueType   =  Key->pValueArray[iPos].ulValueType;

    return MOS_STATUS_SUCCESS;
}

static MOS_STATUS _UserFeature_ReadNextTokenFromFile(FILE *pFile, const char *szFormat, char  *szToken)
{
    size_t nTokenSize = 0;

    // Reads the next token from the given pFile.
    if (fscanf(pFile, szFormat, szToken) <= 0)
    {
        MOS_OS_VERBOSEMESSAGE("Failed reading the next token from the user feature file. This is probably because the token does not exist in the user feature file.");
        return MOS_STATUS_FILE_READ_FAILED;
    }

    // Converts to Unix-style line endings to prevent compatibility problems.
    nTokenSize = strnlen(szToken, MAX_USERFEATURE_LINE_LENGTH);
    if (szToken[nTokenSize-1] == '\r')
    {
        szToken[nTokenSize-1] = '\0';
    }

    return MOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_DumpFile
| Purpose   : This function read the whole User Feature File and dump User Feature File
|             data to key linked list.
| Arguments : szFileName         [in]  User Feature File name.
|             pKeyList           [out] Key Linked list.
| Returns   : MOS_STATUS_SUCCESS           Operation success.
|             MOS_STATUS_USER_FEATURE_KEY_READ_FAILED  User Feature File can't be open as read.
|             MOS_STATUS_NO_SPACE          no space left for allocate
|             MOS_STATUS_UNKNOWN           unknown user feature type found in User Feature File
|             MOS_STATUS_INVALID_PARAMETER unknown items found in User Feature File
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_DumpFile(const char * const szFileName, MOS_PUF_KEYLIST* pKeyList)
{
    MOS_UF_KEY      *CurKey;
    MOS_UF_VALUE    *CurValue;
    char            szTmp[MAX_USERFEATURE_LINE_LENGTH];
    int32_t         iResult;
    size_t          nSize;
    int32_t         bFirst;
    int32_t         iCount;
    PFILE           File;
    int32_t         bEmpty;
    int32_t         iCurId;
    MOS_STATUS      eStatus;
    char            *tmpChar; // Used in the 64-bit case to read uint64_t

    CurValue  =  nullptr;
    nSize     =  0;
    bFirst    =  1;    // 1 stand for "is the first key".
    iCount    =  0;
    File      =  nullptr;
    bEmpty    =  0;
    iCurId    =  0;
    eStatus  =  MOS_STATUS_SUCCESS;

    CurKey = (MOS_UF_KEY*)MOS_AllocMemory(sizeof(MOS_UF_KEY));
    if (CurKey == nullptr)
    {
        return MOS_STATUS_NO_SPACE;
    }
    CurKey->ulValueNum       = 0;
    CurKey->pcKeyName[0]    = '\0';
    CurKey->pValueArray       = nullptr;

    if ( (File = fopen(szFileName, "r")) == nullptr)
    {
        MOS_FreeMemory(CurKey);
        return MOS_STATUS_USER_FEATURE_KEY_READ_FAILED;
    }
    while (feof(File) != EOF)
    {
        MOS_ZeroMemory(szTmp, MAX_USERFEATURE_LINE_LENGTH*sizeof(char ));
        if (MOS_FAILED(_UserFeature_ReadNextTokenFromFile(File, MAX_UF_LINE_STRING_FORMAT, szTmp)))
        {
            break;
        }

        // set szDumpData with extracted File content.
        iResult = strcmp(szTmp, UF_KEY_ID);
        if ( iResult == 0 )
        {
            // It is a new key starting!
            if (! bFirst )
            {
                // Add last key struct to contents when the key is not first.
                // otherwise, continue to load key struct data.
                CurKey->pValueArray   = CurValue;
                CurKey->ulValueNum   = iCount;
                if(_UserFeature_Add(pKeyList, CurKey) != MOS_STATUS_SUCCESS)
                {
                    // if the CurKey didn't be added in pKeyList, free it.
                    MOS_FreeMemory(CurKey);
                }
                CurKey = (MOS_UF_KEY*)MOS_AllocMemory(sizeof(MOS_UF_KEY));
                if (CurKey == nullptr)
                {
                    eStatus = MOS_STATUS_NO_SPACE;
                    break;
                }
            } // if (! bFirst )

            if (fscanf(File, "%x\n", &iCurId) <= 0)
            {
                break;
            }

            CurKey->UFKey = (void *)(intptr_t)iCurId;

            MOS_ZeroMemory(szTmp, MAX_USERFEATURE_LINE_LENGTH * sizeof(char));
            if (MOS_FAILED(_UserFeature_ReadNextTokenFromFile(File, MAX_UF_LINE_STRING_FORMAT, szTmp)))
            {
                break;
            }

            MOS_SecureStrcpy(CurKey->pcKeyName, MAX_USERFEATURE_LINE_LENGTH, szTmp);
            CurKey->ulValueNum = 0;

            // allocate capability length for valuearray.
            CurValue = (MOS_UF_VALUE*)MOS_AllocMemory(sizeof(MOS_UF_VALUE)*UF_CAPABILITY);
            if (CurValue == nullptr)
            {
                eStatus = MOS_STATUS_NO_SPACE;
                break;
            }
            bFirst = 0;
            iCount = 0;  // next key's array number.
            bEmpty = 1;
        } // if ( iResult == 0 )
        else // not a key
        {
            // Is it a value starting?
            iResult = strcmp(szTmp, UF_VALUE_ID);
            if ( iResult == 0 )
            {
                if (MOS_FAILED(_UserFeature_ReadNextTokenFromFile(File, MAX_UF_LINE_STRING_FORMAT, szTmp)))
                {
                    break;
                }

                if (CurValue == nullptr)
                {
                    break;
                }

                // Out of bounds technically based on how much memory we allocated
                if (iCount < 0 || iCount >= UF_CAPABILITY)
                {
                    eStatus = MOS_STATUS_USER_FEATURE_KEY_READ_FAILED;
                    break;
                }

                // Load value name;
                MOS_SecureStrcpy(CurValue[iCount].pcValueName, MAX_USERFEATURE_LINE_LENGTH, szTmp);

                // Load value type
                if (MOS_FAILED(_UserFeature_ReadNextTokenFromFile(File, MAX_UF_LINE_STRING_FORMAT, szTmp)))
                {
                    break;
                }

                CurValue[iCount].ulValueType = atoi(szTmp);

                // Load value buffer.
                switch ( CurValue[iCount].ulValueType )
                {
                case UF_DWORD: // 32-bit
                    if (MOS_FAILED(_UserFeature_ReadNextTokenFromFile(File, MAX_UF_LINE_STRING_FORMAT, szTmp)))
                    {
                        break;
                    }

                    CurValue[iCount].ulValueLen = sizeof(uint32_t);
                    CurValue[iCount].ulValueBuf = MOS_AllocMemory(sizeof(uint32_t));
                    if(CurValue[iCount].ulValueBuf == nullptr)
                    {
                        eStatus = MOS_STATUS_NO_SPACE;
                        break;
                    }
                    *(uint32_t*)(CurValue[iCount].ulValueBuf) = atoi(szTmp);
                    break;
                case UF_QWORD: // 64-bit
                    if (MOS_FAILED(_UserFeature_ReadNextTokenFromFile(File, MAX_UF_LINE_STRING_FORMAT, szTmp)))
                    {
                        break;
                    }

                    CurValue[iCount].ulValueLen = sizeof(uint64_t);
                    CurValue[iCount].ulValueBuf = MOS_AllocMemory(sizeof(uint64_t));
                    if(CurValue[iCount].ulValueBuf == nullptr)
                    {
                        eStatus = MOS_STATUS_NO_SPACE;
                        break;
                    }
                    tmpChar = &szTmp[0];
                    *(uint64_t*)(CurValue[iCount].ulValueBuf) = strtoll(tmpChar,&tmpChar,0);
                    break;
                case UF_SZ:
                case UF_MULTI_SZ:
                    if (MOS_FAILED(_UserFeature_ReadNextTokenFromFile(File, MAX_UF_LINE_STRING_FORMAT, szTmp)))
                    {
                        break;
                    }

                    nSize = strlen(szTmp);
                    CurValue[iCount].ulValueLen = (nSize+1)*sizeof(char );
                    CurValue[iCount].ulValueBuf = MOS_AllocMemory(nSize+1);
                    if(CurValue[iCount].ulValueBuf == nullptr)
                    {
                        eStatus = MOS_STATUS_NO_SPACE;
                        break;
                    }
                    MOS_ZeroMemory(CurValue[iCount].ulValueBuf, nSize+1);
                    MOS_SecureMemcpy(CurValue[iCount].ulValueBuf, nSize, szTmp, nSize);
                    break;
                default:
                    eStatus = MOS_STATUS_UNKNOWN;
                }
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    break;
                }

                iCount ++; // do the error checking near the top

            } // if ( iResult == 0 )
            else   // It is not a value starting, it's bad User Feature File.
            {
                int32_t iResult = strcmp(szTmp, "");
                if ( !iResult )
                {
                    continue;
                }
                else
                {
                    eStatus =  MOS_STATUS_INVALID_PARAMETER;
                    break;
                }
            } // else ( iResult == 0 )
        }
    } // while (feof(File) != EOF)

    if (eStatus == MOS_STATUS_SUCCESS)
    {
        if ( bEmpty && (strlen(CurKey->pcKeyName) > 0) &&
            (CurKey->ulValueNum == 0) )
        {
            CurKey->pValueArray   = CurValue;
            CurKey->ulValueNum   = iCount;
            if(_UserFeature_Add(pKeyList, CurKey) != MOS_STATUS_SUCCESS)
            {
                // if the CurKey didn't be added in pKeyList, free it.
                for (uint32_t i = 0; i < iCount; i++)
                {
                    if (CurValue)
                    {
                        MOS_FreeMemory(CurValue[i].ulValueBuf);
                    }
                }
                MOS_FreeMemory(CurValue);
                MOS_FreeMemory(CurKey);
            }
        }
        else
        {
            for (uint32_t i = 0; i < iCount; i++)
            {
                if (CurValue)
                {
                    MOS_FreeMemory(CurValue[i].ulValueBuf);
                }
            }
            MOS_FreeMemory(CurValue);
            MOS_FreeMemory(CurKey);
        }
    }
    else
    {
        for (uint32_t i = 0; i < iCount; i++)
        {
            if (CurValue)
            {
                MOS_FreeMemory(CurValue[i].ulValueBuf);
            }
        }
        MOS_FreeMemory(CurValue);
        MOS_FreeMemory(CurKey);
    }
    fclose(File);
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_DumpDataToFile
| Purpose   : This function dump key linked list data to File.
| Arguments : szFileName             [in] A handle to the File.
|             pKeyList               [in] Reserved, any LPDWORD type value.
| Returns   : MOS_STATUS_SUCCESS                        Operation success.
|             MOS_STATUS_USER_FEATURE_KEY_WRITE_FAILED  File can't be written.
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_DumpDataToFile(const char *szFileName, MOS_PUF_KEYLIST pKeyList)
{
    int32_t           iResult;
    PFILE             File;
    MOS_PUF_KEYLIST   pKeyTmp;
    int32_t           j;

    File = fopen(szFileName, "w+");
    if ( !File )
    {
        return MOS_STATUS_USER_FEATURE_KEY_WRITE_FAILED;
    }

    for (pKeyTmp = pKeyList; pKeyTmp; pKeyTmp = pKeyTmp->pNext)
    {
        fprintf(File, "%s\n", UF_KEY_ID);
        fprintf(File,  "\t0x%.8x\n", (uint32_t)(uintptr_t)pKeyTmp->pElem->UFKey);
        fprintf(File,  "\t%s\n", pKeyTmp->pElem->pcKeyName);
        for ( j = 0; j < (int32_t)pKeyTmp->pElem->ulValueNum; j ++ )
        {
            fprintf(File, "\t\t%s\n", UF_VALUE_ID);
            if ( strlen(pKeyTmp->pElem->pValueArray[j].pcValueName) > 0 )
            {
                fprintf(File, "\t\t\t%s\n",
                    pKeyTmp->pElem->pValueArray[j].pcValueName);
            }
            fprintf(File, "\t\t\t%d\n", pKeyTmp->pElem->pValueArray[j].ulValueType);
            if (pKeyTmp->pElem->pValueArray[j].ulValueBuf != nullptr)
            {
                switch (pKeyTmp->pElem->pValueArray[j].ulValueType)
                {
                case UF_SZ:
                    fprintf(File,  "\t\t\t%s\n",
                        (char *)(pKeyTmp->pElem->pValueArray[j].ulValueBuf));
                    break;
                case UF_DWORD:
                case UF_QWORD:
                    fprintf(File, "\t\t\t%d\n",
                        *(uint32_t*)(pKeyTmp->pElem->pValueArray[j].ulValueBuf));
                    break;
                default:
                    fprintf(File, "\t\t\t%s\n",
                        (char *)(pKeyTmp->pElem->pValueArray[j].ulValueBuf));
                    break;
                } //switch (pKeyTmp->pElem->pValueArray[j].ulValueType)
            }
        } // for ( j = 0; j < (int32_t)pKeyTmp->pElem->ulValueNum; j ++ )
    } //for (pKeyTmp = pKeyList; pKeyTmp; pKeyTmp = pKeyTmp->pNext)
    fclose(File);
    MOS_UserFeatureNotifyChangeKeyValue(nullptr, false, nullptr, true);

    return MOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_FreeKeyList
| Purpose   : Free key list
| Arguments : pKeyList           [in] key list to be free.
| Returns   : None
| Comments  :
\---------------------------------------------------------------------------*/
static void _UserFeature_FreeKeyList(MOS_PUF_KEYLIST pKeyList)
{
    MOS_PUF_KEYLIST     pKeyTmp;
    MOS_PUF_KEYLIST     pKeyTmpNext;
    uint32_t            i;

    pKeyTmp = pKeyList;
    while(pKeyTmp)
    {
        pKeyTmpNext = pKeyTmp->pNext;
        for(i=0;i<pKeyTmp->pElem->ulValueNum;i++)
        {
            MOS_FreeMemory(pKeyTmp->pElem->pValueArray[i].ulValueBuf);
        }
        MOS_FreeMemory(pKeyTmp->pElem->pValueArray);
        MOS_FreeMemory(pKeyTmp->pElem);
        MOS_FreeMemory(pKeyTmp);
        pKeyTmp = pKeyTmpNext;
    }
    return;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_SetValue
| Purpose   : Modify or add a value of the specified user feature key.
| Arguments : strKey         [in] Pointer to user feature key name.
|             pcValueName    [in] Pointer to a string containing the name of
|                                 the value to set. If a value with this name
|                                 is not already present in the key, the
|                                 function adds it to the key.
|             uiValueType    [in] Type of information to be stored.
|             szValueData    [in] Pointer to a null-terminated string
|                                 containing the data to set for the default
|                                 value of the specified key
|             uiValueDataLen [in] Size of the string pointed to by the
|                                 szValueData parameter, not including the
|                                 terminating null character, in bytes
| Returns   : MOS_STATUS_SUCCESS           function success
|             MOS_STATUS_INVALID_PARAMETER invalid paramater
|             MOS_STATUS_USER_FEATURE_KEY_READ_FAILED  User Feature File can't be open as read.
|             MOS_STATUS_NO_SPACE          no space left for allocate
|             MOS_STATUS_UNKNOWN           unknown user feature type found in User Feature File
|             MOS_STATUS_INVALID_PARAMETER unknown items found in User Feature File
|             MOS_STATUS_USER_FEATURE_KEY_WRITE_FAILED  User Feature File can't be written.
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_SetValue(
    char * const        strKey,
    const char * const  pcValueName,
    uint32_t            uiValueType,
    void                *pData,
    int32_t             nDataSize)
{
    MOS_UF_KEY          NewKey;
    MOS_UF_VALUE        NewValue;
    MOS_STATUS          eStatus;
    MOS_PUF_KEYLIST     pKeyList;

    eStatus   = MOS_STATUS_UNKNOWN;
    pKeyList   = nullptr;

    if ( (strKey== nullptr) || (pcValueName == nullptr) )
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    MOS_ZeroMemory(NewValue.pcValueName, MAX_USERFEATURE_LINE_LENGTH);
    MOS_SecureStrcpy(NewValue.pcValueName, MAX_USERFEATURE_LINE_LENGTH, pcValueName);
    NewValue.ulValueType    = uiValueType;
    if( NewValue.ulValueType == UF_DWORD)
    {
        NewValue.ulValueLen = sizeof(uint32_t);
    }
    else
    {
        NewValue.ulValueLen = nDataSize;
    }
    NewValue.ulValueBuf     = pData;

    MOS_ZeroMemory(NewKey.pcKeyName, MAX_USERFEATURE_LINE_LENGTH);
    MOS_SecureStrcpy(NewKey.pcKeyName, MAX_USERFEATURE_LINE_LENGTH, strKey);
    NewKey.pValueArray = &NewValue;
    NewKey.ulValueNum = 1;

    if ( (eStatus = _UserFeature_DumpFile(szUserFeatureFile, &pKeyList)) != MOS_STATUS_SUCCESS )
    {
        _UserFeature_FreeKeyList(pKeyList);
        return eStatus;
    }

    if ( ( eStatus = _UserFeature_Set(&pKeyList, NewKey)) == MOS_STATUS_SUCCESS )
    {
        eStatus = _UserFeature_DumpDataToFile(szUserFeatureFile, pKeyList);
    }

    _UserFeature_FreeKeyList(pKeyList);
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_QueryValue
| Purpose   : The QueryValue function retrieves the type and data for a
|             specified value name associated with a special user feature key.
| Arguments : strKey         [in]  Pointer to user feature key name.
|             pcValueName    [in]  Pointer to a string containing the name
|                                  of the value to query.
|             uiValueType    [out] Output Value's type
|             pData          [out] Output value's content
|             nDataSize      [out] Output the size of value's content.
| Returns   : MOS_STATUS_SUCCESS           function success
|             MOS_STATUS_INVALID_PARAMETER invalid paramater
|             MOS_STATUS_USER_FEATURE_KEY_READ_FAILED  User Feature File can't be open as read.
|             MOS_STATUS_NO_SPACE          no space left for allocate
|             MOS_STATUS_UNKNOWN           Can't find key or value in User Feature File.
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_QueryValue(
    char * const        strKey,
    const char * const  pcValueName,
    uint32_t            *uiValueType,
    void                *pData,
    int32_t             *nDataSize)
{
    MOS_UF_KEY          NewKey;
    MOS_UF_VALUE        NewValue;
    size_t              nKeyLen, nValueLen;
    MOS_STATUS          eStatus;
    MOS_PUF_KEYLIST     pKeyList;
    char                strTempKey[MAX_USERFEATURE_LINE_LENGTH];
    char                strTempValueName[MAX_USERFEATURE_LINE_LENGTH];

    eStatus   = MOS_STATUS_UNKNOWN;
    pKeyList   = nullptr;

    if ( (strKey == nullptr) || (pcValueName == nullptr))
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }
    MOS_ZeroMemory(NewValue.pcValueName, MAX_USERFEATURE_LINE_LENGTH);
    MOS_SecureStrcpy(NewValue.pcValueName, MAX_USERFEATURE_LINE_LENGTH, pcValueName);
    NewValue.ulValueBuf     = pData;

    MOS_ZeroMemory(NewKey.pcKeyName, MAX_USERFEATURE_LINE_LENGTH);
    MOS_SecureStrcpy(NewKey.pcKeyName, MAX_USERFEATURE_LINE_LENGTH, strKey);
    NewKey.pValueArray = &NewValue;
    NewKey.ulValueNum = 1;

    if ( (eStatus = _UserFeature_DumpFile(szUserFeatureFile, &pKeyList)) == MOS_STATUS_SUCCESS)
    {
        if ( (eStatus = _UserFeature_Query(pKeyList, &NewKey)) == MOS_STATUS_SUCCESS )
        {
            if(uiValueType != nullptr)
            {
                *uiValueType = NewKey.pValueArray[0].ulValueType;
            }
            if (nDataSize != nullptr)
            {
                *nDataSize   = NewKey.pValueArray[0].ulValueLen;
            }
        }
    }
    _UserFeature_FreeKeyList(pKeyList);

    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_GetKeyIdbyName
| Purpose   : Get ID of the user feature key bu its name
| Arguments : pcKeyName      [in]  Pointer to user feature key name.
|             pUFKey         [out] A UFKEY pointer to store returned UFKey
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_GetKeyIdbyName(const char  *pcKeyName, void **pUFKey)
{
    MOS_PUF_KEYLIST     pKeyList;
    int32_t             iResult;
    MOS_STATUS          eStatus;
    MOS_PUF_KEYLIST     pTempNode;

    pKeyList   = nullptr;
    iResult    = -1;

    if ( (eStatus = _UserFeature_DumpFile(szUserFeatureFile, &pKeyList)) !=
        MOS_STATUS_SUCCESS )
    {
        _UserFeature_FreeKeyList(pKeyList);
        return eStatus;
    }

    eStatus   = MOS_STATUS_INVALID_PARAMETER;

    for(pTempNode=pKeyList; pTempNode; pTempNode=pTempNode->pNext)
    {
        iResult = strcmp(pTempNode->pElem->pcKeyName, pcKeyName);
        if ( iResult == 0 )
        {
            *pUFKey = pTempNode->pElem->UFKey;
            eStatus = MOS_STATUS_SUCCESS;
            break;
        }
    }
    _UserFeature_FreeKeyList(pKeyList);

    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : _UserFeature_GetKeyNamebyId
| Purpose   : Get name of the user feature key bu its ID
| Arguments : UFKey      [in]  ID of the user feature key
|             pcKeyName  [out] To store user feature key name.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
static MOS_STATUS _UserFeature_GetKeyNamebyId(void  *UFKey, char  *pcKeyName)
{
    MOS_PUF_KEYLIST     pKeyList;
    MOS_PUF_KEYLIST     pTempNode;
    MOS_STATUS          eStatus;

    pKeyList   = nullptr;

    switch((uintptr_t)UFKey)
    {
    case UFKEY_INTERNAL:
        MOS_SecureStrcpy(pcKeyName, MAX_USERFEATURE_LINE_LENGTH, USER_FEATURE_KEY_INTERNAL);
        eStatus = MOS_STATUS_SUCCESS;
        break;
    case UFKEY_EXTERNAL:
        MOS_SecureStrcpy(pcKeyName, MAX_USERFEATURE_LINE_LENGTH, USER_FEATURE_KEY_EXTERNAL);
        eStatus = MOS_STATUS_SUCCESS;
        break;
    default:
        if ( (eStatus = _UserFeature_DumpFile(szUserFeatureFile, &pKeyList)) !=
            MOS_STATUS_SUCCESS )
        {
            _UserFeature_FreeKeyList(pKeyList);
            return eStatus;
        }

        eStatus   = MOS_STATUS_UNKNOWN;

        for(pTempNode=pKeyList;pTempNode;pTempNode=pTempNode->pNext)
        {
            if(pTempNode->pElem->UFKey == UFKey)
            {
                MOS_SecureStrcpy(pcKeyName, MAX_USERFEATURE_LINE_LENGTH, pTempNode->pElem->pcKeyName);
                eStatus = MOS_STATUS_SUCCESS;
                break;
            }
        }
        _UserFeature_FreeKeyList(pKeyList);
        break;
    }

    return eStatus;

}

/*----------------------------------------------------------------------------
| Name      : MOS_CheckMountStatus
| Purpose   : check mount status
| Arguments : pKeyWord   [in]  Keyword for the Mountpoint
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_CheckMountStatus(char  *pKeyWord)
{
    char        sPartitionPath[MAX_UF_PATH] = {'\0'};
    char        sMountPoint[MAX_UF_PATH] = {'\0'};
    char        sSystemType[MAX_UF_PATH] = {'\0'};
    char        sTemp0[MAX_UF_PATH] = {'\0'};
    char        sTemp1[MAX_UF_PATH] = {'\0'};
    char        sTemp2[MAX_UF_PATH] = {'\0'};
    FILE*       file;
    MOS_STATUS  eStatus = MOS_STATUS_UNKNOWN;

    file = fopen("/proc/mounts", "r");
    MOS_OS_CHK_NULL(file);
    MOS_OS_CHK_NULL(pKeyWord);

    while( fscanf( file, "%255s %255s %255s %255s %255s %255s\n", sPartitionPath, sMountPoint, sSystemType, sTemp0, sTemp1, sTemp2 ) > 0 )
    {
        if( strcmp(sSystemType, pKeyWord) == 0 )
        {
            eStatus = MOS_STATUS_SUCCESS;
            break;
        }
        if( strcmp(sMountPoint, pKeyWord) == 0 )
        {
            eStatus = MOS_STATUS_SUCCESS;
            break;
        }
    }
finish:
    if (file != nullptr)
    {
        fclose(file);
    }
    return eStatus;
}
#ifdef ANDROID
/*----------------------------------------------------------------------------
| Name      : MOS_Strip_Chars
| Purpose   : Strip some characters from a string
| Arguments : pstorestr  [out] To store a striped string.
|             pstring    [in]  string needed to be striped.
|             pchars     [in]  stripped keyword.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is an error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_StripChars(char  *pstorestr, const char *pstring, const char *pchars)
{
    int32_t       counter = 0;
    MOS_STATUS    eStatus = MOS_STATUS_SUCCESS;

    MOS_OS_CHK_NULL(pstring);
    MOS_OS_CHK_NULL(pchars);

    for ( ; *pstring; pstring++)
    {
        if (!strchr(pchars, *pstring))
        {
            pstorestr[ counter ] = *pstring;
            ++ counter;
        }
    }
    pstorestr[counter] = 0;
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_InitAndroidPropInfo
| Purpose   : Init Android Property Info
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_InitAndroidPropInfo()
{
    char                            prop[MOS_USER_CONTROL_MAX_DATA_SIZE];
    MOS_STATUS                      eStatus = MOS_STATUS_UNKNOWN;
    int32_t                         ret;
    int32_t                         iUFKeyEnable;
    MOS_USER_FEATURE_VALUE_DATA     UserFeatureData;

    eStatus = MOS_CheckMountStatus((char *)"/system");
    if (eStatus == MOS_STATUS_SUCCESS)
    {
        eStatus = MOS_STATUS_UNKNOWN;
        if (property_get("debug.LibVa.RegKeyEnable", prop, nullptr) > 0)
        {
            if (sscanf(prop, "%d\n", &iUFKeyEnable) > 0)
            {
                if (iUFKeyEnable == 1)
                {
                    eStatus = MOS_STATUS_SUCCESS;
                }
            }
        }
    }
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_GetAndroidPropPath
| Purpose   : get AndroidProp path
| Arguments : pPath         [out] store the path
|             pUserFeature  [in]  User Feature data for input User Feature Key
|             FuncType      [in]  Read/Write Type
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_GetAndroidPropPath(
    char                        *pPath,
    PMOS_USER_FEATURE_VALUE     pUserFeature,
    LINUX_UF_FUNC_TYPE          FuncType)
{

    char        sPath[MAX_UF_PATH];
    char        sKey[MAX_UF_PATH];
    char        sFuncType[MAX_UF_PATH];
    char        pPrefixPath[MAX_UF_PATH];
    char        sUFName[MAX_UF_PATH];
    MOS_STATUS  eStatus = MOS_STATUS_SUCCESS;
    MOS_OS_CHK_NULL(pUserFeature);
    MOS_OS_CHK_NULL(pPath);

    MOS_ZeroMemory(sPath, MAX_UF_PATH);
    MOS_ZeroMemory(sKey,  MAX_UF_PATH);
    switch(pUserFeature->Type)
    {
    case MOS_USER_FEATURE_TYPE_USER:
        MOS_SecureStrcpy(sKey, MAX_UF_PATH, UFINT_PATH_LINUX);
        break;
    case MOS_USER_FEATURE_TYPE_SYSTEM:
        MOS_SecureStrcpy(sKey, MAX_UF_PATH, UFEXT_PATH_LINUX);
        break;
    default:
        MOS_SecureStrcpy(sKey, MAX_UF_PATH, UFINT_PATH_LINUX);
        break;
    }// switch

    MOS_ZeroMemory(sFuncType, MAX_UF_PATH);
    switch(FuncType)
    {
    case LINUX_UF_FUNCTYPE_READ:
        MOS_SecureStrcpy(sFuncType, MAX_UF_PATH, pUserFeature->pcPath);
        break;
    case LINUX_UF_FUNCTYPE_WRITE:
        MOS_SecureStrcpy(sFuncType, MAX_UF_PATH, pUserFeature->pcWritePath);
        break;
    default:
        MOS_SecureStrcpy(sFuncType, MAX_UF_PATH, pUserFeature->pcPath);
        break;
    }// switch

    MOS_OS_CHK_STATUS(MOS_StripChars(sUFName,pUserFeature->pValueName," "));
    snprintf(
        sPath,
        sizeof(sPath),
        "%s.%s.%s",
        sKey,
        sFuncType,
        sUFName);

    MOS_SecureMemcpy(pPath, strlen(sPath)+1, sPath, strlen(sPath)+1);
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_AndroidPropOpenKey
| Purpose   : open a file for AndroidProp
| Arguments : pPath       [in]
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_AndroidPropOpenKey(
    char                *pPath)
{
    MOS_STATUS      eStatus = MOS_STATUS_FILE_OPEN_FAILED;
    char            prop[MOS_USER_CONTROL_MAX_DATA_SIZE];
    MOS_OS_CHK_NULL(pPath);

    if (property_get(pPath, prop, nullptr) > 0)
    {
        eStatus = MOS_STATUS_SUCCESS;
    }
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_AndroidPropWriteValue
| Purpose   : write a AndroidProp User Feature Data Value
| Arguments : pPath       [in]
|             pUserData   [in]  user feature key write value
|             ValueType   [in]  Type of Data
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_AndroidPropWriteValue(
    char                                *pPath,
    PMOS_USER_FEATURE_VALUE_DATA        pUserData,
    MOS_USER_FEATURE_VALUE_TYPE         ValueType)
{
    MOS_STATUS  eStatus = MOS_STATUS_USER_FEATURE_KEY_WRITE_FAILED;
    char        prop[MOS_USER_CONTROL_MAX_DATA_SIZE];
    int32_t     ret = 0;
    MOS_OS_CHK_NULL(pPath);
    MOS_OS_CHK_NULL(pUserData);

    switch(ValueType)
    {
     case MOS_USER_FEATURE_VALUE_TYPE_BOOL:
        ret = snprintf(prop, sizeof(prop), "%d\n", pUserData->bData);
        break;
    case MOS_USER_FEATURE_VALUE_TYPE_INT32:
        ret = snprintf(prop, sizeof(prop), "%d\n", pUserData->i32Data);
        break;
    case MOS_USER_FEATURE_VALUE_TYPE_UINT32:
        ret = snprintf(prop, sizeof(prop), "%u\n", pUserData->u32Data);
        break;
    case MOS_USER_FEATURE_VALUE_TYPE_INT64:
        ret = snprintf(prop, sizeof(prop), "%" MOSd64 "\n", pUserData->i64Data);
        break;
    case MOS_USER_FEATURE_VALUE_TYPE_UINT64:
        ret = snprintf(prop, sizeof(prop), "%" MOSu64 "\n", pUserData->u64Data);
        break;
    case MOS_USER_FEATURE_VALUE_TYPE_STRING:
        if ((pUserData->StringData.pStringData != nullptr) && (strlen(pUserData->StringData.pStringData) != 0))
        {
            ret = snprintf(prop, sizeof(prop), "%s\n", pUserData->StringData.pStringData);
        }
        break;
    default:
        break;
    }
    if (ret > 0)
    {
        ret = property_set(pPath, prop);
        if (ret == 0)
        {
            eStatus = MOS_STATUS_SUCCESS;
        }
    }
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_AndroidPropCreateKey
| Purpose   : set default value to AndroidProp User Feature Key according to userfeature
| Arguments : pUserFeature   [in]  value for ceated key
|             FuncType       [in]  Type of function
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_AndroidPropCreateKey(
    PMOS_USER_FEATURE_VALUE     pUserFeature,
    LINUX_UF_FUNC_TYPE          FuncType)
{
    char                        sPath[MAX_UF_PATH];
    MOS_STATUS                  eStatus = MOS_STATUS_DIR_CREATE_FAILED;
    MOS_USER_FEATURE_VALUE_DATA UserFeatureData;
    MOS_USER_FEATURE_VALUE_TYPE ValueType = MOS_USER_FEATURE_VALUE_TYPE_INVALID;
    char                        prop[MOS_USER_CONTROL_MAX_DATA_SIZE];
    int32_t                     ret;

    MOS_OS_CHK_NULL(pUserFeature);
    MOS_ZeroMemory(&UserFeatureData, sizeof(UserFeatureData));

    // create key
    MOS_ZeroMemory(sPath, MAX_UF_PATH);
    MOS_OS_CHK_STATUS(MOS_GetAndroidPropPath(sPath, pUserFeature, FuncType));
    // set the default Data and Type value according to default value and type in pUserFeature.
    MOS_OS_CHK_STATUS(MOS_AndroidPropWriteValue(sPath, &pUserFeature->Value, pUserFeature->ValueType));
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_AndroidPropReadValue
| Purpose   : read a AndroidProp User Feature Data Value
| Arguments : pPath       [in]
|             pUserData   [out] To store user feature key value.
|             ValueType   [in]  Type of Data
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_AndroidPropReadValue(
    char                            *pPath,
    PMOS_USER_FEATURE_VALUE_DATA    pUserData,
    MOS_USER_FEATURE_VALUE_TYPE     ValueType)
{
    MOS_USER_FEATURE_VALUE_DATA UserData;
    char                        pcTmpStr[MOS_USER_CONTROL_MAX_DATA_SIZE];
    MOS_STATUS                  eStatus = MOS_STATUS_USER_FEATURE_KEY_READ_FAILED;
    char                        prop[MOS_USER_CONTROL_MAX_DATA_SIZE];
    int32_t                     ret = 0;

    MOS_OS_CHK_NULL(pPath);
    MOS_OS_CHK_NULL(pUserData);

    MOS_ZeroMemory(&UserData, sizeof(UserData));

    if (property_get(pPath, prop, nullptr) > 0)
    {
        switch(ValueType)
        {
         case MOS_USER_FEATURE_VALUE_TYPE_BOOL:
            ret = sscanf(prop, "%d\n", &pUserData->bData);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_INT32:
            ret = sscanf(prop, "%d\n", &pUserData->i32Data);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_UINT32:
            ret = sscanf(prop, "%u\n", &pUserData->u32Data);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_INT64:
            ret = sscanf(prop, "%" MOSd64 "\n", &pUserData->i64Data);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_UINT64:
            ret = sscanf(prop, "%" MOSu64 "\n", &pUserData->u64Data);
        break;
        case MOS_USER_FEATURE_VALUE_TYPE_STRING:
            if( sscanf( prop, "%s\n", pcTmpStr) > 0 )
            {
                if (strlen(pcTmpStr) > 0)
                {
                    MOS_SafeFreeMemory(pUserData->StringData.pStringData);
                    pUserData->StringData.pStringData = (char *)MOS_AllocAndZeroMemory(strlen(pcTmpStr)+1);
                    MOS_SecureMemcpy(pUserData->StringData.pStringData, strlen(pcTmpStr), pcTmpStr, MOS_MIN(strlen(pcTmpStr), MOS_USER_CONTROL_MAX_DATA_SIZE));
                    pUserData->StringData.uSize = strlen(pcTmpStr);
                    ret = pUserData->StringData.uSize;
                }
            }
            break;
        default:
            break;
        }
    }
    if (ret > 0)
    {
        eStatus = MOS_STATUS_SUCCESS;
    }
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_UserFeatureOpenKey_AndroidProp
| Purpose   : Opens the specified user feature key.
| Arguments : UFKey        [in]  A handle to an open user feature key.
|             lpSubKey     [in]  The name of the user feature subkey to be opened.
|             ulOptions    [in]  This parameter is reserved and must be zero.
|             samDesired   [in]  Reserved, could be any REGSAM type value
|             phkResult    [out] A pointer to a variable that receives a handle
|                                to the opened key.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_UserFeatureOpenKey_AndroidProp(
    void       *UFKey,
    const char *lpSubKey,
    uint32_t   ulOptions,
    uint32_t   samDesired,
    void       **phkResult)
{
    char                            pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;
    PMOS_USER_FEATURE_VALUE         pUserFeature = nullptr;
    char                            sPath[MAX_UF_PATH];
    LINUX_UF_FUNC_TYPE              FuncType = LINUX_UF_FUNCTYPE_INVALID;
    MOS_UNUSED(UFKey);
    MOS_UNUSED(ulOptions);

    MOS_OS_CHK_NULL(lpSubKey);
    pUserFeature = (PMOS_USER_FEATURE_VALUE)*phkResult;
    MOS_OS_CHK_NULL(pUserFeature);
    if( strcmp(lpSubKey, pUserFeature->pcWritePath) == 0 )
    {
        FuncType = LINUX_UF_FUNCTYPE_WRITE;
    }
    else if( strcmp(lpSubKey, pUserFeature->pcPath) == 0 )
    {
        FuncType = LINUX_UF_FUNCTYPE_READ;
    }
    MOS_ZeroMemory(sPath, MAX_UF_PATH);
    MOS_OS_CHK_STATUS(MOS_GetAndroidPropPath(sPath, pUserFeature, FuncType));
    if (MOS_AndroidPropOpenKey(sPath) != MOS_STATUS_SUCCESS)
    {
        // No Sub Key return directly
        eStatus = MOS_STATUS_FILE_OPEN_FAILED;
        // KEY_WRITE
        if (samDesired == KEY_WRITE)
        {
            if (MOS_AndroidPropCreateKey(pUserFeature, FuncType) != MOS_STATUS_SUCCESS)
            {
                eStatus = MOS_STATUS_DIR_CREATE_FAILED;
            }
        }
        else
        {
            eStatus = MOS_STATUS_FILE_OPEN_FAILED;
        }
    }
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_UserFeatureGetValue_AndroidProp
| Purpose   : Retrieves the type and data for the specified user feature value.
| Arguments : UFKey     [in]  A handle to an open user feature key.
|             lpSubKey  [in]  The name of the user feature key. This key must be a
|                             subkey of the key specified by the UFKey parameter
|             lpValue   [in]  The name of the user feature value.
|             dwFlags   [in]  Reserved, could be any uint32_t type value
|             pdwType   [out] A pointer to a variable that receives a code
|                             indicating the type of data stored in the
|                             specified value.
|             pvData    [out] A pointer to a buffer that receives the value's
|                             data.
|             pcbData   [out] A pointer to a variable that specifies the size
|                             of the buffer pointed to by the pvData parameter,
|                             in bytes.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_UserFeatureGetValue_AndroidProp(
    void       *UFKey,
    const char *lpSubKey,
    const char *lpValue,
    uint32_t   dwFlags,
    uint32_t   *pdwType,
    void       *pvData,
    uint32_t   *pcbData)
{
    char                        pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    int32_t                     dData;
    int32_t                     index = 0;
    PMOS_USER_FEATURE_VALUE     pSettingsValue;
    PMOS_USER_FEATURE_VALUE     pUserFeature = nullptr;
    char                        sPath[MAX_UF_PATH];
    MOS_USER_FEATURE_VALUE_DATA UserFeatureData;
    MOS_STATUS                  eStatus = MOS_STATUS_SUCCESS;
    MOS_UNUSED(lpSubKey);
    MOS_UNUSED(lpValue);
    MOS_UNUSED(dwFlags);
    MOS_UNUSED(pdwType);

    if(UFKey == nullptr)
    {
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        goto finish;
    }
    pUserFeature = (PMOS_USER_FEATURE_VALUE)UFKey;

    MOS_ZeroMemory(sPath, MAX_UF_PATH);
    MOS_OS_CHK_STATUS(MOS_GetAndroidPropPath(sPath, pUserFeature, LINUX_UF_FUNCTYPE_READ));

    // Read Type
    MOS_ZeroMemory(&UserFeatureData, sizeof(UserFeatureData));
    if (MOS_AndroidPropReadValue(sPath, &UserFeatureData, pUserFeature->ValueType) == MOS_STATUS_SUCCESS)
    {
        // get key content from user feature
        switch(pUserFeature->ValueType)
        {
        case MOS_USER_FEATURE_VALUE_TYPE_BINARY:
            *(int32_t*)pvData = UserFeatureData.bData;
            *(uint32_t*)pcbData = sizeof(int32_t);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_INT32:
            *(int32_t*)pvData = UserFeatureData.i32Data;
            *(uint32_t*)pcbData = sizeof(int32_t);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_INT64:
            *(int64_t*)pvData = UserFeatureData.i64Data;
            *(uint32_t*)pcbData = sizeof(int64_t);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_UINT32:
            *(uint32_t*)pvData = UserFeatureData.u32Data;
            *(uint32_t*)pcbData = sizeof(uint32_t);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_UINT64:
            *(uint64_t*)pvData = UserFeatureData.u64Data;
            *(uint32_t*)pcbData = sizeof(uint64_t);
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_STRING:
            MOS_SecureMemcpy(pvData, UserFeatureData.StringData.uSize, UserFeatureData.StringData.pStringData, UserFeatureData.StringData.uSize);
            MOS_SafeFreeMemory(UserFeatureData.StringData.pStringData);
            *(uint32_t*)pcbData = UserFeatureData.StringData.uSize;
            break;
        default:
            break;
        }// switch
    }
    else
    {
       eStatus = MOS_STATUS_FILE_NOT_FOUND;
    }
finish:
    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_UserFeatureSetValueEx_AndroidProp
| Purpose   : Sets the data and type of a specified value under a user feature key.
| Arguments : UFKey        [in] A handle to an open user feature key.
|             lpValueName  [in] The name of the user feature value.
|             Reserved     [in] This parameter is reserved and must be NULL.
|             dwType       [in] The type of data pointed to by the lpData
|                               parameter.
|             lpData       [in] The data to be stored.
|             cbData       [in] The size of the information pointed to by the
|                               lpData parameter, in bytes.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_UserFeatureSetValueEx_AndroidProp(
    void            *UFKey,
    const char      *lpValueName,
    uint32_t        Reserved,
    uint32_t        dwType,
    uint8_t         *lpData,
    uint32_t        cbData)
{
    char                        pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    int32_t                     dData;
    int32_t                     index = 0;
    uint32_t                    ui;
    PMOS_USER_FEATURE_VALUE     pUserFeature = nullptr;
    char                        sPath[MAX_UF_PATH];
    MOS_USER_FEATURE_VALUE_DATA UserFeatureData;
    MOS_USER_FEATURE_VALUE_TYPE ValueType = MOS_USER_FEATURE_VALUE_TYPE_INVALID;
    MOS_STATUS                  eStatus = MOS_STATUS_SUCCESS;
    MOS_UNUSED(lpValueName);
    MOS_UNUSED(Reserved);
    MOS_UNUSED(dwType);

    if(UFKey == nullptr)
    {
       eStatus = MOS_STATUS_INVALID_PARAMETER;
       goto finish;
    }
    pUserFeature = (PMOS_USER_FEATURE_VALUE)UFKey;
    for (ui = 0; ui < pUserFeature->uiNumOfValues; ui++)
    {
        // Check the Key exist or not
        MOS_ZeroMemory(sPath, MAX_UF_PATH);
        MOS_OS_CHK_STATUS(MOS_GetAndroidPropPath(sPath, pUserFeature, LINUX_UF_FUNCTYPE_WRITE));

        if (MOS_AndroidPropOpenKey(sPath) != MOS_STATUS_SUCCESS){
            // create the Key according to pFeatureValue->ValueType
            if( MOS_AndroidPropCreateKey(pUserFeature, LINUX_UF_FUNCTYPE_WRITE) != MOS_STATUS_SUCCESS )
            {
                eStatus = MOS_STATUS_DIR_CREATE_FAILED;
                goto finish;
            }
        }
        MOS_ZeroMemory(&UserFeatureData, sizeof(UserFeatureData));
        ValueType = (MOS_USER_FEATURE_VALUE_TYPE)pUserFeature->ValueType;
        switch(ValueType)
        {
        case MOS_USER_FEATURE_VALUE_TYPE_BINARY:
            UserFeatureData.bData =*(int32_t*)lpData ;
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_INT32:
            UserFeatureData.i32Data =*(int32_t*)lpData ;
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_INT64:
            UserFeatureData.i64Data =*(int64_t*)lpData;
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_UINT32:
            UserFeatureData.u32Data = *(uint32_t*)lpData;
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_UINT64:
            UserFeatureData.u64Data =*(uint64_t*)lpData;
            break;
        case MOS_USER_FEATURE_VALUE_TYPE_STRING:
            UserFeatureData.StringData.pStringData =(char *)lpData;
            UserFeatureData.StringData.uSize = cbData;
            break;
        default:
            break;
        }//switch
        if (MOS_AndroidPropWriteValue(sPath, &UserFeatureData, ValueType) != MOS_STATUS_SUCCESS)
        {
            eStatus = MOS_STATUS_USER_FEATURE_KEY_WRITE_FAILED;
            goto finish;
        }
    }
finish:
    return eStatus;
}
#endif

/*----------------------------------------------------------------------------
| Name      : MOS_UserFeatureOpenKey_File
| Purpose   : Opens the specified user feature key.
| Arguments : UFKey        [in]  A handle to an open user feature key.
|             lpSubKey     [in]  The name of the user feature subkey to be opened.
|             ulOptions    [in]  This parameter is reserved and must be zero.
|             samDesired   [in]  Reserved, could be any REGSAM type value
|             phkResult    [out] A pointer to a variable that receives a handle
|                                to the opened key.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_UserFeatureOpenKey_File(
    void       *UFKey,
    const char *lpSubKey,
    uint32_t   ulOptions,  // reserved
    uint32_t   samDesired,
    void       **phkResult)
{
    char           pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    MOS_STATUS     iRet;
    uintptr_t      h_key = (uintptr_t)UFKey;
    MOS_UNUSED(ulOptions);
    MOS_UNUSED(samDesired);

    if((h_key == 0) /*|| (lpSubKey == nullptr)*/ || (phkResult == nullptr))    //[SH]: subkey can be NULL???
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    MOS_ZeroMemory(pcKeyName, MAX_USERFEATURE_LINE_LENGTH*sizeof(char));
    switch(h_key)
    {
    case UFKEY_INTERNAL:
        MOS_SecureStrcpy(pcKeyName, MAX_USERFEATURE_LINE_LENGTH, USER_FEATURE_KEY_INTERNAL);
        break;
    case UFKEY_EXTERNAL:
        MOS_SecureStrcpy(pcKeyName, MAX_USERFEATURE_LINE_LENGTH, USER_FEATURE_KEY_EXTERNAL);
        break;
    default:
        break;
    }

    MOS_SecureStrcat(pcKeyName, sizeof(pcKeyName), lpSubKey);
    iRet =  _UserFeature_GetKeyIdbyName(pcKeyName, phkResult);

    return iRet;
}

/*----------------------------------------------------------------------------
| Name      : MOS_UserFeatureGetValue_File
| Purpose   : Retrieves the type and data for the specified user feature value.
| Arguments : UFKey     [in]  A handle to an open user feature key.
|             lpSubKey  [in]  The name of the user feature key. This key must be a
|                             subkey of the key specified by the UFKey parameter
|             lpValue   [in]  The name of the user feature value.
|             dwFlags   [in]  Reserved, could be any uint32_t type value
|             pdwType   [out] A pointer to a variable that receives a code
|                             indicating the type of data stored in the
|                             specified value.
|             pvData    [out] A pointer to a buffer that receives the value's
|                             data.
|             pcbData   [out] A pointer to a variable that specifies the size
|                             of the buffer pointed to by the pvData parameter,
|                             in bytes.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_UserFeatureGetValue_File(
    void       *UFKey,
    const char *lpSubKey,
    const char *lpValue,
    uint32_t   dwFlags,
    uint32_t   *pdwType,
    void       *pvData,
    uint32_t   *pcbData)
{
    char          pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    MOS_STATUS    eStatus;
    MOS_UNUSED(dwFlags);

    if(UFKey == nullptr)
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    eStatus = MOS_STATUS_UNKNOWN;
    MOS_ZeroMemory(pcKeyName, MAX_USERFEATURE_LINE_LENGTH * sizeof(char));
    if ( (eStatus = _UserFeature_GetKeyNamebyId(UFKey,pcKeyName)) != MOS_STATUS_SUCCESS)
    {
        return eStatus;
    }

    if(lpSubKey != nullptr)
    {
        MOS_SecureStrcat(pcKeyName, sizeof(pcKeyName), lpSubKey);
    }
    eStatus = _UserFeature_QueryValue(pcKeyName,
                                  lpValue,
                                  (uint32_t*)pdwType,
                                  pvData,
                                  (int32_t*)pcbData);

    return eStatus;
}

/*----------------------------------------------------------------------------
| Name      : MOS_UserFeatureSetValueEx_File
| Purpose   : Sets the data and type of a specified value under a user feature key.
| Arguments : UFKey        [in] A handle to an open user feature key.
|             lpValueName  [in] The name of the user feature value.
|             Reserved      in] This parameter is reserved and must be NULL.
|             dwType       [in] The type of data pointed to by the lpData
|                               parameter.
|             lpData       [in] The data to be stored.
|             cbData       [in] The size of the information pointed to by the
|                               lpData parameter, in bytes.
| Returns   : If the function succeeds, the return value is MOS_STATUS_SUCCESS.
|             If the function fails, the return value is a error code defined
|             in mos_utilities.h.
| Comments  :
\---------------------------------------------------------------------------*/
MOS_STATUS MOS_UserFeatureSetValueEx_File(
    void            *UFKey,
    const char      *lpValueName,
    uint32_t        Reserved,
    uint32_t        dwType,
    uint8_t         *lpData,
    uint32_t        cbData)
{
    char    pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    MOS_STATUS  eStatus;
    MOS_UNUSED(Reserved);

    if (UFKey == nullptr)
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }
    MOS_ZeroMemory(pcKeyName, MAX_USERFEATURE_LINE_LENGTH*sizeof(char));
    if ((eStatus = _UserFeature_GetKeyNamebyId(UFKey,pcKeyName)) != MOS_STATUS_SUCCESS)
    {
        return eStatus;
    }

    eStatus = _UserFeature_SetValue(pcKeyName,lpValueName,dwType,lpData,cbData);

    return eStatus;
}

MOS_STATUS MOS_UserFeatureOpenKey(
    void       *ufKey,
    const char *lpSubKey,
    uint32_t   ulOptions,
    uint32_t   samDesired,
    void       **phkResult,
    MOS_USER_FEATURE_KEY_PATH_INFO *ufInfo)
{
    return MosUtilities::MosUserFeatureOpenKey(
        ufKey,
        lpSubKey,
        ulOptions,
        samDesired,
        phkResult,
        ufInfo);
}

MOS_STATUS MOS_UserFeatureCloseKey(void  *UFKey)
{
    MOS_UNUSED(UFKey);
    //always return success, because we actually dong't have a key opened.
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_UserFeatureGetValue(
    void       *UFKey,
    const char *lpSubKey,
    const char *lpValue,
    uint32_t   dwFlags,
    uint32_t   *pdwType,
    void       *pvData,
    uint32_t   *pcbData)
{
    char          pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    MOS_STATUS    eStatus;

    if(UFKey == nullptr)
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    eStatus = MOS_STATUS_UNKNOWN;
    if (( pUFKeyOps != nullptr) && (pUFKeyOps->pfnUserFeatureGetValue != nullptr))
    {
        return pUFKeyOps->pfnUserFeatureGetValue(UFKey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData);
    }
    else
    {
        return MOS_UserFeatureGetValue_File(UFKey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData);
    }

}

MOS_STATUS MOS_UserFeatureQueryValueEx(
    void            *UFKey,
    char            *lpValueName,
    uint32_t        *lpReserved,
    uint32_t        *lpType,
    char            *lpData,
    uint32_t        *lpcbData)
{
    MOS_UNUSED(lpReserved);
    return MOS_UserFeatureGetValue(UFKey, "", lpValueName, 0, lpType, lpData, lpcbData);
}

MOS_STATUS MOS_UserFeatureSetValueEx(
    void            *UFKey,
    const char      *lpValueName,
    uint32_t        Reserved,
    uint32_t        dwType,
    uint8_t         *lpData,
    uint32_t        cbData)
{
    char        pcKeyName[MAX_USERFEATURE_LINE_LENGTH];
    MOS_STATUS  eStatus;

    if (UFKey == nullptr)
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if (dwType == UF_SZ || dwType == UF_MULTI_SZ)
    {
        if (lpData == nullptr || strlen((const char*)lpData) == 0)
        {
            MOS_OS_NORMALMESSAGE("NULL string, skip to report");
            return MOS_STATUS_SUCCESS;
        }
    }

    if (( pUFKeyOps != nullptr) && (pUFKeyOps->pfnUserFeatureSetValueEx!= nullptr))
    {
        return pUFKeyOps->pfnUserFeatureSetValueEx(UFKey, lpValueName, Reserved, dwType, lpData, cbData);
    }
    else
    {
        return MOS_UserFeatureSetValueEx_File(UFKey, lpValueName, Reserved, dwType, lpData, cbData);
    }
}

// Event Related Functions: Android does not support these
#ifndef ANDROID
MOS_STATUS MOS_UserFeatureNotifyChangeKeyValue(
    void                *UFKey,
    int32_t             bWatchSubtree,
    HANDLE              hEvent,
    int32_t             fAsynchronous)
{
    key_t          key;
    int32_t        semid;
    struct sembuf  operation[1] ;

    key = ftok(szUserFeatureFile,1);
    semid = semget(key,1,0);
    //change semaphore
    operation[0].sem_op  = 1;
    operation[0].sem_num = 0;
    operation[0].sem_flg = SEM_UNDO;
    semop(semid, operation, 1);

    return MOS_STATUS_SUCCESS;
}

HANDLE MOS_CreateEventEx(
    void                *lpEventAttributes,
    char                *lpName,
    uint32_t            dwFlags)
{
    int32_t     semid;
    key_t       key;
    union semun
    {
        int32_t val;
        struct semid_ds *Buf;
        unsigned short *array;
    } semctl_arg;

    semid = 0;

    //Generate a unique key, U can also supply a value instead
    key = ftok(szUserFeatureFile, 1);
    semid = semget(key,  1, 0666 | IPC_CREAT );
    semctl_arg.val = 0; //Setting semval to 0
    semctl(semid, 0, SETVAL, semctl_arg);

    HANDLE ret = reinterpret_cast<HANDLE>(semid);

    return ret;
}

int32_t MOS_UserFeatureWaitForSingleObject(
    PTP_WAIT*           phNewWaitObject,
    HANDLE              hObject,
    void                *Callback,
    void                *Context)
{
    int32_t                  iRet;
    int32_t                  semid;
    struct sembuf            operation[1];
    pid_t                    pid;
    MOS_UserFeatureCallback  pCallback;
    LARGE_INTEGER            largeInteger;

    pCallback = (MOS_UserFeatureCallback)Callback;

    iRet  = 0;

    largeInteger.QuadPart = (int64_t)hObject;

    semid = largeInteger.u.LowPart;

    if ((pid=fork()) == -1)
    {
        printf("error\n");
    }
    else if(pid == 0)
    {
        while(1)
        {
            operation[0].sem_op = -1;
            operation[0].sem_num = 0;
            //now waiting
            semop(semid, operation, 1);
            pCallback(Context, 0);
        }
        exit(0);
    }
    else
    {
        iRet = pid;
    }

    *phNewWaitObject = reinterpret_cast<PTP_WAIT>(iRet);

    return (iRet != 0);
}

int32_t MOS_UnregisterWaitEx(PTP_WAIT hWaitHandle)
{
    int32_t iPid;
    LARGE_INTEGER largeInteger;

    largeInteger.QuadPart = (int64_t)hWaitHandle;

    iPid = largeInteger.u.LowPart;
    kill(iPid,SIGKILL);
    return true;
}

/*----------------------------------------------------------------------------
| Name      : GMMDebugBreak
| Purpose   : Fix compiling issue for Gmmlib on debug mode
| Arguments : N/A
| Returns   : void
| Calls     : N/A
| Callers   : Several
\---------------------------------------------------------------------------*/
void GMMDebugBreak(const char  *file, const char  *function,const int32_t line)
{
    // Not required for media driver
    return;
}

/*----------------------------------------------------------------------------
| Name      : GMMPrintMessage
| Purpose   : Fix compiling issue for Gmmlib on debug mode
| Arguments : N/A
| Returns   : void
| Calls     : N/A
| Callers   : Several
\---------------------------------------------------------------------------*/
void GMMPrintMessage(int32_t debuglevel, const char  *function, ...)
{
    // Not Required for media driver
    return;
}

#else // ANDROID
MOS_STATUS MOS_UserFeatureNotifyChangeKeyValue(
    void                *UFKey,
    int32_t             bWatchSubtree,
    HANDLE              hEvent,
    int32_t             fAsynchronous)
{
    MOS_UNUSED(UFKey);
    MOS_UNUSED(bWatchSubtree);
    MOS_UNUSED(hEvent);
    MOS_UNUSED(fAsynchronous);
    return MOS_STATUS_SUCCESS;
}

HANDLE MOS_CreateEventEx(
    void                *lpEventAttributes,
    char                *lpName,
    uint32_t            dwFlags)
{
    MOS_UNUSED(lpEventAttributes);
    MOS_UNUSED(lpName);
    MOS_UNUSED(dwFlags);
    return (HANDLE)1;
}

int32_t MOS_UserFeatureWaitForSingleObject(
    PTP_WAIT*           phNewWaitObject,
    HANDLE              hObject,
    void                *Callback,
    void                *Context)
{
    MOS_UNUSED(phNewWaitObject);
    MOS_UNUSED(hObject);
    MOS_UNUSED(Callback);
    MOS_UNUSED(Context);
    return true;
}

int32_t MOS_UnregisterWaitEx(PTP_WAIT hWaitHandle)
{
    MOS_UNUSED(hWaitHandle);
    return true;
}
#endif // !ANDROID

MOS_STATUS MOS_UserFeature_ParsePath(
    PMOS_USER_FEATURE_INTERFACE     pOsUserFeatureInterface,
    char * const                    pInputPath,
    PMOS_USER_FEATURE_TYPE          pUserFeatureType,
    char                            **ppSubPath)
{
    char                            *pValue;
    MOS_USER_FEATURE_TYPE           UserFeatureType;
    size_t                          uUFKeyLen;
    size_t                          uHKeyLen;
    size_t                          uValLen;
    size_t                          uSepLen;
    MOS_UNUSED(pOsUserFeatureInterface);

    //-------------------------------------------
    // the UserFeature interface is not currently an actual interface, just a collection
    // of functions, so pOsUserFeatureInterface will always be nullptr until this changes
    //MOS_OS_ASSERT(pOsUserFeatureInterface);
    MOS_OS_ASSERT(pInputPath);
    MOS_OS_ASSERT(strlen(pInputPath) > 0);
    MOS_OS_ASSERT(pUserFeatureType);
    MOS_OS_ASSERT(ppSubPath);
    //-------------------------------------------

    pValue = nullptr;

    pValue = strstr(pInputPath, MOS_UF_SEPARATOR);

    if (!pValue)
    {
        MOS_OS_ASSERTMESSAGE("Invalid user feature key %s.", pInputPath);
        return MOS_STATUS_INVALID_PARAMETER;
    }

    uUFKeyLen   = strlen(pInputPath);
    uValLen     = strlen(pValue);
    uSepLen     = strlen(MOS_UF_SEPARATOR);
    uHKeyLen    = uUFKeyLen - uValLen;

    if (uHKeyLen == 0)
    {
        MOS_OS_ASSERTMESSAGE("Invalid user feature key %s. Path separator in the begining.", pInputPath);
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if (uValLen <= uSepLen)
    {
        MOS_OS_ASSERTMESSAGE("Invalid user feature key %s. No value after path separator.", pInputPath);
        return MOS_STATUS_INVALID_PARAMETER;
    }

    if ((uHKeyLen == strlen(MOS_UFKEY_EXT)) &&
        (strncmp(pInputPath, MOS_UFKEY_EXT, uHKeyLen) == 0))
    {
        UserFeatureType = MOS_USER_FEATURE_TYPE_SYSTEM;
    }
    else if ((uHKeyLen == strlen(MOS_UFKEY_INT)) &&
        (strncmp(pInputPath, MOS_UFKEY_INT, uHKeyLen) == 0))
    {
        UserFeatureType = MOS_USER_FEATURE_TYPE_USER;
    }
    else
    {
        MOS_OS_ASSERTMESSAGE("Invalid user feature key %s. Expected %s or %s.", pInputPath, MOS_UFKEY_EXT, MOS_UFKEY_INT);
        return MOS_STATUS_INVALID_PARAMETER;
    }

    pValue             = pValue + uSepLen;

    *pUserFeatureType  = UserFeatureType;
    *ppSubPath         = pValue;

    return MOS_STATUS_SUCCESS;
}

uint32_t MOS_GetLogicalCoreNumber()
{
    return sysconf(_SC_NPROCESSORS_CONF);
}

MOS_THREADHANDLE MOS_CreateThread(
    void                        *ThreadFunction,
    void                        *ThreadData)
{
    MOS_THREADHANDLE Thread;

    if (0 != pthread_create(&Thread, nullptr, (void *(*)(void *))ThreadFunction, ThreadData))
    {
        Thread = 0;
        MOS_OS_ASSERTMESSAGE("Create thread failed.");
    }

    return Thread;
}

uint32_t MOS_GetThreadId(
    MOS_THREADHANDLE            hThread)
{
    MOS_UNUSED(hThread);
    return 0;
}

uint32_t MOS_GetCurrentThreadId()
{
    return (uint32_t)pthread_self();
}

MOS_STATUS MOS_WaitThread(
    MOS_THREADHANDLE            hThread)
{
    MOS_STATUS                  eStatus = MOS_STATUS_SUCCESS;

    if (hThread == 0)
    {
        MOS_OS_ASSERTMESSAGE("MOS wait thread failed, invalid thread handle.");
        eStatus = MOS_STATUS_INVALID_PARAMETER;
    }
    else if (0 != pthread_join(hThread, nullptr))
    {
        MOS_OS_ASSERTMESSAGE("Failed to join thread.");
        eStatus = MOS_STATUS_UNKNOWN;
    }

    return eStatus;
}

PMOS_MUTEX MOS_CreateMutex()
{
    PMOS_MUTEX pMutex;

    pMutex = (PMOS_MUTEX)MOS_AllocMemory(sizeof(*pMutex));
    if (pMutex != nullptr)
    {
        if (pthread_mutex_init(pMutex, nullptr))
        {
            MOS_FreeMemory(pMutex);
            pMutex = nullptr;
        }
    }

    return pMutex;
}

MOS_STATUS MOS_DestroyMutex(PMOS_MUTEX pMutex)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    if (pMutex)
    {
        if (pthread_mutex_destroy(pMutex))
        {
            eStatus = MOS_STATUS_UNKNOWN;
        }
        MOS_FreeMemory(pMutex);
    }

    return eStatus;
}

MOS_STATUS MOS_LockMutex(PMOS_MUTEX pMutex)
{
    MOS_OS_CHK_NULL_RETURN(pMutex);

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    if (pthread_mutex_lock(pMutex))
    {
        eStatus = MOS_STATUS_UNKNOWN;
    }

    return eStatus;
}

MOS_STATUS MOS_UnlockMutex(PMOS_MUTEX pMutex)
{
    MOS_OS_CHK_NULL_RETURN(pMutex);

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    if (pthread_mutex_unlock(pMutex))
    {
        eStatus = MOS_STATUS_UNKNOWN;
    }

    return eStatus;
}

PMOS_SEMAPHORE MOS_CreateSemaphore(
    uint32_t            uiInitialCount,
    uint32_t            uiMaximumCount)
{
    PMOS_SEMAPHORE pSemaphore = nullptr;
    MOS_UNUSED(uiMaximumCount);

    pSemaphore = (PMOS_SEMAPHORE)MOS_AllocMemory(sizeof(*pSemaphore));
    if (!pSemaphore)
        return nullptr;
    if (sem_init(pSemaphore, 0, uiInitialCount))
    {
        MOS_SafeFreeMemory(pSemaphore);
        pSemaphore = nullptr;
    }

    return pSemaphore;
}

MOS_STATUS MOS_DestroySemaphore(
    PMOS_SEMAPHORE              pSemaphore)
{
    MOS_SafeFreeMemory(pSemaphore);

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MOS_WaitSemaphore(
    PMOS_SEMAPHORE              pSemaphore,
    uint32_t                    uiMilliseconds)
{
    MOS_STATUS                  eStatus = MOS_STATUS_SUCCESS;

    if (uiMilliseconds == INFINITE)
    {
        if (sem_wait(pSemaphore))
        {
            eStatus = MOS_STATUS_UNKNOWN;
        }
    }
    else
    {
        struct timespec time = {
            (int32_t)uiMilliseconds / 1000000,
            ((int32_t)uiMilliseconds % 1000000) * 1000};

        if (sem_timedwait(pSemaphore, &time))
        {
            eStatus = MOS_STATUS_UNKNOWN;
        }
    }

    return eStatus;
}

MOS_STATUS MOS_PostSemaphore(
    PMOS_SEMAPHORE              pSemaphore,
    uint32_t                    uiPostCount)
{
    MOS_STATUS                  eStatus = MOS_STATUS_SUCCESS;

    if (uiPostCount > 0)
    {
        while (uiPostCount--)
        {
            if (sem_post(pSemaphore))
            {
                eStatus = MOS_STATUS_UNKNOWN;
                break;
            }
        }
    }
    else
    {
        eStatus = MOS_STATUS_UNKNOWN;
    }

    return eStatus;
}

uint32_t MOS_WaitForSingleObject(
    void                        *pObject,
    uint32_t                    uiMilliseconds)
{
    uint32_t WaitSignal = 0;
    MOS_UNUSED(pObject);
    MOS_UNUSED(uiMilliseconds);

    return WaitSignal;
}

uint32_t MOS_WaitForMultipleObjects(
    uint32_t                    uiThreadCount,
    void                        **ppObjects,
    uint32_t                    bWaitAll,
    uint32_t                    uiMilliseconds)
{
    MOS_UNUSED(uiThreadCount);
    MOS_UNUSED(ppObjects);
    MOS_UNUSED(bWaitAll);
    MOS_UNUSED(uiMilliseconds);
    return 0;
}

int32_t MOS_AtomicIncrement(
    int32_t *pValue)
{
    return __sync_fetch_and_add(pValue, 1);
}

int32_t MOS_AtomicDecrement(
    int32_t *pValue)
{
    return __sync_fetch_and_sub(pValue, 1);
}

VAStatus MOS_StatusToOsResult(
    MOS_STATUS               eStatus)
{
    switch (eStatus)
    {
        case MOS_STATUS_SUCCESS:                        return VA_STATUS_SUCCESS;
        case MOS_STATUS_NO_SPACE:                       return VA_STATUS_ERROR_ALLOCATION_FAILED;
        case MOS_STATUS_INVALID_PARAMETER:              return VA_STATUS_ERROR_INVALID_PARAMETER;
        case MOS_STATUS_INVALID_HANDLE:                 return VA_STATUS_ERROR_INVALID_BUFFER;
        case MOS_STATUS_NULL_POINTER:                   return VA_STATUS_ERROR_INVALID_CONTEXT;
        default:                                        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    return VA_STATUS_ERROR_OPERATION_FAILED;
}

MOS_STATUS OsResultToMOS_Status(
    VAStatus                 eResult)
{
    switch (eResult)
    {
        case VA_STATUS_SUCCESS:                     return MOS_STATUS_SUCCESS;
        case VA_STATUS_ERROR_ALLOCATION_FAILED:     return MOS_STATUS_NO_SPACE;
        case VA_STATUS_ERROR_INVALID_PARAMETER:     return MOS_STATUS_INVALID_PARAMETER;
        case VA_STATUS_ERROR_INVALID_BUFFER:        return MOS_STATUS_INVALID_HANDLE;
        case VA_STATUS_ERROR_INVALID_CONTEXT:       return MOS_STATUS_NULL_POINTER;
        default:                                    return MOS_STATUS_UNKNOWN;
    }

    return MOS_STATUS_UNKNOWN;
}

MOS_STATUS MOS_GetLocalTime(
    struct tm* Tm)
{
    MOS_STATUS     eStatus = MOS_STATUS_SUCCESS;
    struct tm      *pTm;
    time_t         lTime = time(nullptr);
    pTm = localtime(&lTime);
    if(pTm == nullptr)
    {
        MOS_OS_ASSERTMESSAGE("Failed to get localtime.");
        eStatus = MOS_STATUS_UNKNOWN;
        return eStatus;
    }

    eStatus = MOS_SecureMemcpy(Tm, sizeof(struct tm), pTm, sizeof(struct tm));
    return eStatus;
}

void MOS_TraceEventInit()
{
    return MosUtilities::MosTraceEventInit();
}

void MOS_TraceEventClose()
{
    return MosUtilities::MosTraceEventClose();
}

void MOS_TraceSetupInfo(uint32_t DrvVer, uint32_t PlatFamily, uint32_t RenderFamily, uint32_t DeviceID)
{
    // not implemented
}

void MOS_TraceEvent(
    uint16_t         usId,
    uint8_t          ucType,
    const void       *pArg1,
    uint32_t         dwSize1,
    const void       *pArg2,
    uint32_t         dwSize2)
{
    return MosUtilities::MosTraceEvent(usId, ucType, pArg1, dwSize1, pArg2, dwSize2);
}

void MOS_TraceDataDump(
    const char * pcName,
    uint32_t     flags,
    const void * pBuf,
    uint32_t     dwSize)
{
    // not implemented
}

void MOS_TraceDataDictionary(
    const char* pcName,
    const void* pBuf,
    uint32_t    dwSize)
{
    // not implemented
}


MOS_STATUS MOS_GfxInfoInit()
{
    // not implemented
    return MOS_STATUS_SUCCESS;
}

void MOS_GfxInfoClose()
{
    // not implemented
}

void MOS_GfxInfo_RTErr(uint8_t ver,
    uint16_t    compId,
    uint16_t    FtrId,
    uint32_t    ErrorCode,
    uint8_t     num_of_triples,
    ...)
{
    // not implemented
}

void MOS_GfxInfo(
    uint8_t         ver,
    uint16_t        compId,
    uint32_t        tmtryID,
    uint8_t         num_of_triples,
    ...)
{
    // not implemented
}
