/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "appspawn_client.h"
#include "appspawn_mount_permission.h"
#include "appspawn_hook.h"
#include "appspawn_utils.h"
#include "parameter.h"
#include "securec.h"
#define OHOS_PERMISSION_FOWNER "ohos.permission.FOWNER"
static inline int CalcFlagsUnits(uint32_t maxIndex)
{
    return ((maxIndex / 32) + ((maxIndex % 32 == 0) ? 0 : 1));  // 32 max bit in uint32_t
}

static inline int SetAppSpawnMsgFlags(AppSpawnMsgFlags *msgFlags, uint32_t index)
{
    uint32_t blockIndex = index / 32;  // 32 max bit in int
    uint32_t bitIndex = index % 32;    // 32 max bit in int
    if (blockIndex < msgFlags->count) {
        msgFlags->flags[blockIndex] |= (1 << bitIndex);
    }
    return 0;
}

static inline int CheckMsg(const AppSpawnReqMsgNode *reqNode, const AppSpawnTlv *tlv, const char *name)
{
    if ((reqNode->msg->msgLen + tlv->tlvLen) > MAX_MSG_TOTAL_LENGTH) {
        APPSPAWN_LOGE("The message is too long %{public}s", name);
        return APPSPAWN_MSG_INVALID;
    }
    if (reqNode->msg->msgType == MSG_GET_RENDER_TERMINATION_STATUS) {
        if (tlv->tlvType != TLV_RENDER_TERMINATION_INFO) {
            APPSPAWN_LOGE("Not support tlv %{public}s for message MSG_GET_RENDER_TERMINATION_STATUS", name);
            return APPSPAWN_TLV_NOT_SUPPORT;
        }
    }
    return 0;
}

static inline int CheckInputString(const char *info, const char *value, uint32_t maxLen)
{
    APPSPAWN_CHECK(value != NULL, return APPSPAWN_ARG_INVALID, "Invalid input info for %{public}s ", info);
    uint32_t valueLen = (uint32_t)strlen(value);
    APPSPAWN_CHECK(valueLen > 0 && valueLen < maxLen, return APPSPAWN_ARG_INVALID,
        "Invalid input string length '%{public}s' for '%{public}s'", value, info);
    return 0;
}

static AppSpawnMsgBlock *CreateAppSpawnMsgBlock(AppSpawnReqMsgNode *reqNode)
{
    AppSpawnMsgBlock *block = (AppSpawnMsgBlock *)calloc(1, MAX_MSG_BLOCK_LEN);
    APPSPAWN_CHECK(block != NULL, return NULL, "Failed to create block");
    OH_ListInit(&block->node);
    block->blockSize = MAX_MSG_BLOCK_LEN - sizeof(AppSpawnMsgBlock);
    block->currentIndex = 0;
    OH_ListAddTail(&reqNode->msgBlocks, &block->node);
    return block;
}

static AppSpawnMsgBlock *GetValidMsgBlock(const AppSpawnReqMsgNode *reqNode, uint32_t realLen)
{
    AppSpawnMsgBlock *block = NULL;
    struct ListNode *node = reqNode->msgBlocks.next;
    while (node != &reqNode->msgBlocks) {
        block = ListEntry(node, AppSpawnMsgBlock, node);
        if ((block->blockSize - block->currentIndex) >= realLen) {
            return block;
        }
        node = node->next;
    }
    return NULL;
}

static AppSpawnMsgBlock *GetTailMsgBlock(const AppSpawnReqMsgNode *reqNode)
{
    AppSpawnMsgBlock *block = NULL;
    struct ListNode *node = reqNode->msgBlocks.prev;
    if (node != &reqNode->msgBlocks) {
        block = ListEntry(node, AppSpawnMsgBlock, node);
    }
    return block;
}

static void FreeMsgBlock(ListNode *node)
{
    AppSpawnMsgBlock *block = ListEntry(node, AppSpawnMsgBlock, node);
    OH_ListRemove(node);
    OH_ListInit(node);
    free(block);
}

