高通camx Node相关
一、node的存放位置
node在camx和chi中均会存在,但存在的位置不一样。
Camx中主要位于:android/vendor/qcom/proprietary/camx/src/(hwl/swl),例如:IFE,IPE,BPS,Sensor等。
Chi中主要位于:android/vendor/qcom/proprietary/chi-cdk/oem/qcom/node/,例如:三方EIS,memcpy等。
二、两种node的差异
Camx node是平台已经封装好的节点,一般不需要改动;而Chi node则是提供给vendor自定义实现的节点,用于自定义算法处理。
三、node是如何启用的
一个node会被编译成一个.so文件。在开机过程中系统会加载很多东西,比如各种应用程序、so文件等等,在加载HAL进程时,会一起加载node。
具体实现如下:
probechicomponents代码如下:
CamxResult ProbeChiComponents(ExternalComponentInfo* pExternalComponentInfo,
UINT* pNumExternalComponent)
//返回so的文件数量fileCountTypeNode = OsUtils::GetFilesFromPath(ExtCompPath,FILENAME_MAX,&soFilesName[0][0],"*", //VendorName"node", //CategoryName
,例如com.qti.node.memcpy.so, com.wt.node.sat.so"*","*",&SharedLibraryExtension[0]);
//循环加载Node节点while (index < fileCountTypeNode + fileCountTypeStats + fileCountTypeHvx){CamX::OSLIBRARYHANDLE handle = CamX::OsUtils::LibMap(&soFilesName[index][0]);// 1.dlopen的封装方法if (index < fileCountTypeNode){pNodeEntry = reinterpret_cast<PFCHINODEENTRY>(CamX::OsUtils::LibGetAddr(handle, "ChiNodeEntry")); // 2.dlsys的封装方法CAMX_ASSERT(NULL != pNodeEntry);pExternalComponentInfo[index].nodeCallbacks.size = sizeof(ChiNodeCallbacks);if (NULL != pNodeEntry){pNodeEntry(&pExternalComponentInfo[index].nodeCallbacks);// 3.Node API’s Callbacks}if (NULL != pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag){GetComponentTag(pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag);}pExternalComponentInfo[index].nodeAlgoType = ExternalComponentNodeAlgo::COMPONENTNODE;}
代码中的核心方法:
1、dlopen
OSLIBRARYHANDLE ChxUtils::LibMap(const CHAR* pLibraryName)
{
OSLIBRARYHANDLE hLibrary = NULL;
const UINT bindFlags = RTLD_NOW | RTLD_LOCAL;
hLibrary = dlopen(pLibraryName, bindFlags);
if (NULL == hLibrary)
{
CHX_LOG_ERROR("Failed to load library %s error %s", pLibraryName, dlerror());
CHX_ASSERT(0 == dlerror());
}
return hLibrary;
}
2、dlsym
VOID* ChxUtils::LibGetAddr(OSLIBRARYHANDLE hLibrary,
const CHAR* pProcName)
{
VOID* pProcAddr = NULL;
if (hLibrary != NULL)
{
pProcAddr = dlsym(hLibrary, pProcName);
}
return pProcAddr;
}
首先要知道.so 库文件是一个 ELF 文件,可以通过 readelf -s 命令查看对应的.so文件描述,如下图可以看到其中有一个 Name 属性为 ChiNodeEntry。
获取node方法总体解释: 也就是:CamX通过GetFilesFromPath遍历camera/components目录下的所有so,调用dlopen()来打开目标库获取handle(定位库文件的地址),然后使用dlsym()来得到符号名字为"ChiNodeEntry"的地址,因为所有Node都有一个入口方法ChiNodeEntry,这样便可以加载所有的Node。
CDK_VISIBILITY_PUBLIC VOID ChiNodeEntry(CHINODECALLBACKS* pNodeCallbacks)
{if (NULL != pNodeCallbacks){if (pNodeCallbacks->majorVersion == ChiNodeMajorVersion &&pNodeCallbacks->size >= sizeof(CHINODECALLBACKS)){pNodeCallbacks->majorVersion = ChiNodeMajorVersion;pNodeCallbacks->minorVersion = ChiNodeMinorVersion;pNodeCallbacks->pGetCapabilities = MemCpyNodeGetCaps;pNodeCallbacks->pQueryVendorTag = MemCpyNodeQueryVendorTag;pNodeCallbacks->pCreate = MemCpyNodeCreate;pNodeCallbacks->pDestroy = MemCpyNodeDestroy;pNodeCallbacks->pQueryBufferInfo = MemCpyNodeQueryBufferInfo;pNodeCallbacks->pSetBufferInfo = MemCpyNodeSetBufferInfo;pNodeCallbacks->pProcessRequest = MemCpyNodeProcRequest;pNodeCallbacks->pChiNodeSetNodeInterface = MemCpyNodeSetNodeInterface;}
}
加载node之后,如何使用node中的方法呢?
通过调用pNodeEntry对pExternalComponentInfo[index].nodeCallbacks参数进行取地址赋值,这样就可以使用Node中的方法,其他的节点类似就好。
总结:node 的加载是通过编译成.so文件使用,当程序起来的时候,就可以使用.so文件,加载node节点,通过ChiNodeEntry,就可以加载node里面的方法。