* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "capability_manager.h"
#include "error_manager.h"
#include "tsd_log.h"
#include "tsd/status.h"
#include "tsd_util_func.h"
#include "tsd/tsd_client.h"
namespace tsd {
namespace {
constexpr uint32_t COMMON_SUPPORT_TIMEOUT = 10000U;
constexpr uint32_t SUPPORT_OM_INNER_DEC_MSG_TIMEOUT = 10000U;
constexpr uint64_t TSD_SUPPORT_OM_INNER_DEC = 1UL;
constexpr uint64_t TSD_NOT_SUPPORT_OM_INNER_DEC = 0UL;
bool PidQosTryUseStored(CapabilityManager& mgr, uint64_t ptr)
{
(void)mgr;
(void)ptr;
return false;
}
TSD_StatusT PidQosSaveResult(const CapabilityManager& mgr, uint64_t ptr)
{
uint64_t* const resultPtr = reinterpret_cast<uint64_t*>(static_cast<uintptr_t>(ptr));
if (resultPtr == nullptr) {
TSD_ERROR("input ptr is null");
return TSD_CLT_OPEN_FAILED;
}
const int64_t pidQos = mgr.GetPidQos();
if (pidQos != -1) {
*resultPtr = static_cast<uint64_t>(pidQos);
}
return TSD_OK;
}
void PidQosWriteUnsupported(uint64_t ptr) { *reinterpret_cast<uint64_t*>(static_cast<uintptr_t>(ptr)) = 0UL; }
void PidQosUpdateState(CapabilityManager& mgr, const HDCMessage& msg) { mgr.SetPidQos(msg.pid_of_qos()); }
bool LevelTryUseStored(CapabilityManager& mgr, uint64_t ptr)
{
const uint32_t level = mgr.GetTsdSupportLevel();
if (TSD_BITMAP_GET(level, TSD_SUPPORT_HS_AISERVER_FEATURE_BIT) != 0U) {
uint32_t* const resultPtr = PtrToPtr<void, uint32_t>(ValueToPtr(static_cast<uintptr_t>(ptr)));
*resultPtr = level;
return true;
}
return false;
}
TSD_StatusT LevelSaveResult(const CapabilityManager& mgr, uint64_t ptr)
{
uint32_t* const resultPtr = PtrToPtr<void, uint32_t>(ValueToPtr(static_cast<uintptr_t>(ptr)));
if (resultPtr == nullptr) {
TSD_ERROR("input ptr is null");
return TSD_CLT_OPEN_FAILED;
}
*resultPtr = static_cast<uint32_t>(mgr.GetTsdSupportLevel());
return TSD_OK;
}
void LevelWriteUnsupported(uint64_t ptr) { *reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(ptr)) = 0U; }
void LevelUpdateState(CapabilityManager& mgr, const HDCMessage& msg)
{
const uint32_t level = msg.capability_level();
if ((msg.tsd_rsp_code() == 0U) && (level != 0U)) {
mgr.SetTsdSupportLevel(level);
}
}
bool OmInnerDecTryUseStored(CapabilityManager& mgr, uint64_t ptr)
{
if (mgr.IsSupportOmInnerDec()) {
uint64_t* const resultPtr = reinterpret_cast<uint64_t*>(static_cast<uintptr_t>(ptr));
*resultPtr = TSD_SUPPORT_OM_INNER_DEC;
return true;
}
return false;
}
TSD_StatusT OmInnerDecSaveResult(const CapabilityManager& mgr, uint64_t ptr)
{
uint64_t* const resultPtr = reinterpret_cast<uint64_t*>(static_cast<uintptr_t>(ptr));
*resultPtr = mgr.IsSupportOmInnerDec() ? TSD_SUPPORT_OM_INNER_DEC : TSD_NOT_SUPPORT_OM_INNER_DEC;
return TSD_OK;
}
void OmInnerDecWriteUnsupported(uint64_t ptr) { *reinterpret_cast<uint64_t*>(static_cast<uintptr_t>(ptr)) = 0UL; }
void OmInnerDecUpdateState(CapabilityManager& mgr, const HDCMessage& msg)
{
mgr.SetSupportOmInnerDec(msg.tsd_rsp_code() == 0U);
}
bool BuiltinUdfTryUseStored(CapabilityManager& mgr, uint64_t ptr)
{
if (TSD_BITMAP_GET(mgr.GetTsdSupportLevel(), TSD_SUPPORT_BUILTIN_UDF_BIT)) {
bool* const resultPtr = reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr));
*resultPtr = true;
return true;
}
return false;
}
TSD_StatusT BuiltinUdfSaveResult(const CapabilityManager& mgr, uint64_t ptr)
{
bool* const resultPtr = reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr));
*resultPtr = TSD_BITMAP_GET(mgr.GetTsdSupportLevel(), TSD_SUPPORT_BUILTIN_UDF_BIT) ? true : false;
return TSD_OK;
}
void BuiltinUdfWriteUnsupported(uint64_t ptr) { *reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr)) = false; }
bool DriverVersionTryUseStored(CapabilityManager& mgr, uint64_t ptr)
{
(void)mgr;
uint64_t* const resultPtr = PtrToPtr<void, uint64_t>(ValueToPtr(static_cast<uintptr_t>(ptr)));
*resultPtr = 0UL;
return true;
}
TSD_StatusT DriverVersionSaveResult(const CapabilityManager& mgr, uint64_t ptr)
{
(void)mgr;
(void)ptr;
return TSD_CLT_OPEN_FAILED;
}
void DriverVersionWriteUnsupported(uint64_t ptr) { *reinterpret_cast<uint64_t*>(static_cast<uintptr_t>(ptr)) = 0UL; }
bool AdprofTryUseStored(CapabilityManager& mgr, uint64_t ptr)
{
if (mgr.IsAdprofSupport()) {
bool* const resultPtr = reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr));
*resultPtr = true;
return true;
}
return false;
}
TSD_StatusT AdprofSaveResult(const CapabilityManager& mgr, uint64_t ptr)
{
bool* const resultPtr = reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr));
if (resultPtr == nullptr) {
TSD_ERROR("input ptr is null");
return TSD_CLT_OPEN_FAILED;
}
*resultPtr = mgr.IsAdprofSupport();
return TSD_OK;
}
void AdprofWriteUnsupported(uint64_t ptr) { *reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr)) = false; }
void AdprofUpdateState(CapabilityManager& mgr, const HDCMessage& msg) { mgr.SetAdprofSupport(msg.support_adprof()); }
bool MultipleHccpTryUseStored(CapabilityManager& mgr, uint64_t ptr)
{
if (TSD_BITMAP_GET(mgr.GetTsdSupportLevel(), TSD_SUPPORT_MUL_HCCP) != 0U) {
bool* const resultPtr = reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr));
*resultPtr = true;
return true;
}
return false;
}
TSD_StatusT MultipleHccpSaveResult(const CapabilityManager& mgr, uint64_t ptr)
{
bool* const resultPtr = reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr));
*resultPtr = TSD_BITMAP_GET(mgr.GetTsdSupportLevel(), TSD_SUPPORT_MUL_HCCP) != 0U ? true : false;
return TSD_OK;
}
void MultipleHccpWriteUnsupported(uint64_t ptr) { *reinterpret_cast<bool*>(static_cast<uintptr_t>(ptr)) = false; }
const CapabilitySpec kCapabilitySpecs[] = {
{
TSD_CAPABILITY_PIDQOS,
HDCMessage::TSD_GET_PID_QOS,
HDCMessage::TSD_GET_PID_QOS_RSP,
true,
0U,
false,
false,
PidQosTryUseStored,
PidQosSaveResult,
PidQosWriteUnsupported,
PidQosUpdateState,
},
{
TSD_CAPABILITY_LEVEL,
HDCMessage::TSD_GET_SUPPORT_CAPABILITY_LEVEL,
HDCMessage::TSD_GET_SUPPORT_CAPABILITY_LEVEL_RSP,
false,
COMMON_SUPPORT_TIMEOUT,
true,
false,
LevelTryUseStored,
LevelSaveResult,
LevelWriteUnsupported,
LevelUpdateState,
},
{
TSD_CAPABILITY_OM_INNER_DEC,
HDCMessage::TSD_SUPPORT_OM_INNER_DEC,
HDCMessage::TSD_SUPPORT_OM_INNER_DEC_RSP,
false,
SUPPORT_OM_INNER_DEC_MSG_TIMEOUT,
true,
true,
OmInnerDecTryUseStored,
OmInnerDecSaveResult,
OmInnerDecWriteUnsupported,
OmInnerDecUpdateState,
},
{
TSD_CAPABILITY_BUILTIN_UDF,
HDCMessage::TSD_GET_SUPPORT_CAPABILITY_LEVEL,
HDCMessage::TSD_GET_SUPPORT_CAPABILITY_LEVEL_RSP,
false,
COMMON_SUPPORT_TIMEOUT,
true,
false,
BuiltinUdfTryUseStored,
BuiltinUdfSaveResult,
BuiltinUdfWriteUnsupported,
nullptr,
},
{
TSD_CAPABILITY_DRIVER_VERSION,
HDCMessage::INIT,
HDCMessage::INIT,
false,
0U,
false,
false,
DriverVersionTryUseStored,
DriverVersionSaveResult,
DriverVersionWriteUnsupported,
nullptr,
},
{
TSD_CAPABILITY_ADPROF,
HDCMessage::TSD_GET_SUPPORT_ADPROF,
HDCMessage::TSD_GET_SUPPORT_ADPROF_RSP,
false,
COMMON_SUPPORT_TIMEOUT,
true,
false,
AdprofTryUseStored,
AdprofSaveResult,
AdprofWriteUnsupported,
AdprofUpdateState,
},
{
TSD_CAPABILITY_MUTIPLE_HCCP,
HDCMessage::TSD_GET_SUPPORT_CAPABILITY_LEVEL,
HDCMessage::TSD_GET_SUPPORT_CAPABILITY_LEVEL_RSP,
false,
COMMON_SUPPORT_TIMEOUT,
true,
false,
MultipleHccpTryUseStored,
MultipleHccpSaveResult,
MultipleHccpWriteUnsupported,
nullptr,
},
};
}
const CapabilitySpec* FindCapabilitySpec(const int32_t type)
{
for (const CapabilitySpec& spec : kCapabilitySpecs) {
if (spec.type == type) {
return &spec;
}
}
return nullptr;
}
CapabilityManager::CapabilityManager(uint32_t logicDeviceId, DeviceCommAgent& commAgent, bool isAdcEnv)
: logicDeviceId_(logicDeviceId), commAgent_(commAgent), isAdcEnv_(isAdcEnv)
{}
CapabilityManager::~CapabilityManager() {}
void CapabilityManager::ConstructCapabilityMsg(HDCMessage& msg, const int32_t type)
{
MessageContext ctx{};
ctx.logicDeviceId = logicDeviceId_;
ctx.procSign = commAgent_.GetProcSign();
ctx.capabilityType = type;
(void)HdcMessageBuilder::BuildCapability(msg, ctx);
}
bool CapabilityManager::IsOkToGetCapability(const int32_t type) const
{
const CapabilitySpec* spec = FindCapabilitySpec(type);
if (spec == nullptr) {
return false;
}
if (!spec->requiresStartCpAndComm) {
return true;
}
return tsdStartCp_ && (commAgent_.GetDeviceComm() != nullptr);
}
TSD_StatusT CapabilityManager::SendCapabilityMsg(const int32_t type)
{
if (!commAgent_.IsInit()) {
TSD_WARN("[TsdClient] tsd client need open first");
return TSD_OK;
}
HDCMessage msg;
ConstructCapabilityMsg(msg, type);
const TSD_StatusT ret = commAgent_.SendMsg(msg);
return ret;
}
bool CapabilityManager::IsSupportCommonInterface(const uint32_t level)
{
const uint32_t tsdSupportLevel = tsdSupportLevel_;
if (tsdSupportLevel != 0U) {
return TSD_BITMAP_GET(tsdSupportLevel, level) != 0U;
}
TSD_StatusT ret = commAgent_.InitTsdClient(isAdcEnv_);
if ((ret != TSD_OK) || (commAgent_.GetDeviceComm() == nullptr)) {
TSD_ERROR("Init hdc client failed.");
return false;
}
ret = SendCapabilityMsg(TSD_CAPABILITY_LEVEL);
if (ret != TSD_OK) {
TSD_ERROR("SendCapabilityMsg failed");
return false;
}
ret = commAgent_.RecvData(true, COMMON_SUPPORT_TIMEOUT);
if (ret != TSD_OK) {
TSD_RUN_INFO("TSD_CAPABILITY_LEVEL is not supported");
return false;
}
const uint32_t curSupportLevel = tsdSupportLevel_;
if (TSD_BITMAP_GET(curSupportLevel, level)) {
return true;
}
TSD_RUN_INFO(
"IsSupportCommonInterface check was not successful, level[%u], tsd support level[%u]", level, curSupportLevel);
return false;
}
bool CapabilityManager::IsSupportCommonSink()
{
if (!hasGetHostSoPath_) {
hostSoPath_ = tsd::GetHostSoPath();
hasGetHostSoPath_ = true;
}
if (!hostSoPath_.empty()) {
const std::string mutexFile = hostSoPath_ + MUTEX_FILE_PREFIX + "0.cfg";
if (CheckRealPath(mutexFile)) {
TSD_RUN_INFO("mutexFile[%s] found means supporting common sink", mutexFile.c_str());
return true;
}
}
TSD_INFO("hostSoPath is %s.", hostSoPath_.c_str());
return IsSupportCommonInterface(TSD_SUPPORT_COMMON_SINK_PKG_CONFIG);
}
bool CapabilityManager::CheckSubProcSupported(SubProcType procType)
{
struct SubProcCapabilityEntry {
SubProcType procType;
uint32_t capabilityBit;
};
static const SubProcCapabilityEntry kSubProcCapabilityMap[] = {
{TSD_SUB_PROC_UDF, TSD_SUPPORT_HS_AISERVER_FEATURE_BIT},
{TSD_SUB_PROC_NPU, TSD_SUPPORT_HS_AISERVER_FEATURE_BIT},
{TSD_SUB_PROC_BUILTIN_UDF, TSD_SUPPORT_BUILTIN_UDF_BIT},
{TSD_SUB_PROC_ADPROF, TSD_SUPPORT_ADPROF_BIT},
};
for (const SubProcCapabilityEntry& entry : kSubProcCapabilityMap) {
if (entry.procType == procType) {
return IsSupportCommonInterface(entry.capabilityBit);
}
}
return true;
}
bool CapabilityManager::UseStoredCapabityInfo(const int32_t type, const uint64_t ptr)
{
const CapabilitySpec* spec = FindCapabilitySpec(type);
if (spec == nullptr) {
return false;
}
return spec->tryUseStored(*this, ptr);
}
TSD_StatusT CapabilityManager::WaitRspForCapability(const uint32_t timeout, const bool ignoreRecvErr)
{
const TSD_StatusT ret = commAgent_.RecvData(ignoreRecvErr, timeout);
if (ret != TSD_OK) {
if (!ignoreRecvErr) {
TSD_ERROR("tsd client wait capability response fail, ret=%u", static_cast<uint32_t>(ret));
TSD_REPORT_INNER_ERROR("tsd client wait capability response fail, ret=%u", static_cast<uint32_t>(ret));
}
return TSD_CLT_OPEN_FAILED;
}
return TSD_OK;
}
TSD_StatusT CapabilityManager::WaitCapabilityRsp(const int32_t type, const uint64_t ptr)
{
const CapabilitySpec* spec = FindCapabilitySpec(type);
const uint32_t timeout = (spec != nullptr) ? spec->waitTimeout : 0U;
const bool ignoreFail = (spec != nullptr) ? spec->waitIgnoreFail : false;
const TSD_StatusT ret = WaitRspForCapability(timeout, ignoreFail);
if ((ignoreFail) && (ret != TSD_OK)) {
TSD_RUN_INFO("not recv capability:%d rsp", type);
if ((spec != nullptr) && (spec->hasTimeoutFallback)) {
spec->writeUnsupported(ptr);
}
return TSD_OK;
}
TSD_CHECK(ret == TSD_OK, ret, "Wait capability response from device failed.");
const TSD_StatusT saveRet = SaveCapabilityResult(type, ptr);
TSD_CHECK(saveRet == TSD_OK, saveRet, "SaveCapabilityResult failed.");
return TSD_OK;
}
TSD_StatusT CapabilityManager::CapabilityGet(const int32_t type, const uint64_t ptr)
{
if ((!commAgent_.IsInit()) && (type == TSD_CAPABILITY_PIDQOS)) {
TSD_WARN("[CapabilityManager] tsd client need open first");
return TSD_OK;
}
TSD_RUN_INFO("[CapabilityManager] enter into CapabilityGet process deviceId[%u] type[%d].", logicDeviceId_, type);
if (ptr == 0UL) {
TSD_ERROR("input ptr is null");
return TSD_CLT_OPEN_FAILED;
}
if (!IsOkToGetCapability(type)) {
TSD_ERROR(
"[CapabilityManager] startCp[%u],type[%d],sessionid[%u]", static_cast<uint32_t>(tsdStartCp_), type,
commAgent_.GetSessionId());
return TSD_CLT_OPEN_FAILED;
}
if (UseStoredCapabityInfo(type, ptr)) {
return TSD_OK;
}
TSD_StatusT ret = commAgent_.InitTsdClient(isAdcEnv_);
TSD_CHECK(ret == TSD_OK, ret, "Init hdc client failed.");
TSD_CHECK_NULLPTR(
commAgent_.GetDeviceComm(), TSD_INSTANCE_NOT_INITIALED,
"[CapabilityManager] devCommClient_ is null in Close function.");
ret = SendCapabilityMsg(type);
TSD_CHECK(ret == TSD_OK, ret, "SendCapabilityMsg failed.");
TSD_RUN_INFO(
"[CapabilityManager][deviceId=%u] [sessionId=%u] [type=%d]send capability successfully.", logicDeviceId_,
commAgent_.GetSessionId(), type);
ret = WaitCapabilityRsp(type, ptr);
TSD_RUN_INFO(
"[CapabilityManager][logicDeviceId_=%u][type=%d][pidQos=%lld][ret=%u]recv capability response finished.",
logicDeviceId_, type, pidQos_, ret);
return TSD_OK;
}
TSD_StatusT CapabilityManager::SaveCapabilityResult(const int32_t type, const uint64_t ptr) const
{
const CapabilitySpec* spec = FindCapabilitySpec(type);
if (spec == nullptr) {
return TSD_CLT_OPEN_FAILED;
}
return spec->saveResult(*this, ptr);
}
void CapabilityManager::UpdateStateFromMsg(const HDCMessage& msg)
{
const HDCMessage::MsgType msgType = msg.type();
bool handledBySpec = false;
for (const CapabilitySpec& spec : kCapabilitySpecs) {
if ((spec.rspMsgType != msgType) || (spec.updateStateFromMsg == nullptr)) {
continue;
}
spec.updateStateFromMsg(*this, msg);
handledBySpec = true;
break;
}
if (!handledBySpec || (msgType != HDCMessage::TSD_GET_SUPPORT_CAPABILITY_LEVEL_RSP)) {
if (msg.capability_level() != 0U) {
tsdSupportLevel_ = msg.capability_level();
}
}
}
void CapabilityManager::HandlePidQosRsp(const HDCMessage& msg)
{
pidQos_ = msg.pid_of_qos();
const uint32_t realDeviceId = msg.real_device_id();
const uint32_t deviceId = msg.device_id();
const HDCMessage::MsgType msgType = msg.type();
TSD_RUN_INFO(
"[TsdClient] PidQosMsgProc recvMsg realDeviceId[%u] msgType[%u] localDevId[%u] rspCode[%u],pidqos[%lld]",
realDeviceId, static_cast<uint32_t>(msgType), deviceId, msg.tsd_rsp_code(), pidQos_);
}
}