static int AddAppDataToBlock(AppSpawnMsgBlock *block, const uint8_t *data, uint32_t dataLen, int32_t dataType)
{
    APPSPAWN_CHECK(block->blockSize > block->currentIndex,
        return APPSPAWN_BUFFER_NOT_ENOUGH, "Not enough buffer for data");
    uint32_t reminderLen = block->blockSize - block->currentIndex;
    uint32_t realDataLen = (dataType == DATA_TYPE_STRING) ? APPSPAWN_ALIGN(dataLen + 1) : APPSPAWN_ALIGN(dataLen);
    APPSPAWN_CHECK(reminderLen >= realDataLen, return APPSPAWN_BUFFER_NOT_ENOUGH, "Not enough buffer for data");
    int ret = memcpy_s(block->buffer + block->currentIndex, reminderLen, data, dataLen);
    APPSPAWN_CHECK(ret == EOK, return APPSPAWN_SYSTEM_ERROR, "Failed to copy data");
    if (dataType == DATA_TYPE_STRING) {
        *((char *)block->buffer + block->currentIndex + dataLen) = '\0';
    }
    block->currentIndex += realDataLen;
    return 0;
}

static int AddAppDataToTail(AppSpawnReqMsgNode *reqNode, const uint8_t *data, uint32_t dataLen, int32_t dataType)
{
    uint32_t currLen = 0;
    AppSpawnMsgBlock *block = GetTailMsgBlock(reqNode);
    APPSPAWN_CHECK(block != NULL, return APPSPAWN_BUFFER_NOT_ENOUGH, "Not block info reqNode");
    uint32_t realDataLen = (dataType == DATA_TYPE_STRING) ? dataLen + 1 : dataLen;
    do {
        uint32_t reminderBufferLen = block->blockSize - block->currentIndex;
        uint32_t reminderDataLen = realDataLen - currLen;
        uint32_t realLen = APPSPAWN_ALIGN(reminderDataLen);
        uint32_t realCopy = 0;
        if (reminderBufferLen >= realLen) {  // 足够存储,直接保存
            int ret = memcpy_s(block->buffer + block->currentIndex, reminderBufferLen, data + currLen, reminderDataLen);
            APPSPAWN_CHECK(ret == EOK, return APPSPAWN_SYSTEM_ERROR, "Failed to copy data");
            block->currentIndex += realLen;
            break;
        } else if (reminderBufferLen > 0) {
            realCopy = reminderDataLen > reminderBufferLen ? reminderBufferLen : reminderDataLen;
            int ret = memcpy_s(block->buffer + block->currentIndex, reminderBufferLen, data + currLen, realCopy);
            APPSPAWN_CHECK(ret == EOK, return APPSPAWN_SYSTEM_ERROR, "Failed to copy data");
            block->currentIndex += realCopy;
            currLen += realCopy;
        }
        block = CreateAppSpawnMsgBlock(reqNode);
        APPSPAWN_CHECK(block != NULL, return APPSPAWN_SYSTEM_ERROR, "Not enough buffer for data");
    } while (currLen < realDataLen);
    return 0;
}

