• 发生时间:2022-10-08

  • 问题描述:

    • 同事 A 在做功能测试时,发现 IMU 测试失败,设备端返回失败信息:{"name": "imu_test", "code": 1, "message": "imu calib failed"}
    • 但是 ssh 登录设备后,执行 run.sh imu test,设备端可以返回成功信息:{"name": "imu_test", "code": 0, "message": "imu_test is success"}
  • 问题类别:软件调试

  • 原因分析:

    • 设备端能够返回失败信息,说明网络连接是正确的。那为什么 ssh 登录后执行命令可以成功,而上位机执行命令却会失败呢?
    • 一番思索过后,同事 A 尝试直接在终端执行上位机代码里的完整命令,得到以下结果:
    $ ssh -i id_rsa.pub -o "StrictHostKeyChecking no" root@host "run.sh imu test"
    
    ./bin/imu_test: error while loading shared libraries: libdds_api.so: cannot open shared object file: No such file or directory
    {"name": "imu_test", "code": 1, "message": "imu calib failed"}
    
    • 根据报错信息,已经能够确定是嵌入式软件的问题了——执行 imu_test 文件时由于无法加载动态链接库而报错。但为什么 ssh 登录后再执行命令就不会报错呢?
    • 经过网上搜索,在 Stack Exchange 的一个回答 中找到了答案:
      • ssh 登录远端设备的 Linux 系统时,会启动 bash 进程,并加载一些初始化脚本,比如 ~/.bashrc/etc/profile 等。
      • ssh 不登录远端设备,直接连接远端设备执行命令时,不会启动 bash 进程,也不会加载那些初始化脚本。
      • 设备系统里的 imu_test 程序所依赖的动态链接库 libdds_api.so 的路径,是在 /etc/profile 脚本中被添加到环境变量 PATH 的; 但由于我们不登录设备,所以 /etc/profile 没有被加载,从而导致 imu_test 程序找不到动态链接库而报错。
  • 解决方案:

    • 根据嵌入式同事 B 的建议,可以将上位机要执行的命令改为. /etc/profile; run.sh imu test
    • 但这显然对用户并不友好,不是种优雅的解决方案。嵌入式命令本身应该处理好环境变量加载,不应该把这个细节暴露给用户。
    • 经过沟通,嵌入式同事同意修改嵌入式软件,在 run.sh 脚本中增加初始化环境变量的操作。这样上位机不需进行修改。
  • 实施结果:

    • 按照嵌入式组的建议临时修改命令后,上位机可以执行成功。
    • 最终的解决方案,需要等嵌入式同事发布版本后才能验证。
  • 经验总结:

    • 目前上位机软件采用 ssh 连接远端主机直接执行命令的方案,因此有必要理解它与 ssh 登录后再执行命令的差异:前者不会加载初始化脚本,后者会。
    • 上位机的日志打印需要优化,要能够把关键的报错信息报告出来。(这里上位机将设备端的关键报错信息屏蔽掉了,否则可以更快地定位到问题原因。)