Feature/rdkemw 8587 dlsym - Test#187
Feature/rdkemw 8587 dlsym - Test#187yuvaramachandran-gurusamy wants to merge 75 commits intofeature/RDKEMW-8587-config-dlsymfrom
Conversation
* RDKEMW-4848: pass the proper handle to dsEnableHDCP
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW. Test Procedure: refer RDKEMW-8587 Risks: High Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 31 out of 31 changed files in this pull request and generated 16 comments.
Comments suppressed due to low confidence (1)
ds/frontPanelConfig.cpp:108
- The frontPanelConfig.load() method was removed from the getInstance() method but is now expected to be called separately via loadDeviceCapabilities(). However, there's no guard to prevent operations before load() is called. If code tries to use front panel functionality before loadDeviceCapabilities() is invoked, it will fail because _colors, _indicators, and _textDisplays vectors will be empty. Consider adding a check in getter methods or documenting this initialization requirement.
FrontPanelConfig & FrontPanelConfig::getInstance()
{
static FrontPanelConfig _singleton;
if (!_singleton.m_isFPInitialized)
{
dsError_t errorCode = dsERR_NONE;
unsigned int retryCount = 1;
do
{
errorCode = dsFPInit();
if (dsERR_NONE == errorCode)
{
_singleton.m_isFPInitialized = true;
INT_INFO("dsFPInit success\n");
}
else{
INT_ERROR("dsFPInit failed with error[%d]. Retrying... (%d/20)\n", errorCode, retryCount);
usleep(50000); // Sleep for 50ms before retrying
}
}
while ((!_singleton.m_isFPInitialized) && (retryCount++ < 20));
}
return _singleton;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
rpc/srv/dsVideoPort.c
Outdated
| dsVideoPortResolution_t *kVidoeResolutionsSettings = NULL; | ||
| int iCount = 0; | ||
| dsGetVideoPortResolutions(&iCount, &kVidoeResolutionsSettings); | ||
|
|
||
| // Print kVidoeResolutionsSettings array | ||
| INT_INFO("[DsMgr] ========== Dumping kVidoeResolutionsSettings Array in getPixelResolution ==========\r\n"); | ||
| INT_INFO("[DsMgr] Total resolutions retrieved: %d\r\n", iCount); | ||
| for (int k = 0; k < iCount; k++) { | ||
| dsVideoPortResolution_t *res = &kVidoeResolutionsSettings[k]; | ||
| INT_INFO("[DsMgr] [%d] name=%s, pixelRes=%d, aspectRatio=%d, stereoMode=%d, frameRate=%d, interlaced=%d\r\n", | ||
| k, res->name, res->pixelResolution, res->aspectRatio, | ||
| res->stereoScopicMode, res->frameRate, res->interlaced); | ||
| } | ||
| INT_INFO("[DsMgr] ========== End of kVidoeResolutionsSettings Dump ==========\r\n"); | ||
|
|
||
| for (unsigned int i = 0; i < dsUTL_DIM(kResolutions); i++) | ||
| dsVideoPortResolution_t *Resn = &kVidoeResolutionsSettings[0]; | ||
|
|
||
| for (int i = 0; i < iCount; i++) | ||
| { | ||
| Resn = &kResolutions[i]; | ||
| Resn = &kVidoeResolutionsSettings[i]; |
There was a problem hiding this comment.
Typo in variable name 'kVidoeResolutionsSettings' - should be 'kVideoResolutionsSettings' (missing 'd' in 'Video'). This typo appears multiple times in the file and affects code readability.
| videoPortConfiguration.pKVideoPortConfigs = (dsVideoPortTypeConfig_t*)malloc(numElements * sizeof(dsVideoPortTypeConfig_t)); | ||
| if (videoPortConfiguration.pKVideoPortConfigs == NULL) { | ||
| INT_ERROR("Failed to allocate memory for %s video port configs\n", configType); | ||
| return -1; | ||
| } | ||
|
|
||
| memcpy(videoPortConfiguration.pKVideoPortConfigs, source, numElements * sizeof(dsVideoPortTypeConfig_t)); |
There was a problem hiding this comment.
Shallow copy of structures with pointer members. The memcpy operation performs a shallow copy of dsVideoPortTypeConfig_t structures. Based on the stub definition at stubs/dsVideoPortSettings.h:93-103, these structures contain pointer members like 'supportedResolutions' (line 101). When copying from dynamic configs loaded via dlsym, the pointers will reference memory in the dynamically loaded library. If the library is unloaded (as it is at line 168 of dsConfigs.c), these pointers become dangling, leading to undefined behavior when accessed later. Consider either keeping the library loaded or performing deep copies of the data.
rpc/srv/dsAudioConfig.c
Outdated
| audioConfiguration.pKAudioConfigs = (dsAudioTypeConfig_t*)malloc(numElements * sizeof(dsAudioTypeConfig_t)); | ||
| if (audioConfiguration.pKAudioConfigs == NULL) { | ||
| INT_ERROR("Failed to allocate memory for %s audio configs\n", configType); | ||
| return -1; | ||
| } | ||
|
|
||
| memcpy(audioConfiguration.pKAudioConfigs, source, numElements * sizeof(dsAudioTypeConfig_t)); |
There was a problem hiding this comment.
Shallow copy of structures with pointer members. The memcpy operation performs a shallow copy of dsAudioTypeConfig_t structures which likely contain pointer members (encodings, compressions, stereoModes arrays based on usage at audioOutputPortConfig.cpp:229-241). When copying from dynamic configs loaded via dlsym, the pointers reference memory in the dynamically loaded library. If the library is unloaded (as it is at line 168 of dsConfigs.c), these pointers become dangling, leading to undefined behavior. Consider either keeping the library loaded or performing deep copies.
rpc/srv/dsAudioConfig.c
Outdated
|
|
||
| void audioDumpconfig(audioConfigsLocal_t *config) | ||
| { | ||
| if (nullptr == config) { |
There was a problem hiding this comment.
Mixing C and C++ null pointer constants. In C code (line 52), 'nullptr' is used which is a C++ keyword. In C, use 'NULL' instead. This will cause a compilation error in C code.
| if (nullptr == config) { | |
| if (NULL == config) { |
| void loadDeviceCapabilities(unsigned int capabilityType) | ||
| { | ||
| void* pDLHandle = nullptr; | ||
| bool isSymbolsLoaded = false; | ||
|
|
||
| INT_INFO("Entering capabilityType = 0x%08X", capabilityType); | ||
| dlerror(); // clear old error | ||
| pDLHandle = dlopen(RDK_DSHAL_NAME, RTLD_LAZY); | ||
| INT_INFO("DL Instance '%s'", (nullptr == pDLHandle ? "NULL" : "Valid")); | ||
|
|
||
| // Audio Port Config | ||
| if (DEVICE_CAPABILITY_AUDIO_PORT & capabilityType) { | ||
| audioConfigs_t dynamicAudioConfigs = {0 }; | ||
| dlSymbolLookup audioConfigSymbols[] = { | ||
| {"kAudioConfigs", (void**)&dynamicAudioConfigs.pKConfigs}, | ||
| {"kAudioPorts", (void**)&dynamicAudioConfigs.pKPorts}, | ||
| {"kAudioConfigs_size", (void**)&dynamicAudioConfigs.pKConfigSize}, | ||
| {"kAudioPorts_size", (void**)&dynamicAudioConfigs.pKPortSize} | ||
| }; | ||
|
|
||
| isSymbolsLoaded = false; | ||
| if (nullptr != pDLHandle) { | ||
| isSymbolsLoaded = LoadDLSymbols(pDLHandle, audioConfigSymbols, sizeof(audioConfigSymbols)/sizeof(dlSymbolLookup)); | ||
| } | ||
| AudioOutputPortConfig::getInstance().load(isSymbolsLoaded ? &dynamicAudioConfigs : nullptr); | ||
| } | ||
|
|
||
| // Video Port Config | ||
| if (DEVICE_CAPABILITY_VIDEO_PORT & capabilityType) { | ||
| videoPortConfigs_t dynamicVideoPortConfigs = {0}; | ||
| dlSymbolLookup videoPortConfigSymbols[] = { | ||
| {"kVideoPortConfigs", (void**)&dynamicVideoPortConfigs.pKConfigs}, | ||
| {"kVideoPortConfigs_size", (void**)&dynamicVideoPortConfigs.pKVideoPortConfigs_size}, | ||
| {"kVideoPortPorts", (void**)&dynamicVideoPortConfigs.pKPorts}, | ||
| {"kVideoPortPorts_size", (void**)&dynamicVideoPortConfigs.pKVideoPortPorts_size}, | ||
| {"kResolutionsSettings", (void**)&dynamicVideoPortConfigs.pKResolutionsSettings}, | ||
| {"kResolutionsSettings_size", (void**)&dynamicVideoPortConfigs.pKResolutionsSettings_size} | ||
| }; | ||
|
|
||
| isSymbolsLoaded = false; | ||
| if (nullptr != pDLHandle) { | ||
| isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoPortConfigSymbols, sizeof(videoPortConfigSymbols)/sizeof(dlSymbolLookup)); | ||
| } | ||
| VideoOutputPortConfig::getInstance().load(isSymbolsLoaded ? &dynamicVideoPortConfigs : nullptr); | ||
| } | ||
|
|
||
| // Video Device Config | ||
| if (DEVICE_CAPABILITY_VIDEO_DEVICE & capabilityType) { | ||
| videoDeviceConfig_t dynamicVideoDeviceConfigs = {0}; | ||
| dlSymbolLookup videoDeviceConfigSymbols[] = { | ||
| {"kVideoDeviceConfigs", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs}, | ||
| {"kVideoDeviceConfigs_size", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs_size} | ||
| }; | ||
| isSymbolsLoaded = false; | ||
| if (nullptr != pDLHandle) { | ||
| isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoDeviceConfigSymbols, sizeof(videoDeviceConfigSymbols)/sizeof(dlSymbolLookup)); | ||
| } | ||
| VideoDeviceConfig::getInstance().load(isSymbolsLoaded ? &dynamicVideoDeviceConfigs : nullptr); | ||
| } | ||
|
|
||
| // Front Panel Config | ||
| if (DEVICE_CAPABILITY_FRONT_PANEL & capabilityType) { | ||
| fpdConfigs_t dynamicFPDConfigs = {0}; | ||
| dlSymbolLookup fpdConfigSymbols[] = { | ||
| {"kFPDIndicatorColors", (void**)&dynamicFPDConfigs.pKFPDIndicatorColors}, | ||
| {"kFPDIndicatorColors_size", (void**)&dynamicFPDConfigs.pKFPDIndicatorColors_size}, | ||
| {"kIndicators", (void**)&dynamicFPDConfigs.pKIndicators}, | ||
| {"kIndicators_size", (void**)&dynamicFPDConfigs.pKIndicators_size}, | ||
| {"kFPDTextDisplays", (void**)&dynamicFPDConfigs.pKTextDisplays}, | ||
| {"kFPDTextDisplays_size", (void**)&dynamicFPDConfigs.pKTextDisplays_size} | ||
| }; | ||
| isSymbolsLoaded = false; | ||
| if (nullptr != pDLHandle) { | ||
| isSymbolsLoaded = LoadDLSymbols(pDLHandle, fpdConfigSymbols, sizeof(fpdConfigSymbols)/sizeof(dlSymbolLookup)); | ||
| } | ||
| FrontPanelConfig::getInstance().load(isSymbolsLoaded ? &dynamicFPDConfigs : nullptr); | ||
| } | ||
|
|
||
| if (nullptr != pDLHandle) { | ||
| dlclose(pDLHandle); | ||
| pDLHandle = nullptr; | ||
| } | ||
| INT_INFO("Exiting ..."); | ||
| } |
There was a problem hiding this comment.
Duplicate function implementation. loadDeviceCapabilities is implemented in both manager.cpp (lines 101-184) and dsConfigs.c (lines 84-172). These implementations are nearly identical and load the same device configurations. This code duplication violates DRY principle and creates maintenance burden. Consider consolidating into a single shared implementation or clearly documenting why both are needed.
rpc/srv/dsAudioConfig.c
Outdated
| INT_INFO("Allocated and copied %d audio configs (%s)", numElements, configType); | ||
| return numElements; | ||
| } | ||
|
|
||
| static int allocateAndCopyAudioPorts(const dsAudioPortConfig_t* source, int numElements, bool isDynamic) | ||
| { | ||
| const char* configType = isDynamic ? "dynamic" : "static"; | ||
|
|
||
| if (numElements <= 0) { | ||
| INT_ERROR("Invalid %s port numElements: %d\n", configType, numElements); | ||
| return -1; | ||
| } | ||
|
|
||
| audioConfiguration.pKAudioPorts = (dsAudioPortConfig_t*)malloc(numElements * sizeof(dsAudioPortConfig_t)); | ||
| if (audioConfiguration.pKAudioPorts == NULL) { | ||
| INT_ERROR("Failed to allocate memory for %s audio ports\n", configType); | ||
| return -1; | ||
| } | ||
|
|
||
| memcpy(audioConfiguration.pKAudioPorts, source, numElements * sizeof(dsAudioPortConfig_t)); | ||
| INT_INFO("Allocated and copied %d audio ports (%s)", numElements, configType); |
There was a problem hiding this comment.
The logging function signature changed to include a 'func' parameter, but the INT_INFO macro at line 114 and 134 doesn't include the '\n' character which was present in the previous logging. This inconsistency could affect log formatting, though it appears the new logging function adds its own newline at line 73 of dslogger.cpp.
| vsnprintf(formatted, kFormatMessageSize, format, argptr); | ||
| va_end(argptr); | ||
|
|
||
| if (nullptr != logCb) { | ||
| logCb(priority, tmp_buff); | ||
| logCb(priority, formatted); | ||
| } else { | ||
| return printf("%s\n", tmp_buff); | ||
| fprintf(stderr, "[DS][%d] %s [%s:%d] %s: %s \n", | ||
| (int)syscall(SYS_gettid), | ||
| levelMap[static_cast<int>(priority)], | ||
| fileName, | ||
| lineNum, | ||
| func, | ||
| formatted); |
There was a problem hiding this comment.
Potential buffer overflow risk. The log formatting uses kFormatMessageSize (896 bytes) for the user message, but then formats an additional header that could be up to ~128 bytes. If the user message is exactly 896 bytes, the total formatted output at line 66-72 could exceed MAX_LOG_BUFF (1024 bytes), causing buffer overflow. Consider reducing kFormatMessageSize further or using dynamic allocation.
| static int LoadDLSymbols(void* pDLHandle, const dlSymbolLookup_t* symbols, int numberOfSymbols) | ||
| { | ||
| int currentSymbols = 0; | ||
| int isAllSymbolsLoaded = 0; | ||
|
|
||
| if ((NULL == pDLHandle) || (NULL == symbols)) { | ||
| INT_ERROR("Invalid DL Handle or symbolsPtr\n"); | ||
| return 0; | ||
| } | ||
|
|
||
| INT_INFO("numberOfSymbols = %d\n", numberOfSymbols); | ||
| for (int i = 0; i < numberOfSymbols; i++) { | ||
| if ((NULL == symbols[i].dataptr) || (NULL == symbols[i].name)) { | ||
| INT_ERROR("Invalid symbol entry at index [%d]\n", i); | ||
| continue; | ||
| } | ||
| *(symbols[i].dataptr) = dlsym(pDLHandle, symbols[i].name); | ||
| if (NULL == *(symbols[i].dataptr)) { | ||
| INT_ERROR("[%s] is not defined\n", symbols[i].name); | ||
| } | ||
| else { | ||
| currentSymbols++; | ||
| INT_INFO("[%s] is defined and loaded, data[%p]\n", symbols[i].name, *(symbols[i].dataptr)); | ||
| } | ||
| } | ||
| isAllSymbolsLoaded = (numberOfSymbols) ? (currentSymbols == numberOfSymbols) : 0; | ||
| return isAllSymbolsLoaded; | ||
| } |
There was a problem hiding this comment.
The function return type is declared as 'int' but the function always returns 0 or -1. However, the caller in dsConfigs.c (line 111) checks the result but doesn't actually use the return value properly - it checks 'isSymbolsLoaded' which is the result of this function, then passes it as a boolean to determine whether to use dynamic or static config. The function should return a boolean type (or the caller should be updated to handle -1 as false).
rpc/srv/dsVideoPortConfig.c
Outdated
| return numElements; | ||
| } | ||
|
|
||
| int dsLoadVideoOutputPortConfig(const videoPortConfigs_t* dynamicVideoPortConfigs) |
There was a problem hiding this comment.
The function signature declares return type as 'int', but at line 53 in the header file it's declared as 'void'. This is a function signature mismatch between declaration and definition that will cause compilation errors.
rpc/srv/dsVideoPortConfig.c
Outdated
| INT_INFO("Store sizes configSize =%d, portSize =%d, resolutionSize = %d\n", configSize, portSize, resolutionSize); | ||
| videoPortConfiguration.kDefaultResIndex = defaultResIndex; | ||
| INT_INFO("Store sizes videoPortConfiguration.kDefaultResIndex = %d\n", videoPortConfiguration.kDefaultResIndex); | ||
|
|
||
| INT_INFO("Store sizes configSize =%d, portSize =%d, resolutionSize = %d\n", configSize, portSize, resolutionSize); |
There was a problem hiding this comment.
Duplicate log message at lines 252 and 256. The same information is being logged twice consecutively, which is redundant and clutters the logs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 41 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| int Manager::IsInitialized = 0; //!< Indicates the application has initialized with devicettings modules. | ||
| static std::mutex gManagerInitMutex; | ||
| static dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc); | ||
|
|
There was a problem hiding this comment.
initializeFunctionWithRetry is forward-declared as static but later defined without static, which is a linkage mismatch and typically fails to compile. Also this file uses std::function but doesn't include <functional>. Make the declaration/definition consistent (either both static or both non-static) and add the missing header include.
rpc/srv/dsVideoPort.c
Outdated
| // Print kVideoPortPorts array | ||
| INT_INFO("[DsMgr] ========== Dumping kVideoPortPorts Array in _GetVideoPortType ==========\r\n"); | ||
| INT_INFO("[DsMgr] Total ports retrieved: %d\r\n", numPorts); | ||
| for (int k = 0; k < numPorts; k++) { | ||
| const dsVideoPortPortConfig_t *port = &kVideoPortPorts[k]; | ||
| INT_INFO("[DsMgr] [%d] type=%d, index=%d, connectedAOP_type=%d, connectedAOP_index=%d, defaultResolution=%s\r\n", | ||
| k, port->id.type, port->id.index, | ||
| port->connectedAOP.type, port->connectedAOP.index, | ||
| port->defaultResolution ? port->defaultResolution : "NULL"); | ||
| } |
There was a problem hiding this comment.
The port/resolution array dumps added here run unconditionally at INT_INFO level and iterate over every entry. These functions can be called frequently, so this can create significant log spam and runtime overhead in production. Please gate these dumps behind an existing runtime flag (e.g., /opt/dsMgrDumpDeviceConfigs) or only enable them under INT_DEBUG/higher log level.
| public: | ||
| std::vector<VideoResolution> _supportedResolutions; | ||
| static VideoOutputPortConfig & getInstance(); |
There was a problem hiding this comment.
_supportedResolutions was moved into the public API surface of VideoOutputPortConfig. This exposes internal mutable state and allows callers to bypass locking (gSupportedResolutionsMutex) which can lead to data races or inconsistent cache state. Prefer keeping this member private and providing a const accessor (or a method that fills a caller-provided list) that preserves the class’ synchronization guarantees.
| intptr_t Host::getAudioPortHandle() | ||
| { | ||
| try | ||
| { | ||
| if (isHDMIOutPortPresent()) | ||
| { | ||
| //STB profile with single audio output port | ||
| AudioOutputPort aPort = getAudioOutputPort("HDMI0"); | ||
| return aPort.getOutputPortHandle(); | ||
| } | ||
| else | ||
| { | ||
| //TV profile with multiple audio output ports | ||
| // First check the ports which are dynamically conected and finally fallback to SPEAKER0 which is always connected. | ||
| const std::string audio_ports[] = {"HDMI_ARC0", "HEADPHONE0", "SPDIF0", "SPEAKER0"}; | ||
|
|
||
| // Try each port in priority order | ||
| for (const auto& portName : audio_ports) | ||
| { | ||
| try | ||
| { | ||
| AudioOutputPort aPort = getAudioOutputPort(portName); | ||
| cout << "Checking audio port: " << portName << " isEnabled: " << aPort.isEnabled() << " isConnected: " << aPort.isConnected() << "\n"; | ||
| // Check if port is enabled and connected | ||
| if (aPort.isEnabled() && aPort.isConnected()) | ||
| { | ||
| cout << "Using audio port: " << portName << "\n"; | ||
| return aPort.getOutputPortHandle(); | ||
| } | ||
| } | ||
| catch(const std::exception& e) | ||
| { | ||
| // Port not found or error accessing it, log and continue to next port | ||
| cout << "Exception while accessing audio port " << portName << ": " << e.what() << "\n"; | ||
| continue; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| catch(const std::exception& e) | ||
| { | ||
| cout << " Exception Thrown in getAudioPortHandle().. returning NULL...: " << e.what() << "\n"; | ||
| } | ||
|
|
||
| return NULL; | ||
| } |
There was a problem hiding this comment.
Host::getAudioPortHandle() returns NULL even though the return type is intptr_t. This can be misleading and makes it harder to distinguish “no handle” from a valid numeric handle; it also gets passed into dsGetAudioFormat() immediately after. Return a well-defined invalid handle value (e.g., 0 or -1, matching HAL expectations) and consider logging via INT_* macros instead of cout for consistency with the rest of the module.
| if ( -1 == access("/opt/dsMgrDumpDeviceConfigs", F_OK) ) { | ||
| INT_INFO("Dumping of Device configs is disabled\n"); | ||
| return; | ||
| } | ||
| INT_INFO("\n=============== Starting to Dump VideoPort Configs ===============\n"); | ||
|
|
||
| int configSize = -1, portSize = -1, resolutionSize = -1; | ||
| if (( NULL != config->pKVideoPortConfigs ) && ( NULL != config->pKVideoPortPorts ) && ( nullptr != config->pKVideoPortResolutionsSettings )) | ||
| { |
There was a problem hiding this comment.
This file is compiled as C (.c) but uses C++ nullptr (line 66) and calls access()/F_OK without including the proper header. This will fail to compile on C toolchains (and C99+ treats implicit declarations as errors). Replace nullptr with NULL and add the required includes (e.g., <unistd.h> for access/F_OK; also ensure bool is available via <stdbool.h> or a project header).
ds/videoDeviceConfig.cpp
Outdated
| #define DEBUG 1 // Using for dumpconfig | ||
|
|
There was a problem hiding this comment.
#define DEBUG 1 is introduced but never used in this translation unit. Consider removing it to avoid dead code/macros and accidental interactions with other headers/macros during compilation.
| #define DEBUG 1 // Using for dumpconfig |
| if (NULL == config) { | ||
| INT_ERROR("Video config is NULL\n"); | ||
| return; | ||
| } | ||
| if ( -1 == access("/opt/dsMgrDumpDeviceConfigs", F_OK) ) { | ||
| INT_INFO("Dumping of Device configs is disabled\n"); | ||
| return; |
There was a problem hiding this comment.
access()/F_OK is used here but this C file doesn't include the header that declares it (typically <unistd.h>). On C99+ compilers this can be a hard error due to implicit function declaration. Please include the correct header (and ensure bool is defined via <stdbool.h> or a project header since this file uses bool later).
rpc/srv/dsVideoPort.c
Outdated
| dsVideoPortResolution_t *Resn = &kVidoeResolutionsSettings[0]; | ||
|
|
There was a problem hiding this comment.
getPixelResolution() unconditionally sets Resn = &kVidoeResolutionsSettings[0] even when dsGetVideoPortResolutions() returns iCount == 0 or kVidoeResolutionsSettings == NULL, which will dereference invalid memory. Add a guard for iCount > 0 && kVidoeResolutionsSettings != NULL and return a safe default (or an error) when the resolutions list isn't available.
rpc/srv/dsDisplay.c
Outdated
| const dsVideoPortPortConfig_t *port = &kVideoPortPorts[k]; | ||
| INT_INFO("[DsMgr] [%d] type=%d, index=%d, connectedAOP_type=%d, connectedAOP_index=%d, defaultResolution=%s\r\n", | ||
| k, port->id.type, port->id.index, | ||
| port->connectedAOP.type, port->connectedAOP.index, | ||
| port->defaultResolution); |
There was a problem hiding this comment.
In _GetDisplayPortType(), the log prints port->defaultResolution with %s without a NULL check. If defaultResolution is NULL for any port, this can crash during logging. Use a ternary fallback (e.g., "NULL") like other call sites.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 41 changed files in this pull request and generated 9 comments.
Comments suppressed due to low confidence (1)
rpc/srv/dsDisplay.c:586
- After
malloc(sizeof(dsDisplayEDID_t)), the code checksif (edid == NULL)but the comment says it's handling malloc failure. This should checkedidData == NULL(and also handle the case whereedidDatais NULL beforememset/memcpy_s). As written, an allocation failure will lead to a NULL dereference.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| void dsVideoPortConfigFree(void) | ||
| { | ||
| INT_INFO("Freeing VideoPort configuration resources\n"); | ||
| // Free video port configs | ||
| if (videoPortConfiguration.pKVideoPortConfigs != NULL) { | ||
| free(videoPortConfiguration.pKVideoPortConfigs); | ||
| videoPortConfiguration.pKVideoPortConfigs = NULL; | ||
| INT_INFO("Freed pKVideoPortConfigs\n"); | ||
| } | ||
|
|
||
| // Free video port ports | ||
| if (videoPortConfiguration.pKVideoPortPorts != NULL) { | ||
| free(videoPortConfiguration.pKVideoPortPorts); | ||
| videoPortConfiguration.pKVideoPortPorts = NULL; | ||
| INT_INFO("Freed pKVideoPortPorts\n"); | ||
| } | ||
|
|
||
| // Free video port resolutions | ||
| if (videoPortConfiguration.pKVideoPortResolutionsSettings != NULL) { | ||
| free(videoPortConfiguration.pKVideoPortResolutionsSettings); | ||
| videoPortConfiguration.pKVideoPortResolutionsSettings = NULL; | ||
| INT_INFO("Freed pKVideoPortResolutionsSettings\n"); | ||
| } |
There was a problem hiding this comment.
dsVideoPortConfigFree() frees only the top-level arrays, but allocateAndCopyVideoPortConfigs() and allocateAndCopyVideoPortPorts() deep-copy strings (name, defaultResolution). Those heap allocations will leak unless freed per-entry before freeing the arrays.
| #define INT_ERROR(FORMAT, ...) LOG_ERROR(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__) | ||
| #define INT_WARNING(FORMAT, ...) LOG_WARNING(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__) | ||
| #define INT_INFO(FORMAT, ...) LOG_INFO(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__) | ||
| #define INT_DEBUG(FORMAT, ...) LOG_DEBUG(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__) | ||
| #define INT_TRACE(FORMAT, ...) LOG_TRACE(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__) | ||
|
|
There was a problem hiding this comment.
INT_TRACE expands to LOG_TRACE(...), but LOG_TRACE is not defined anywhere in this header (only DEBUG/ERROR/INFO/WARNING exist). This leaves a broken macro that will fail to compile if INT_TRACE is ever used. Define LOG_TRACE (mapping to an appropriate RDK_LOG level) or remove INT_TRACE.
| { | ||
| if (nullptr == config) { | ||
| INT_ERROR("Audio config is NULL\n"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
audioDumpconfig() uses nullptr, but this file is C (.c) and will not compile. Use NULL (and consider adding a NULL check for edidData-style allocations consistently).
| static int allocateAndCopyAudioConfigs(const dsAudioTypeConfig_t* source, int numElements, bool isDynamic) | ||
| { | ||
| const char* configType = isDynamic ? "dynamic" : "static"; | ||
|
|
||
| if (numElements <= 0) { | ||
| INT_ERROR("Invalid %s config numElements: %d\n", configType, numElements); | ||
| return -1; | ||
| } | ||
|
|
||
| audioConfiguration.pKAudioConfigs = (dsAudioTypeConfig_t*)malloc(numElements * sizeof(dsAudioTypeConfig_t)); | ||
| if (audioConfiguration.pKAudioConfigs == NULL) { | ||
| INT_ERROR("Failed to allocate memory for %s audio configs\n", configType); | ||
| return -1; | ||
| } | ||
|
|
||
| memcpy(audioConfiguration.pKAudioConfigs, source, numElements * sizeof(dsAudioTypeConfig_t)); | ||
| INT_INFO("Allocated and copied %d audio configs (%s)", numElements, configType); | ||
| return numElements; |
There was a problem hiding this comment.
allocateAndCopyAudioConfigs() does a shallow memcpy of dsAudioTypeConfig_t. That struct contains pointer fields (e.g., name, encodings, compressions, stereoModes), so after dsConfigs.c dlclose()s the HAL, these pointers can dangle and cause use-after-free when audio config is accessed. Deep-copy the pointed-to data (and free it in dsAudioConfigFree()), or keep the HAL library loaded for the lifetime of the cached config.
| static dsError_t loadDeviceCapabilities(unsigned int capabilityType) | ||
| { | ||
| void* pDLHandle = NULL; | ||
| int isSymbolsLoaded = 0; | ||
| dsError_t ret = dsERR_GENERAL, audioRet = dsERR_GENERAL, videoRet = dsERR_GENERAL, videoPortRet = dsERR_GENERAL; | ||
|
|
||
| INT_INFO("Entering capabilityType = 0x%08X\n", capabilityType); | ||
| dlerror(); /* clear old error */ | ||
| pDLHandle = dlopen(RDK_DSHAL_NAME, RTLD_LAZY); | ||
| INT_INFO("DL Instance '%s'\n", (NULL == pDLHandle ? "NULL" : "Valid")); | ||
|
|
||
| /* Audio Port Config */ | ||
| if (DEVICE_CAPABILITY_AUDIO_PORT & capabilityType) { | ||
| audioConfigs_t dynamicAudioConfigs; | ||
| memset(&dynamicAudioConfigs, 0, sizeof(audioConfigs_t)); | ||
|
|
||
| dlSymbolLookup_t audioConfigSymbols[] = { | ||
| {"kAudioConfigs", (void**)&dynamicAudioConfigs.pKAudioConfigs}, | ||
| {"kAudioPorts", (void**)&dynamicAudioConfigs.pKAudioPorts}, | ||
| {"kAudioConfigs_size", (void**)&dynamicAudioConfigs.pKConfigSize}, | ||
| {"kAudioPorts_size", (void**)&dynamicAudioConfigs.pKPortSize} | ||
| }; | ||
|
|
||
| isSymbolsLoaded = 0; | ||
| if (NULL != pDLHandle) { | ||
| isSymbolsLoaded = LoadDLSymbols(pDLHandle, audioConfigSymbols, | ||
| sizeof(audioConfigSymbols)/sizeof(dlSymbolLookup_t)); | ||
| } | ||
| audioRet = dsLoadAudioOutputPortConfig(isSymbolsLoaded ? &dynamicAudioConfigs : NULL); | ||
| if(audioRet == dsERR_GENERAL) | ||
| { | ||
| INT_ERROR("dsLoadAudioOutputPortConfig() failed"); | ||
| } | ||
| } | ||
|
|
||
| /* Video Port Config */ | ||
| if (DEVICE_CAPABILITY_VIDEO_PORT & capabilityType) { | ||
| videoPortConfigs_t dynamicVideoPortConfigs; | ||
| memset(&dynamicVideoPortConfigs, 0, sizeof(videoPortConfigs_t)); | ||
|
|
||
| dlSymbolLookup_t videoPortConfigSymbols[] = { | ||
| {"kVideoPortConfigs", (void**)&dynamicVideoPortConfigs.pKVideoPortConfigs}, | ||
| {"kVideoPortConfigs_size", (void**)&dynamicVideoPortConfigs.pKVideoPortConfigs_size}, | ||
| {"kVideoPortPorts", (void**)&dynamicVideoPortConfigs.pKVideoPortPorts}, | ||
| {"kVideoPortPorts_size", (void**)&dynamicVideoPortConfigs.pKVideoPortPorts_size}, | ||
| {"kResolutionsSettings", (void**)&dynamicVideoPortConfigs.pKVideoPortResolutionsSettings}, | ||
| {"kResolutionsSettings_size", (void**)&dynamicVideoPortConfigs.pKResolutionsSettings_size}, | ||
| {"kDefaultResIndex", (void**)&dynamicVideoPortConfigs.pKDefaultResIndex} | ||
| }; | ||
|
|
||
| isSymbolsLoaded = 0; | ||
| if (NULL != pDLHandle) { | ||
| isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoPortConfigSymbols, | ||
| sizeof(videoPortConfigSymbols)/sizeof(dlSymbolLookup_t)); | ||
| } | ||
| videoPortRet = dsLoadVideoOutputPortConfig(isSymbolsLoaded ? &dynamicVideoPortConfigs : NULL); | ||
| if(videoPortRet == dsERR_GENERAL) | ||
| { | ||
| INT_ERROR("dsLoadVideoOutputPortConfig() failed"); | ||
| } | ||
| } | ||
|
|
||
| /* Video Device Config */ | ||
| if (DEVICE_CAPABILITY_VIDEO_DEVICE & capabilityType) { | ||
| videoDeviceConfig_t dynamicVideoDeviceConfigs; | ||
| memset(&dynamicVideoDeviceConfigs, 0, sizeof(videoDeviceConfig_t)); | ||
|
|
||
| dlSymbolLookup_t videoDeviceConfigSymbols[] = { | ||
| {"kVideoDeviceConfigs", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs}, | ||
| {"kVideoDeviceConfigs_size", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs_size} | ||
| }; | ||
|
|
||
| isSymbolsLoaded = 0; | ||
| if (NULL != pDLHandle) { | ||
| isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoDeviceConfigSymbols, | ||
| sizeof(videoDeviceConfigSymbols)/sizeof(dlSymbolLookup_t)); | ||
| } | ||
| videoRet = dsLoadVideoDeviceConfig(isSymbolsLoaded ? &dynamicVideoDeviceConfigs : NULL); | ||
| if(videoRet == dsERR_GENERAL) | ||
| { | ||
| INT_ERROR("dsLoadVideoDeviceConfig() failed"); | ||
| } | ||
| } | ||
|
|
||
| if (NULL != pDLHandle) { | ||
| dlclose(pDLHandle); | ||
| pDLHandle = NULL; | ||
| } | ||
|
|
||
| if(audioRet == dsERR_GENERAL || videoRet == dsERR_GENERAL || videoPortRet == dsERR_GENERAL) | ||
| { | ||
| INT_ERROR("Failed to load device capabilities: audioRet=%d, videoRet=%d, videoPortRet=%d\n", audioRet, videoRet, videoPortRet); | ||
| return dsERR_GENERAL; | ||
| } |
There was a problem hiding this comment.
In loadDeviceCapabilities(), audioRet/videoRet/videoPortRet are initialized to dsERR_GENERAL and later the function returns failure if any remain dsERR_GENERAL, even when that capability wasn't requested in capabilityType. This makes the capabilityType parameter misleading and will break partial loads. Initialize the "*_Ret" variables to dsERR_NONE and only validate the ones corresponding to requested capability bits (or gate the final check by capabilityType).
|
|
||
| if (nullptr != logCb) { | ||
| logCb(priority, tmp_buff); | ||
| logCb(priority, formatted); |
There was a problem hiding this comment.
When logCb is registered, ds_log() now forwards only the raw formatted message (without level/file/line/function context). Since the callback signature is just (priority, const char*), this is a behavior change that drops important context compared to the stderr path. Consider prefixing the message with the same metadata before invoking logCb (or keep the previous behavior).
| logCb(priority, formatted); | |
| char fullMsg[MAX_LOG_BUFF] = {'\0'}; | |
| snprintf(fullMsg, | |
| sizeof(fullMsg), | |
| "[DS][%d] %s [%s:%d] %s: %s \n", | |
| (int)syscall(SYS_gettid), | |
| levelMap[static_cast<int>(priority)], | |
| fileName, | |
| lineNum, | |
| func, | |
| formatted); | |
| logCb(priority, fullMsg); |
| if (_dsGetVideoPortPortConfigs(&numPorts, &pVideoPortPorts) != dsERR_NONE) { | ||
| INT_ERROR("Failed to get video port port configurations\n"); | ||
| return NULL; | ||
| } |
There was a problem hiding this comment.
This function returns NULL on error, but its return type is intptr_t and this module already defines NULL_HANDLE as 0. Returning NULL_HANDLE (or a documented sentinel) would be clearer and avoids pointer-typed semantics in integer APIs.
rpc/srv/dsVideoPortConfig.c
Outdated
| if (videoPortConfiguration.pKVideoPortResolutionsSettings != NULL) { | ||
| for (int i = 0; i < videoPortConfiguration.kResolutionsSettings_size; ++i) { | ||
| if (videoPortConfiguration.pKVideoPortResolutionsSettings[i].name != NULL) { | ||
| free(videoPortConfiguration.pKVideoPortResolutionsSettings[i].name); | ||
| } | ||
| } |
There was a problem hiding this comment.
In the error cleanup path, this code frees videoPortResolutionsSettings[i].name, but dsVideoPortResolution_t::name is a fixed-size array (copied via memcpy), not a heap pointer. Freeing it is invalid and can crash. Remove these per-entry frees and only free the resolutions array itself.
rpc/srv/dsVideoPortConfig.c
Outdated
| if (videoPortConfiguration.pKVideoPortResolutionsSettings != NULL) { | ||
| for (int i = 0; i < resolutionSize; ++i) { | ||
| if (videoPortConfiguration.pKVideoPortResolutionsSettings[i].name != NULL) { | ||
| free(videoPortConfiguration.pKVideoPortResolutionsSettings[i].name); | ||
| } | ||
| } |
There was a problem hiding this comment.
Same issue as above: the cleanup path frees videoPortResolutionsSettings[i].name, which is not heap-allocated. This is an invalid free.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 41 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include "dsserverlogger.h" | ||
| #include "dsTypes.h" | ||
| #include "dsError.h" | ||
| #include "dsAudioConfig.h" | ||
| #include "dsAudioSettings.h" | ||
|
|
There was a problem hiding this comment.
This file uses access()/F_OK but does not include <unistd.h>, which can lead to implicit-declaration warnings/errors depending on compiler flags. Add the proper include so the declaration and F_OK are available.
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include "dsserverlogger.h" | ||
| #include "dsTypes.h" | ||
| #include "dsError.h" | ||
| #include "dsVideoDeviceConfig.h" | ||
| #include "dsVideoDeviceSettings.h" | ||
|
|
There was a problem hiding this comment.
This file uses access()/F_OK but does not include <unistd.h>, which can lead to implicit-declaration warnings/errors depending on compiler flags. Add the proper include so the declaration and F_OK are available.
| public: | ||
| std::vector<VideoResolution> _supportedResolutions; | ||
| std::vector<VideoResolution> _originalSupportedResolutions; | ||
| static VideoOutputPortConfig & getInstance(); |
There was a problem hiding this comment.
Making _supportedResolutions and _originalSupportedResolutions public exposes mutable internal state to the rest of the codebase, which makes it easy to accidentally corrupt the cache and creates tight coupling. Prefer keeping these members private and providing a const accessor (e.g., returning a const std::vector<VideoResolution>& or a read-only List).
|
|
||
| int Manager::IsInitialized = 0; //!< Indicates the application has initialized with devicettings modules. | ||
| static std::mutex gManagerInitMutex; | ||
| static dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc); |
There was a problem hiding this comment.
initializeFunctionWithRetry is forward-declared as static but defined without static later in the file. This changes linkage and typically results in a compile error. Make the declaration/definition consistent (either both static or both non-static).
| static dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc); | |
| dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc); |
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include "dsserverlogger.h" | ||
| #include "dsTypes.h" | ||
| #include "dsError.h" | ||
| #include "dsVideoPortSettings.h" | ||
| #include "dsVideoResolutionSettings.h" | ||
| #include "dsVideoPortConfig.h" |
There was a problem hiding this comment.
This file uses access()/F_OK but does not include <unistd.h>, which can lead to implicit-declaration warnings/errors depending on compiler flags. Add the proper include so the declaration and F_OK are available.
| @@ -52,13 +49,13 @@ static inline const char* fileName(const char* path) { | |||
| #define DS_LOG_LEVEL ERROR_LEVEL | |||
| #endif | |||
|
|
|||
| #define INT_INFO(FORMAT, ...) ds_log(INFO_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ ) | |||
| #define INT_WARN(FORMAT, ...) ds_log(WARN_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ ) | |||
| #define INT_ERROR(FORMAT, ...) ds_log(ERROR_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ ) | |||
| #define INT_INFO(FORMAT, ...) ds_log(INFO_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ ) | |||
| #define INT_WARN(FORMAT, ...) ds_log(WARN_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ ) | |||
| #define INT_ERROR(FORMAT, ...) ds_log(ERROR_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ ) | |||
|
|
|||
| // conditionally enable debug logs, based on DS_LOG_LEVEL | |||
| #if DS_LOG_LEVEL >= DEBUG_LEVEL | |||
| #define INT_DEBUG(FORMAT, ...) ds_log(DEBUG_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ ) | |||
| #define INT_DEBUG(FORMAT, ...) ds_log(DEBUG_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ ) | |||
| #else | |||
| #define INT_DEBUG(FORMAT, ...) ((void)0) | |||
There was a problem hiding this comment.
DS_LOG_LEVEL is defined to the enum identifier ERROR_LEVEL, but #if DS_LOG_LEVEL >= DEBUG_LEVEL is evaluated by the preprocessor. Since enum identifiers aren't macros, they evaluate as 0, which will make this condition behave incorrectly (typically enabling debug logs unconditionally). Define log levels as preprocessor constants (or make DS_LOG_LEVEL a numeric literal) so the #if works as intended.
| static int allocateAndCopyAudioPorts(const dsAudioPortConfig_t* source, int numElements, bool isDynamic) | ||
| { | ||
| const char* configType = isDynamic ? "dynamic" : "static"; | ||
|
|
||
| if (numElements <= 0) { | ||
| INT_ERROR("Invalid %s port numElements: %d\n", configType, numElements); | ||
| return -1; | ||
| } | ||
|
|
||
| audioConfiguration.pKAudioPorts = (dsAudioPortConfig_t*)malloc(numElements * sizeof(dsAudioPortConfig_t)); | ||
| if (audioConfiguration.pKAudioPorts == NULL) { | ||
| INT_ERROR("Failed to allocate memory for %s audio ports\n", configType); | ||
| return -1; | ||
| } | ||
|
|
||
| memcpy(audioConfiguration.pKAudioPorts, source, numElements * sizeof(dsAudioPortConfig_t)); | ||
| INT_INFO("Allocated and copied %d audio ports (%s)", numElements, configType); | ||
| return numElements; |
There was a problem hiding this comment.
allocateAndCopyAudioPorts() does a shallow memcpy of dsAudioPortConfig_t. The port config struct includes pointer members (e.g., connected VOPs in the stub configs), so after dlclose() those pointers can become dangling. Deep-copy any pointer members here as well, and ensure dsAudioConfigFree() frees them.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 41 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
rpc/srv/dsDisplay.c:586
edidDatais allocated withmalloc(), but the subsequent NULL check is againstedidrather thanedidData. If the allocation fails,memset(edidData, ...)will dereference NULL and crash. Please checkedidData == NULL(and separately validateedid) before using it.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (_dsGetVideoPortPortConfigs(&numPorts, &pVideoPortPorts) != dsERR_NONE) { | ||
| INT_ERROR("Failed to get video port port configurations\n"); | ||
| return NULL; | ||
| } |
There was a problem hiding this comment.
dsGetDefaultPortHandle() returns NULL on failure, but the return type is intptr_t (integer). In C this is typically a pointer constant and can trigger -Wint-conversion warnings; also callers likely expect 0/NULL_HANDLE for an invalid handle. Return 0 (or the project’s invalid-handle constant) instead.
| //This function does not have any caller. | ||
| bool isComponentPortPresent() | ||
| { | ||
| bool componentPortPresent = false; | ||
| int numPorts,i; | ||
|
|
||
| numPorts = dsUTL_DIM(kSupportedPortTypes); | ||
| for(i=0; i< numPorts; i++) | ||
| { | ||
| if (kSupportedPortTypes[i] == dsVIDEOPORT_TYPE_COMPONENT) | ||
| int numTypeConfigs = 0; | ||
| const dsVideoPortTypeConfig_t* typeConfigs = NULL; |
There was a problem hiding this comment.
isComponentPortPresent() is not referenced anywhere in the codebase (as noted by the comment) and is currently a non-static symbol in a C translation unit. If it’s meant to be an internal helper, make it static (or remove it) to avoid exporting an unused symbol from the server binary/library.
rpc/srv/dsAudioConfig.c
Outdated
| // Deep copy connectedVOPs array if present | ||
| // Note: We need to know the size of connectedVOPs array | ||
| // For now, assuming it's NULL or a single element (common case) | ||
| // A proper implementation would need size information | ||
| if (src->connectedVOPs != NULL) { | ||
| dest->connectedVOPs = (dsVideoPortPortId_t*)malloc(sizeof(dsVideoPortPortId_t)); | ||
| if (dest->connectedVOPs == NULL) { | ||
| INT_ERROR("Failed to allocate connectedVOPs for audio port %d\n", i); | ||
| // Cleanup previously allocated items | ||
| for (int j = 0; j < i; j++) { | ||
| free((void*)audioConfiguration.pKAudioPorts[j].connectedVOPs); | ||
| } | ||
| free(audioConfiguration.pKAudioPorts); | ||
| audioConfiguration.pKAudioPorts = NULL; | ||
| return -1; | ||
| } | ||
| memcpy((void*)dest->connectedVOPs, src->connectedVOPs, sizeof(dsVideoPortPortId_t)); | ||
| } else { |
There was a problem hiding this comment.
connectedVOPs is deep-copied as if it contains a single dsVideoPortPortId_t, but in the existing stub config it is an array indexed by dsVIDEOPORT_TYPE_MAX (i.e., multiple entries). Copying/allocating only one element will truncate the data and can lead to out-of-bounds reads if callers iterate over the expected array length. Allocate/copy the full expected array size (or add an explicit size field to dsAudioPortConfig_t and copy that many elements).
| int iCount = 0; | ||
| //Get details from libds | ||
| if (_dsGetVideoPortResolutions(&iCount, &pVideoResolutionsSettings) != dsERR_NONE) { | ||
| INT_ERROR("Failed to get video port resolutions\n"); | ||
| } | ||
|
|
There was a problem hiding this comment.
If _dsGetVideoPortResolutions() fails, iCount remains 0 and pVideoResolutionsSettings stays NULL, so the loop never runs and edid->numOfSupportedResolution is left at 0 even if the EDID contains supported modes. Consider returning early without clearing the EDID list, or falling back to the static resolution table so behavior matches the previous implementation.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| libdshalsrv_la_SOURCES = dsHost.cpp hostPersistence.cpp dsAudio.c dsDisplay.c dsFPD.c dsMgr.c dsVideoDevice.c dsVideoPort.c dsserverlogger.c \ | ||
| dsConfigs.c dsAudioConfig.c dsVideoPortConfig.c dsVideoDeviceConfig.c dsCompositeIn.c dsHdmiIn.c |
There was a problem hiding this comment.
dsConfigs.c uses dlopen/dlsym/dlclose, but libdshalsrv_la doesn't appear to link against libdl. On many toolchains this will fail at link time with unresolved dlopen symbols. Consider adding -ldl via libdshalsrv_la_LIBADD (or an appropriate *_LDFLAGS) so the new config loader links reliably.
| /** | ||
| * @brief Retry initialization function with configurable retry logic. | ||
| * | ||
| * This helper function attempts to initialize a device settings component by calling | ||
| * the provided initialization function. It retries the operation with a delay between | ||
| * attempts until either the operation succeeds, the maximum retry count is reached, | ||
| * or (optionally) a specific error state is encountered. | ||
| * | ||
| * @param[in] functionName Name of the initialization function being called. Used for logging | ||
| * purposes to identify which component is being initialized. | ||
| * @param[in] initFunc Lambda or function object that performs the actual initialization. | ||
| * Should return dsError_t indicating success (dsERR_NONE) or an error code. | ||
| * | ||
| * @return dsERR_NONE on successful initialization, or the last error code encountered after | ||
| * all retry attempts are exhausted. When checkInvalidState is true, also returns | ||
| * immediately with the error code if a non-dsERR_INVALID_STATE error occurs. | ||
| */ |
There was a problem hiding this comment.
initializeFunctionWithRetry’s docstring mentions returning early based on dsERR_INVALID_STATE / a checkInvalidState option, but the implementation retries unconditionally for any non-dsERR_NONE result and has no checkInvalidState parameter. Please align the comment with the actual behavior (or implement the described behavior if that was the intent).
| void Manager::Initialize() | ||
| { | ||
| {std::lock_guard<std::mutex> lock(gManagerInitMutex); | ||
| printf("Entering %s count %d with thread id %lu\n",__FUNCTION__,IsInitialized,pthread_self()); | ||
| bool needInit = false; | ||
|
|
||
| {std::lock_guard<std::mutex> lock(gManagerInitMutex); |
There was a problem hiding this comment.
The Manager::Initialize() API comment immediately above this function still references AudioOutputPortConfig::getInstance().load() / VideoOutputPortConfig::getInstance().load() / VideoDeviceConfig::getInstance().load() with no parameters, but these load methods now take dynamic config pointers and are invoked via loadDeviceCapabilities(...). Updating that comment would prevent callers from following an outdated initialization sequence.
| $(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -ldshalcli -shared -o $(LIBNAMEFULL) | ||
| $(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -ldshalcli -shared -o $(LIBNAMECLI) | ||
| $(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMEFULL) | ||
| $(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMECLI) |
There was a problem hiding this comment.
This library now calls dlopen/dlsym (see ds/manager.cpp), but the link command here only adds -lIARMBus -ldshalcli. On many systems you must also link -ldl to resolve these symbols. Consider adding -ldl (or ensuring $(DSHAL_LDFLAGS) already includes it) to avoid link failures.
| $(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMECLI) | |
| $(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMECLI) |
| catch (...) { | ||
| printf("Unknown exception during DeInitialize\n"); | ||
| } |
There was a problem hiding this comment.
Minor: the new printf uses \n while surrounding output in this file uses \r\n. For consistent console output formatting, consider using \r\n here too.
No description provided.