static int AddAppDataEx(AppSpawnReqMsgNode *reqNode, const char *name, const AppSpawnAppData *data)
{
    AppSpawnTlvExt tlv = {};
    if (data->dataType == DATA_TYPE_STRING) {
        tlv.tlvLen = APPSPAWN_ALIGN(data->dataLen + 1) + sizeof(AppSpawnTlvExt);
    } else {
        tlv.tlvLen = APPSPAWN_ALIGN(data->dataLen) + sizeof(AppSpawnTlvExt);
    }
    tlv.tlvType = TLV_MAX;
    tlv.dataLen = data->dataLen;
    tlv.dataType = data->dataType;
    int ret = strcpy_s(tlv.tlvName, sizeof(tlv.tlvName), name);
    APPSPAWN_CHECK(ret == 0, return APPSPAWN_SYSTEM_ERROR, "Failed to add data for %{public}s", name);
    ret = CheckMsg(reqNode, (AppSpawnTlv *)&tlv, name);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);

    APPSPAWN_LOGV("AddAppDataEx tlv [%{public}s %{public}u ] dataLen: %{public}u start: %{public}u",
        name, tlv.tlvLen, data->dataLen, reqNode->msg->msgLen);
    // 获取一个能保存改完整tlv的block
    AppSpawnMsgBlock *block = GetValidMsgBlock(reqNode, tlv.tlvLen);
    if (block != NULL) {
        ret = AddAppDataToBlock(block, (uint8_t *)&tlv, sizeof(tlv), 0);
        APPSPAWN_CHECK(ret == 0, return ret, "Failed to add tlv for %{public}s", name);
        ret = AddAppDataToBlock(block, data->data, data->dataLen, data->dataType);
        APPSPAWN_CHECK(ret == 0, return ret, "Failed to add data for %{public}s", name);
    } else {
        // 没有一个可用的block,最队列最后添加数据
        ret = AddAppDataToTail(reqNode, (uint8_t *)&tlv, sizeof(tlv), 0);
        APPSPAWN_CHECK(ret == 0, return ret, "Failed to add tlv to tail for %{public}s", name);
        ret = AddAppDataToTail(reqNode, data->data, data->dataLen, data->dataType);
        APPSPAWN_CHECK(ret == 0, return ret, "Failed to add data to tail for %{public}s", name);
    }
    reqNode->msg->tlvCount++;
    reqNode->msg->msgLen += tlv.tlvLen;
    APPSPAWN_LOGV("AddAppDataEx success name '%{public}s' end: %{public}u", name, reqNode->msg->msgLen);
    return 0;
}

static int AddAppData(AppSpawnReqMsgNode *reqNode,
    uint32_t tlvType, const AppSpawnAppData *data, uint32_t count, const char *name)
{
    // 计算实际数据的长度
    uint32_t realLen = sizeof(AppSpawnTlv);
    uint32_t dataLen = 0;
    for (uint32_t index = 0; index < count; index++) {
        dataLen += data[index].dataLen;
        realLen += (data[index].dataType == DATA_TYPE_STRING) ?
            APPSPAWN_ALIGN(data[index].dataLen + 1) : APPSPAWN_ALIGN(data[index].dataLen);
    }
    AppSpawnTlv tlv;
    tlv.tlvLen = realLen;
    tlv.tlvType = tlvType;
    int ret = CheckMsg(reqNode, &tlv, name);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);

    APPSPAWN_LOGV("AddAppData tlv [%{public}s %{public}u] dataLen: %{public}u start: %{public}u",
        name, tlv.tlvLen, dataLen, reqNode->msg->msgLen);
    // 获取一个能保存改完整tlv的block
    AppSpawnMsgBlock *block = GetValidMsgBlock(reqNode, tlv.tlvLen);
    if (block != NULL) {
        ret = AddAppDataToBlock(block, (uint8_t *)&tlv, sizeof(tlv), 0);
        APPSPAWN_CHECK(ret == 0, return ret, "Failed to add tlv for %{public}d", tlvType);

        for (uint32_t index = 0; index < count; index++) {
            ret = AddAppDataToBlock(block, (uint8_t *)data[index].data, data[index].dataLen, data[index].dataType);
            APPSPAWN_CHECK(ret == 0, return ret, "Failed to add data for %{public}d", tlvType);
        }
    } else {
        // 没有一个可用的block,最队列最后添加数据
        ret = AddAppDataToTail(reqNode, (uint8_t *)&tlv, sizeof(tlv), 0);
        APPSPAWN_CHECK(ret == 0, return ret, "Failed to add tlv to tail for %{public}d", tlvType);
        // 添加tlv信息
        for (uint32_t index = 0; index < count; index++) {
            ret = AddAppDataToTail(reqNode, (uint8_t *)data[index].data, data[index].dataLen, data[index].dataType);
            APPSPAWN_CHECK(ret == 0, return ret, "Failed to add data for %{public}d", tlvType);
        }
    }
    reqNode->msg->msgLen += tlv.tlvLen;
    APPSPAWN_LOGV("AddAppData success tlvType %{public}s end: %{public}u", name, reqNode->msg->msgLen);
    return 0;
}

