API void rkcmd(s8* pchCmd, ...)
{
if (NULL == pchCmd)
{
return;
}
//////////////////////////////////////////////////////////////////////////
std::string strCmd = pchCmd;
s8* pchParam = NULL;
va_list pArgList;
va_start(pArgList, pchCmd);
for (u32 dwIdx = 0; dwIdx < 0xf; dwIdx++)
{
pchParam = va_arg(pArgList, s8*);
if (NULL == pchParam)
{
break;
}
strCmd += " ";
strCmd += pchParam;
}
va_end(pArgList);
//////////////////////////////////////////////////////////////////////////
MPrintf(">> %s", strCmd.c_str());
// 执行命令并读取其输出
FILE* pipe = popen(strCmd.c_str(), "r");
if (!pipe)
{
MPrintf("popen() err! Failed to run command");
return;
}
// 读取命令的输出
s8 buffer[1024] = { 0 };
while (fgets(buffer, sizeof(buffer), pipe) != NULL)
{
// 去除行尾换行符(兼容 \n 和 \r\n)
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[len - 1] = '\0'; // 去掉 \n
if (len > 1 && buffer[len - 2] == '\r') {
buffer[len - 2] = '\0'; // 去掉 \r(Windows换行)
}
}
MPrintf("%s", buffer);
}
// 关闭管道并等待命令执行完毕
pclose(pipe);
}
这个 rkcmd
函数在执行 rkcmd("dumpmpi vdec");
时崩溃,可能有以下几个原因和对应的解决方案:
1. 命令字符串问题
可能原因:
"dumpmpi vdec"
命令可能包含特殊字符(如空格、引号、换行符等),导致popen()
解析失败。- 命令本身可能不存在,或者路径未正确设置。
解决方案:
- 检查
dumpmpi
是否是可执行程序(在终端运行which dumpmpi
)。 - 尝试用绝对路径调用,例如:
rkcmd("/usr/bin/dumpmpi", "vdec", NULL);
- 如果命令包含特殊字符,需要转义或使用引号包裹。
- 检查
2. 可变参数(va_list
)处理问题
可能原因:
- 调用
rkcmd("dumpmpi vdec")
时,函数内部仍然会尝试读取后续的va_arg
参数,但由于没有传递NULL
终止,可能导致内存越界访问。
- 调用
解决方案:
- 确保可变参数以
NULL
结尾,例如:rkcmd("dumpmpi", "vdec", NULL); // 正确方式
- 或者在函数内部增加更严格的参数检查:
for (u32 dwIdx = 0; dwIdx < 0xf; dwIdx++) { pchParam = va_arg(pArgList, s8*); if (NULL == pchParam || pchParam[0] == '\0') { // 检查空指针或空字符串 break; } strCmd += " "; strCmd += pchParam; }
- 确保可变参数以
3. popen()
执行失败
可能原因:
popen()
可能因为权限不足、命令不存在或系统资源限制而失败。- 未检查
popen()
的返回值直接使用pipe
,导致崩溃。
解决方案:
- 增加错误处理逻辑:
FILE* pipe = popen(strCmd.c_str(), "r"); if (!pipe) { MPrintf("Error: popen() failed! Command: %s", strCmd.c_str()); perror("Reason"); // 打印系统错误信息 return; }
- 增加错误处理逻辑:
4. 缓冲区溢出或内存泄漏
可能原因:
fgets(buffer, sizeof(buffer), pipe)
如果读取超长行,可能导致截断或异常。pclose(pipe)
未检查返回值,可能隐藏了子进程的错误。
解决方案:
- 增加缓冲区检查和进程状态检查:
int status = pclose(pipe); if (status != 0) { MPrintf("Command failed with exit status %d", status); }
- 增加缓冲区检查和进程状态检查:
5. 平台或环境问题
可能原因:
- 代码被编译为其他平台(非
_RK3588_
或_RK3568_
),导致函数实际未执行。 - 动态库或依赖缺失(如
dumpmpi
是某个 SDK 提供的工具,但未正确安装)。
- 代码被编译为其他平台(非
解决方案:
- 确认宏
_RK3588_
或_RK3568_
已正确定义。 - 检查
dumpmpi
是否存在于设备中(通过adb shell which dumpmpi
或直接在设备终端测试)。
- 确认宏
调试建议
简化测试:
先尝试执行一个简单命令,确认函数基础功能是否正常:rkcmd("ls", "/", NULL); // 列出根目录
打印完整命令:
在调用popen()
前打印strCmd
,确认命令拼接正确:MPrintf("Executing: %s", strCmd.c_str());
检查权限:
如果dumpmpi
需要 root 权限,尝试以超级用户身份运行程序。查看系统日志:
通过dmesg
或logcat
查看内核或系统日志,可能会有更详细的错误信息。
如果仍有崩溃,请提供以下信息以便进一步分析:
- 崩溃时的 调用栈(backtrace)。
dumpmpi
是否能在终端直接运行?- 设备的具体系统和版本(如 Android 版本、Linux 发行版等)。