static int SetFlagsTlv(AppSpawnReqMsgNode *reqNode,
    AppSpawnMsgBlock *block, AppSpawnMsgFlags **msgFlags, int type, int maxCount)
{
    uint32_t units = (uint32_t)CalcFlagsUnits(maxCount);
    APPSPAWN_LOGV("SetFlagsTlv maxCount %{public}d type %{public}d units %{public}d", maxCount, type, units);
    uint32_t flagsLen = sizeof(AppSpawnTlv) + sizeof(AppSpawnMsgFlags) + sizeof(uint32_t) * units;
    APPSPAWN_CHECK((block->blockSize - block->currentIndex) > flagsLen,
        return APPSPAWN_BUFFER_NOT_ENOUGH, "Invalid block to set flags tlv type %{public}d", type);

    AppSpawnTlv *tlv = (AppSpawnTlv *)(block->buffer + block->currentIndex);
    tlv->tlvLen = flagsLen;
    tlv->tlvType = type;
    *msgFlags = (AppSpawnMsgFlags *)(block->buffer + block->currentIndex + sizeof(AppSpawnTlv));
    (*msgFlags)->count = units;
    block->currentIndex += flagsLen;
    reqNode->msg->msgLen += flagsLen;
    reqNode->msg->tlvCount++;
    return 0;
}

static int CreateBaseMsg(AppSpawnReqMsgNode *reqNode, uint32_t msgType, const char *processName)
{
    AppSpawnMsgBlock *block = CreateAppSpawnMsgBlock(reqNode);
    APPSPAWN_CHECK(block != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create block for %{public}s", processName);

    // 保留消息头的大小
    reqNode->msg = (AppSpawnMsg *)(block->buffer + block->currentIndex);
    reqNode->msg->magic = APPSPAWN_MSG_MAGIC;
    reqNode->msg->msgId = 0;
    reqNode->msg->msgType = msgType;
    reqNode->msg->msgLen = sizeof(AppSpawnMsg);
    reqNode->msg->tlvCount = 0;
    int ret = strcpy_s(reqNode->msg->processName, sizeof(reqNode->msg->processName), processName);
    APPSPAWN_CHECK(ret == 0, return APPSPAWN_SYSTEM_ERROR, "Failed to create block for %{public}s", processName);
    block->currentIndex = sizeof(AppSpawnMsg);
    ret = SetFlagsTlv(reqNode, block, &reqNode->msgFlags, TLV_MSG_FLAGS, MAX_FLAGS_INDEX);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
    APPSPAWN_CHECK_ONLY_EXPER(msgType == MSG_APP_SPAWN || msgType == MSG_SPAWN_NATIVE_PROCESS ||
                              msgType == MSG_SPAWN_IMAGE_PROCESS || msgType == MSG_SPAWN_WORKER_PROCESS, return 0);
    int maxCount = GetPermissionMaxCount();
    APPSPAWN_CHECK(maxCount > 0, return APPSPAWN_SYSTEM_ERROR, "Invalid max for permission %{public}s", processName);
    ret = SetFlagsTlv(reqNode, block, &reqNode->permissionFlags, TLV_PERMISSION, maxCount);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
    APPSPAWN_LOGV("CreateBaseMsg msgLen: %{public}u %{public}u", reqNode->msg->msgLen, block->currentIndex);
    return 0;
}

static void DeleteAppSpawnReqMsg(AppSpawnReqMsgNode *reqNode)
{
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return);
    APPSPAWN_LOGV("DeleteAppSpawnReqMsg reqId: %{public}u", reqNode->reqId);
    reqNode->msgFlags = NULL;
    reqNode->permissionFlags = NULL;
    reqNode->msg = NULL;
    // 释放block
    OH_ListRemoveAll(&reqNode->msgBlocks, FreeMsgBlock);
    free(reqNode);
}

static AppSpawnReqMsgNode *CreateAppSpawnReqMsg(uint32_t msgType, const char *processName)
{
    static uint32_t reqId = 0;
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)malloc(sizeof(AppSpawnReqMsgNode));
    APPSPAWN_CHECK(reqNode != NULL, return NULL, "Failed to create msg node for %{public}s", processName);

    OH_ListInit(&reqNode->node);
    OH_ListInit(&reqNode->msgBlocks);
    reqNode->reqId = ++reqId;
    reqNode->msg = NULL;
    reqNode->msgFlags = NULL;
    reqNode->permissionFlags = NULL;
    reqNode->fdCount = 0;
    reqNode->isColdRun = 0;
    int ret = CreateBaseMsg(reqNode, msgType, processName);
    APPSPAWN_CHECK(ret == 0, DeleteAppSpawnReqMsg(reqNode);
         return NULL, "Failed to create base msg for %{public}s", processName);
    APPSPAWN_LOGV("CreateAppSpawnReqMsg reqId: %{public}d msg type: %{public}u processName: %{public}s",
        reqNode->reqId, msgType, processName);
    return reqNode;
}

int AppSpawnReqMsgAddFd(AppSpawnReqMsgHandle reqHandle, const char* fdName, int fd)
{
    APPSPAWN_CHECK(reqHandle != NULL, return APPSPAWN_ARG_INVALID, "Invalid reqHandle");
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK(reqNode != NULL, return APPSPAWN_ARG_INVALID, "Invalid reqNode");
    APPSPAWN_CHECK(fd >= 0 && fdName != NULL && strlen(fdName) <= APP_FDNAME_MAXLEN
        &&  reqNode->fdCount < APP_MAX_FD_COUNT, return APPSPAWN_ARG_INVALID,
        "Invalid fdinfo %{public}d %{public}d %{public}d", fd, fdName != NULL, reqNode->fdCount);
    reqNode->fds[reqNode->fdCount++] = fd;
    return AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_APP_FD, (void *)fdName);
}

APPSPAWN_STATIC void GetSpecialGid(const char *bundleName, gid_t gidTable[], uint32_t *gidCount)
{
    // special handle bundle name medialibrary and scanner
    const char *specialBundleNames[] = {
        "com.ohos.medialibrary.medialibrarydata", "com.ohos.medialibrary.medialibrarydata:backup"
    };

    for (size_t i = 0; i < sizeof(specialBundleNames) / sizeof(specialBundleNames[0]); i++) {
        if (strcmp(bundleName, specialBundleNames[i]) == 0) {
            if (*gidCount + 1 < APP_MAX_GIDS) {
                gidTable[(*gidCount)++] = GID_USER_DATA_RW;
                gidTable[(*gidCount)++] = GID_FILE_ACCESS;
            }
            break;
        }
    }
}

int AppSpawnReqMsgCreate(AppSpawnMsgType msgType, const char *processName, AppSpawnReqMsgHandle *reqHandle)
{
    APPSPAWN_CHECK(reqHandle != NULL, return APPSPAWN_ARG_INVALID, "Invalid request handle");
    APPSPAWN_CHECK(msgType < MAX_TYPE_INVALID,
        return APPSPAWN_MSG_INVALID, "Invalid message type %{public}u %{public}s", msgType, processName);
    int ret = CheckInputString("processName", processName, APP_LEN_PROC_NAME);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
    AppSpawnReqMsgNode *reqNode = CreateAppSpawnReqMsg(msgType, processName);
    APPSPAWN_CHECK(reqNode != NULL, return APPSPAWN_SYSTEM_ERROR,
        "Failed to create msg node for %{public}s", processName);
    *reqHandle = (AppSpawnReqMsgHandle)(reqNode);
    return 0;
}

void AppSpawnReqMsgFree(AppSpawnReqMsgHandle reqHandle)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return);
    DeleteAppSpawnReqMsg(reqNode);
}

int AppSpawnReqMsgSetAppDacInfo(AppSpawnReqMsgHandle reqHandle, const AppDacInfo *dacInfo)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_ARG_INVALID, "Invalid dacInfo ");

    AppDacInfo tmpDacInfo = {0};
    (void)memcpy_s(&tmpDacInfo, sizeof(tmpDacInfo), dacInfo, sizeof(tmpDacInfo));
    GetSpecialGid(reqNode->msg->processName, tmpDacInfo.gidTable, &tmpDacInfo.gidCount);

    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)&tmpDacInfo;
    data[0].dataLen = sizeof(AppSpawnMsgDacInfo);
    return AddAppData(reqNode, TLV_DAC_INFO, data, 1, "TLV_DAC_INFO");
}

int AppSpawnReqMsgSetBundleInfo(AppSpawnReqMsgHandle reqHandle, uint32_t bundleIndex, const char *bundleName)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    int ret = CheckInputString("TLV_BUNDLE_INFO", bundleName, APP_LEN_BUNDLE_NAME);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);

    AppSpawnMsgBundleInfo info = {};
    info.bundleIndex = bundleIndex;
    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)&info;
    data[0].dataLen = sizeof(AppSpawnMsgBundleInfo);
    data[1].data = (uint8_t *)bundleName;
    data[1].dataLen = strlen(bundleName);
    data[1].dataType = DATA_TYPE_STRING;
    return AddAppData(reqNode, TLV_BUNDLE_INFO, data, MAX_DATA_IN_TLV, "TLV_BUNDLE_INFO");
}

static bool ShouldEnableColdRun(AppFlagsIndex flagIndex)
{
    if (flagIndex == APP_FLAGS_UBSAN_ENABLED ||
        flagIndex == APP_FLAGS_ASANENABLED ||
        flagIndex == APP_FLAGS_TSAN_ENABLED ||
        flagIndex == APP_FLAGS_HWASAN_ENABLED) {
        return true;
    }

    if (flagIndex == APP_FLAGS_COLD_BOOT &&
        CheckEnabled("startup.appspawn.cold.boot", "true")) {
        return true;
    }

    if (flagIndex == APP_FLAGS_DEBUG_SIGN &&
        CheckEnabled("const.security.developermode.state", "true") &&
        CheckEnabled("hiviewdfx.hiprofiler.preload", "1")) {
        return true;
    }

    return false;
}

int AppSpawnReqMsgSetAppFlag(AppSpawnReqMsgHandle reqHandle, AppFlagsIndex flagIndex)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    APPSPAWN_CHECK(reqNode->msgFlags != NULL, return APPSPAWN_ARG_INVALID, "No msg flags tlv");
    APPSPAWN_CHECK(flagIndex < MAX_FLAGS_INDEX, return APPSPAWN_ARG_INVALID,
        "Invalid msg app flags %{public}d", flagIndex);
    if (!reqNode->isColdRun && ShouldEnableColdRun(flagIndex)) {
        reqNode->isColdRun = 1;
    }
    return SetAppSpawnMsgFlags(reqNode->msgFlags, flagIndex);
}

int AppSpawnReqMsgAddExtInfo(AppSpawnReqMsgHandle reqHandle, const char *name, const uint8_t *value, uint32_t valueLen)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    int ret = CheckInputString("check name", name, APPSPAWN_TLV_NAME_LEN);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
    APPSPAWN_CHECK(value != NULL && valueLen <= EXTRAINFO_TOTAL_LENGTH_MAX && valueLen > 0,
        return APPSPAWN_ARG_INVALID, "Invalid ext value ");

    APPSPAWN_LOGV("AppSpawnReqMsgAddExtInfo name %{public}s", name);
    AppSpawnAppData data[1] = {};  // 1 max data count
    data[0].data = (uint8_t *)value;
    data[0].dataLen = valueLen;
    return AddAppDataEx(reqNode, name, data);  // 2 max count
}

int AppSpawnReqMsgAddStringInfo(AppSpawnReqMsgHandle reqHandle, const char *name, const char *value)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    int ret = CheckInputString("check name", name, APPSPAWN_TLV_NAME_LEN);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
    ret = CheckInputString(name, value, EXTRAINFO_TOTAL_LENGTH_MAX);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);

    APPSPAWN_LOGV("AppSpawnReqMsgAddStringInfo name %{public}s", name);
    AppSpawnAppData data[1] = {};  // 1 max data count
    data[0].data = (uint8_t *)value;
    data[0].dataLen = strlen(value);
    data[0].dataType = DATA_TYPE_STRING;
    return AddAppDataEx(reqNode, name, data);  // 2 max count
}

int AppSpawnReqMsgAddPermission(AppSpawnReqMsgHandle reqHandle, const char *permission)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    APPSPAWN_CHECK(permission != NULL, return APPSPAWN_ARG_INVALID, "Invalid permission ");
    APPSPAWN_CHECK(reqNode->permissionFlags != NULL, return APPSPAWN_ARG_INVALID, "No permission tlv ");

    int32_t maxIndex = GetMaxPermissionIndex(NULL);
    int index = GetPermissionIndex(NULL, permission);
    APPSPAWN_CHECK(index >= 0 && index < maxIndex,
        return APPSPAWN_PERMISSION_NOT_SUPPORT, "Invalid permission %{public}s", permission);
    APPSPAWN_LOGV("AddPermission index %{public}d name %{public}s", index, permission);
    int ret = SetAppSpawnMsgFlags(reqNode->permissionFlags, index);
    APPSPAWN_CHECK(ret == 0, return ret, "Invalid permission %{public}s", permission);
    return 0;
}

int AppSpawnReqMsgSetAppDomainInfo(AppSpawnReqMsgHandle reqHandle, uint32_t hapFlags, const char *apl)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    int ret = CheckInputString("TLV_DOMAIN_INFO", apl, APP_APL_MAX_LEN);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);

    AppSpawnMsgDomainInfo msgDomainInfo;
    msgDomainInfo.hapFlags = hapFlags;
    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)&msgDomainInfo;
    data[0].dataLen = sizeof(AppSpawnMsgDomainInfo);
    data[1].data = (uint8_t *)apl;
    data[1].dataLen = strlen(apl);
    data[1].dataType = DATA_TYPE_STRING;
    return AddAppData(reqNode, TLV_DOMAIN_INFO, data, MAX_DATA_IN_TLV, "TLV_DOMAIN_INFO");
}

int AppSpawnReqMsgSetAppInternetPermissionInfo(AppSpawnReqMsgHandle reqHandle, uint8_t allow, uint8_t setAllow)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);

    AppSpawnMsgInternetInfo info = {};
    info.allowInternet = allow;
    info.setAllowInternet = setAllow;
    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)&info;
    data[0].dataLen = sizeof(AppSpawnMsgInternetInfo);
    return AddAppData(reqNode, TLV_INTERNET_INFO, data, 1, "TLV_INTERNET_INFO");
}

int AppSpawnReqMsgSetAppOwnerId(AppSpawnReqMsgHandle reqHandle, const char *ownerId)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    int ret = CheckInputString("TLV_OWNER_INFO", ownerId, APP_OWNER_ID_LEN);
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);

    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)ownerId;
    data[0].dataLen = strlen(ownerId);
    data[0].dataType = DATA_TYPE_STRING;
    return AddAppData(reqNode, TLV_OWNER_INFO, data, 1, "TLV_OWNER_INFO");
}

int AppSpawnReqMsgSetAppAccessToken(AppSpawnReqMsgHandle reqHandle, uint64_t accessTokenIdEx)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);

    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)&accessTokenIdEx;
    data[0].dataLen = sizeof(accessTokenIdEx);
    return AddAppData(reqNode, TLV_ACCESS_TOKEN_INFO, data, 1, "TLV_ACCESS_TOKEN_INFO");
}

int AppSpawnTerminateMsgCreate(pid_t pid, AppSpawnReqMsgHandle *reqHandle)
{
    APPSPAWN_CHECK(reqHandle != NULL, return APPSPAWN_ARG_INVALID, "Invalid request handle");
    AppSpawnReqMsgNode *reqNode = CreateAppSpawnReqMsg(MSG_GET_RENDER_TERMINATION_STATUS, "terminate-process");
    APPSPAWN_CHECK(reqNode != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create msg node");

    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)&pid;
    data[0].dataLen = sizeof(pid);
    int ret = AddAppData(reqNode, TLV_RENDER_TERMINATION_INFO, data, 1, "TLV_RENDER_TERMINATION_INFO");
    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, DeleteAppSpawnReqMsg(reqNode);
        return ret);
    *reqHandle = (AppSpawnReqMsgHandle)(reqNode);
    return 0;
}

int AppSpawnClientAddPermission(AppSpawnClientHandle handle, AppSpawnReqMsgHandle reqHandle, const char *permission)
{
    AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
    APPSPAWN_CHECK(reqMgr != NULL, return APPSPAWN_ARG_INVALID, "Invalid reqMgr");
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL, return APPSPAWN_ARG_INVALID);
    APPSPAWN_CHECK(permission != NULL, return APPSPAWN_ARG_INVALID, "Invalid permission ");
    APPSPAWN_CHECK(reqNode->permissionFlags != NULL, return APPSPAWN_ARG_INVALID, "No permission tlv ");

    if (strcmp(permission, OHOS_PERMISSION_FOWNER) == 0) {
        APPSPAWN_LOGI("AppSpawnClientAddPermission %{public}s", permission);
        return AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_SET_CAPS_FOWNER);
    }

#ifdef APPSPAWN_SANDBOX_NEW
    // Don't need to transmit sandbox permission in nwebspawn mode
    if (reqMgr->type == CLIENT_FOR_NWEBSPAWN) {
        return 0;
    }
#endif

    int32_t maxIndex = GetMaxPermissionIndex(handle);
    int index = GetPermissionIndex(handle, permission);
    APPSPAWN_CHECK(index >= 0 && index < maxIndex,
        return APPSPAWN_PERMISSION_NOT_SUPPORT, "Invalid permission %{public}s", permission);
    APPSPAWN_LOGV("add permission index %{public}d name %{public}s", index, permission);
    int ret = SetAppSpawnMsgFlags(reqNode->permissionFlags, index);
    APPSPAWN_CHECK(ret == 0, return ret, "Invalid permission %{public}s", permission);
    return 0;
}

int AppSpawnReqMsgSetCheckpointInfo(AppSpawnReqMsgHandle reqHandle, pid_t imgPid,
    uint64_t checkPointId, const char *imgName)
{
    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
    APPSPAWN_CHECK_ONLY_EXPER(reqNode != NULL && imgPid > 0, return APPSPAWN_ARG_INVALID);

    AppSpawnCheckpointInfo checkpointInfo = {};
    checkpointInfo.imgPid = imgPid;
    checkpointInfo.checkPointId = checkPointId;
    if (imgName != NULL) {
        int ret = strcpy_s(checkpointInfo.imgName, APP_CHECKPOINT_NAME_LEN, imgName);
        APPSPAWN_CHECK(ret == 0, return APPSPAWN_ARG_INVALID,
            "Failed to copy imgName: %{public}s", imgName);
    }

    AppSpawnAppData data[MAX_DATA_IN_TLV] = {};
    data[0].data = (uint8_t *)&checkpointInfo;
    data[0].dataLen = sizeof(AppSpawnCheckpointInfo);
    return AddAppData(reqNode, TLV_CHECK_POINT_INFO, data, 1, "TLV_CHECKPOINT_INFO");
}