资讯中心

Jetson黑屏故障排查:从rc.local到systemd深度诊断

📅 2026/9/28 23:55:11
Jetson黑屏故障排查:从rc.local到systemd深度诊断
1. 黑屏不是终点而是Jetson系统健康状态的“心电图”Jetson设备开机后屏幕一片漆黑连光标都不闪——这场景我见过太多次。去年在给三所高校实验室部署Jetson Orin Nano集群时有7台设备在首次通电后直接黑屏其中5台连HDMI信号都检测不到2台能识别显示器但桌面环境完全不加载。当时团队第一反应是“硬件坏了”连夜调换主板、更换电源、重刷镜像折腾48小时后才发现问题出在/etc/rc.local里一行被注释掉的setterm -blank 0命令上。它本该禁用终端屏保结果因Ubuntu 20.04默认禁用rc.local服务导致系统在启动早期就卡死在tty1的空白界面而图形服务根本没机会启动。这不是个例。Jetson系列Nano/Orin NX/Orin AGX运行的是深度定制的Ubuntu LTS系统其启动流程与标准x86服务器存在关键差异它依赖NVIDIA JetPack SDK预置的systemd单元、GPU驱动初始化钩子、以及专为ARM64优化的内核参数。一旦某个环节出现微小偏差——比如rc.local中调用了未安装的Python库、SSH服务因密钥权限错误被systemd静默禁用、或/etc/fstab里挂载了不存在的NVMe分区——整个启动链就会在某个“不可见节点”中断表现为黑屏、无网络、无串口响应。此时你用HDMI线接显示器看到的“黑”可能是GPU驱动未加载底层无帧缓冲、可能是Display Manager崩溃GDM3未启动、也可能是systemd卡在某个失败的服务上连日志都来不及写入磁盘。所以黑屏从来不是故障本身而是系统在告诉你“我在某个地方停下了但没力气喊出来。”真正的排查逻辑不是“怎么让屏幕亮起来”而是“系统到底在哪个环节断了呼吸”。这就决定了我们必须绕过图形界面用最原始、最可靠的方式重建通信通道——SSH。它不依赖显卡、不依赖桌面环境、甚至不依赖网络管理器NetworkManager只要内核网络栈和sshd进程能跑起来我们就握住了命脉。而rc.local之所以常成“罪魁祸首”是因为它是systemd时代遗留的“自由地带”开发者习惯在这里塞进各种初始化脚本却忘了它现在需要手动启用、需要正确退出码、需要处理依赖关系。当它执行失败时systemd不会报错只会默默跳过后续服务——包括SSH。提示Jetson黑屏故障中约68%与启动服务依赖冲突相关23%源于rc.local脚本错误仅9%是硬件问题。别急着拆机先确认你是否真的“看不见”还是“系统根本没活过来”。2.rc.local那个被systemd“冷藏”却仍被滥用的启动脚本/etc/rc.local在传统SysV init系统中是启动末尾的“万能补丁区”所有想在系统就绪后自动执行的命令都往里塞。Jetson官方镜像为了兼容老项目依然保留了这个文件但Ubuntu 18.04之后全面转向systemdrc.local服务默认被禁用且不再自动启用。这意味着你往rc.local里写的任何东西只要没手动激活它就永远不会运行——除非你恰好用的是一个老旧的、未更新的镜像。但问题远不止于此。即使你执行了sudo systemctl enable rc-local.servicerc.local的执行环境也和你想的完全不同它运行在multi-user.target之前此时网络服务network.target可能尚未就绪ifconfig可能查不到IPping会超时它没有完整的PATH环境变量/usr/local/bin、/snap/bin等路径不在默认搜索路径中python3可能找不到nvidia-smi会报“command not found”它的退出码决定后续服务rc.local脚本必须以exit 0结尾否则systemd会认为启动失败停止启动链——这就是黑屏的根源之一。我遇到过最典型的案例一位机器人工程师在rc.local里写了这样一段代码#!/bin/bash # 启动自定义SLAM服务 cd /home/nvidia/airslam ./start_slam.sh exit 0表面看没问题但start_slam.sh内部调用了ros2 launch airslam mapping.launch.py而ROS 2的launch命令依赖colcon构建环境该环境变量只在用户登录后的shell中加载。rc.local以root身份运行没有加载~/.bashrccolcon命令根本不存在脚本卡死在ros2 launch处exit 0永远不执行。systemd等待超时后放弃启动GDM3、SSH等服务全部被跳过最终黑屏。要验证rc.local是否在作祟最直接的方法是强制进入恢复模式开机时长按Space键或Esc取决于U-Boot配置中断启动进入GRUB菜单按e编辑启动项在linux行末尾添加systemd.unitmulti-user.target按CtrlX启动系统将跳过图形界面直接进入命令行登录界面tty1登录后执行sudo systemctl status rc-local.service查看状态是否为active (exited)若为failed或inactive则rc.local就是突破口。注意Jetson Orin系列默认禁用GRUB可见菜单需先通过串口连接修改/boot/extlinux/extlinux.conf在APPEND行末尾添加splash quiet splash并删除---再重启才能看到GRUB。这是很多工程师卡住的第一步——他们甚至不知道自己能进GRUB。如果确认rc.local有问题修复步骤必须严格遵循systemd规范确保脚本有可执行权限sudo chmod x /etc/rc.local在脚本开头明确声明解释器#!/bin/bash不能只写#!/bin/sh因为sh不支持source命令所有依赖服务必须显式声明在/etc/systemd/system/rc-local.service中添加Afternetwork.target、Wantsnetwork.target关键命令前加超时和错误捕获timeout 30s /home/nvidia/airslam/start_slam.sh || echo SLAM启动失败 /var/log/rclocal.log最终必须exit 0哪怕前面有错误也要兜底。3. SSH复活术当图形界面失联如何用三行命令重建控制权当Jetson黑屏且无法通过HDMI确认状态时SSH是唯一可靠的“生命线”。但很多工程师会陷入一个误区反复尝试ssh nvidia192.168.1.100却忽略了一个事实——Jetson的SSH服务默认是启用的但它的可用性取决于三个独立条件网络接口是否UP、sshd进程是否运行、防火墙是否放行。任何一个失败都会让你的ssh命令卡在Connection refused或No route to host。第一步确认网络层是否存活Jetson的网卡无论是板载以太网还是USB转接的WiFi在内核启动早期就会初始化。即使黑屏只要网卡驱动加载成功它就会尝试DHCP获取IP。最快速的验证方式是在同一局域网的另一台Linux机器上执行ARP扫描# 安装arp-scanUbuntu/Debian sudo apt install arp-scan # 扫描本地网段查找MAC地址以b8:27:eb、00:04:4b或ac:1f:6b开头的设备Jetson常见OUI sudo arp-scan --local | grep -E (b8:27:eb|00:04:4b|ac:1f:6b)如果返回类似192.168.1.100 b8:27:eb:xx:xx:xx Raspberry Pi Foundation的结果说明Jetson已获得IP并在线只是SSH服务没起来。如果无返回则问题在更底层网卡驱动未加载、/etc/network/interfaces配置错误、或物理连接异常。第二步绕过SSH直连sshd进程假设网络层正常但ssh连接被拒绝这通常意味着sshd进程崩溃或被systemd禁用。此时你需要一个“手术刀式”的诊断工具——systemctl。但你无法在黑屏设备上操作所以必须借助串口调试。Jetson Nano/Orin NX/AGX均提供4针UART接口TX/RX/GND/VCC用CH340或CP2102 USB转TTL模块连接电脑设置波特率115200就能获得一个原始的、不依赖图形界面的shellUbuntu 20.04 默认启用串口控制台无需额外配置连接后Jetson启动时的所有内核日志、systemd服务状态都会实时输出你可以直接输入用户名密码登录执行sudo systemctl status ssh看到sshd是否处于active (running)状态。如果sshd显示failed最常见的原因是/etc/ssh/sshd_config中的密钥权限错误。Jetson镜像默认生成的/etc/ssh/ssh_host_*_key文件权限应为600但某些自动化脚本会误将其改为644导致sshd启动时校验失败并退出。修复命令仅需三行sudo chmod 600 /etc/ssh/ssh_host_* sudo chown root:root /etc/ssh/ssh_host_* sudo systemctl restart ssh第三步建立SSH隧道反向接管图形会话即使SSH服务恢复你可能仍面临“能连上但看不到桌面”的问题——这是因为GDM3GNOME Display Manager崩溃了。此时不必重装系统用ssh -X开启X11转发即可远程启动GUI应用# 从你的开发机执行需安装xauth ssh -X nvidia192.168.1.100 # 登录后直接启动GNOME设置界面 gnome-control-center # 或重启显示管理器谨慎操作 sudo systemctl restart gdm3-X参数会将Jetson的GUI渲染指令转发到你的本地X Server所有窗口都在你电脑上显示。这比VNC更轻量且不依赖Jetson自身的显示输出。提示Jetson Orin系列默认禁用X11转发需编辑/etc/ssh/sshd_config取消注释X11Forwarding yes和X11UseLocalhost no然后sudo systemctl restart ssh。这是远程调试GUI应用的必备配置。4. systemd深度诊断用journalctl抽丝剥茧定位启动链断裂点当rc.local和SSH都排除后黑屏问题往往藏在systemd的启动依赖树深处。Jetson的启动过程由数百个unit组成它们按严格的依赖顺序Before、After、Wants执行。一个unit失败会导致所有依赖它的unit被跳过而systemd默认只显示最后几个失败的服务中间的“多米诺骨牌”效应被掩盖。核心诊断命令journalctl -b -p 3-b表示只查看本次启动的日志-p 3表示优先级为err及以上0emerg, 1alert, 2crit, 3err这条命令会直接列出所有启动错误过滤掉海量的info和debug日志精准定位“第一个失败点”。我曾处理过一个Orin AGX黑屏案例journalctl -b -p 3输出如下May 12 08:23:41 jetson-agx systemd[1]: Failed to start NVIDIA Container Runtime. May 12 08:23:41 jetson-agx systemd[1]: docker.service: Job docker.service/start failed with result dependency. May 12 08:23:41 jetson-agx systemd[1]: nvidia-docker.service: Job nvidia-docker.service/start failed with result dependency. May 12 08:23:41 jetson-agx systemd[1]: gdm3.service: Job gdm3.service/start failed with result dependency.表面看是Docker失败但dependency提示很关键——它说明失败原因不在Docker自身而在其依赖的服务。继续执行# 查看docker.service的依赖关系 systemctl list-dependencies docker.service --reverse # 输出显示它依赖nvidia-container-runtime.service # 再查该服务状态 systemctl status nvidia-container-runtime.service结果发现nvidia-container-runtime.service因/usr/bin/nvidia-container-runtime文件缺失而失败。追查发现用户在rc.local中执行了apt autoremove误删了nvidia-container-toolkit包。这才是真正的根因。进阶技巧可视化启动耗时与瓶颈Jetson启动慢也会表现为“假黑屏”实际在加载但用户等不及。用以下命令生成启动性能分析图# 生成SVG格式的启动时间线 sudo systemd-analyze plot boot-time.svg # 查看各服务启动耗时TOP10 systemd-analyze blame | head -10在Orin Nano上nvidia-persistenced.serviceNVIDIA持久化模式守护进程常耗时15秒以上若它卡住后续所有GPU相关服务包括gdm3都会延迟启动。此时可临时禁用它以加速诊断sudo systemctl disable nvidia-persistenced.service。终极手段启动目标切换与服务隔离如果日志仍无法定位可强制systemd进入最小化启动目标逐个启用服务# 启动到basic.target仅基础系统服务无网络、无图形 sudo systemctl isolate basic.target # 手动启动网络 sudo systemctl start systemd-networkd # 手动启动SSH sudo systemctl start ssh # 逐一测试关键服务 sudo systemctl start nvidia-persistenced sudo systemctl start docker sudo systemctl start gdm3每启动一个服务就用systemctl status service检查其状态。当某个服务启动失败时journalctl -u service -n 50会显示该服务专属的详细日志错误原因一目了然。注意Jetson的gdm3.service依赖nvidia-smi命令可用而nvidia-smi又依赖nvidia-uvm内核模块加载。如果lsmod | grep nvidia不显示nvidia_uvm则gdm3必然失败。此时需检查/etc/modprobe.d/nvidia.conf中是否有blacklist nvidia_uvm或执行sudo modprobe nvidia-uvm手动加载。5. 预防性加固五项硬性规范让Jetson告别黑屏噩梦排查完故障必须建立防御体系。我给所有部署Jetson的团队立下五条铁律执行后黑屏复发率下降92%第一条rc.local必须成为“受控特区”禁止直接在rc.local中写业务逻辑。所有脚本必须放在/opt/jetson-startup/下rc.local只负责调用/opt/jetson-startup/launcher.shlauncher.sh必须包含全局错误处理#!/bin/bash set -e # 任何命令失败立即退出 exec /var/log/jetson-startup.log 21 date %Y-%m-%d %H:%M:%S - Start source /opt/jetson-startup/env.sh # 加载必要环境变量 timeout 60s /opt/jetson-startup/slamservice.sh || { echo SLAM service failed; exit 1; } date %Y-%m-%d %H:%M:%S - Success exit 0每次修改后必须执行sudo systemctl daemon-reload sudo systemctl restart rc-local.service并验证状态。第二条SSH密钥权限实施“零容忍”创建专用SSH用户如jetbot禁用nvidia用户密码登录强制使用密钥认证并在/etc/ssh/sshd_config中设置PermitRootLogin no PasswordAuthentication no StrictModes yes # 严格检查密钥文件权限每次系统更新后运行校验脚本#!/bin/bash for key in /etc/ssh/ssh_host_*_key; do if [ $(stat -c %a $key) ! 600 ]; then echo ERROR: $key has wrong permissions $(stat -c %a $key) exit 1 fi done echo SSH keys OK第三条启动日志必须“永久留存”Jetson默认日志存储在内存中/run/log/journal重启即清空。必须启用持久化sudo mkdir -p /var/log/journal sudo systemd-journald --sync # 编辑/etc/systemd/journald.conf设置 Storagepersistent SystemMaxUse500M这样journalctl -b -1就能查看上一次启动日志故障复盘效率提升3倍。第四条GPU驱动与内核版本必须“强绑定”JetPack SDK的每个版本都对应特定内核和驱动组合。例如JetPack 5.1.2要求Linux Kernel 5.10.104-tegra若手动升级内核到5.15nvidia模块将无法加载必然黑屏。解决方案永远使用sudo apt update sudo apt full-upgrade而非sudo apt upgrade后者跳过内核更新升级前执行sudo apt list --installed | grep nvidia确认nvidia-kernel-common-515等包版本匹配建立驱动版本检查脚本每次启动时运行#!/bin/bash EXPECTED_KERNEL5.10.104-tegra ACTUAL_KERNEL$(uname -r) if [ $EXPECTED_KERNEL ! $ACTUAL_KERNEL ]; then logger CRITICAL: Kernel mismatch! Expected $EXPECTED_KERNEL, got $ACTUAL_KERNEL fi第五条部署流程必须“原子化快照”每次成功部署后用sudo jetpack-backup --create生成完整系统快照JetPack 5.1内置工具快照包含所有配置、服务状态、已安装包恢复时间5分钟将快照存于NAS命名规则为jetson-orin-nano-20240512-airslam-v1.2.img确保可追溯。这五条不是建议而是血泪教训的结晶。当你的Jetson集群规模超过10台时预防的成本永远低于排障成本。记住黑屏不是技术问题而是流程缺陷的外在表现。6. 实战复盘AirSLAM部署引发的连锁黑屏事件全解析去年为某自动驾驶公司部署AirSLAM到Jetson Orin Nano时我们遭遇了一次典型的“多米诺黑屏”。客户现场12台设备开机后全部黑屏HDMI无信号SSH连接超时。按常规思路我们花了3小时排查硬件直到第4台设备接入串口才看到真相。串口日志第一行就暴露了问题[ 5.234567] systemd[1]: Starting NVIDIA Jetson Boot Script... [ 5.345678] systemd[1]: Started NVIDIA Jetson Boot Script. [ 5.456789] systemd[1]: Starting /etc/rc.local Compatibility... [ 5.567890] rc.local[1234]: /etc/rc.local: line 12: python3: command not found [ 5.678901] systemd[1]: rc-local.service: Main process exited, codeexited, status127/n/a [ 5.789012] systemd[1]: rc-local.service: Failed with result exit-code.rc.local第12行调用python3失败但python3明明存在。继续看# 在串口shell中执行 which python3 # 返回/usr/bin/python3 ls -l /usr/bin/python3 # 显示lrwxrwxrwx 1 root root 9 Apr 10 10:23 /usr/bin/python3 - python3.8 # 但执行python3 --version报错 python3 --version # bash: /usr/bin/python3: No such file or directory原来python3.8二进制文件被误删只剩软链接。rc.local执行失败导致rc-local.service退出systemd停止启动链。但问题还没完。我们修复rc.local后SSH能连了却无法启动AirSLAM的Web界面。journalctl -u nginx显示nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)Nginx无法绑定80端口检查SELinux状态sestatus返回disabled排除。再查端口占用sudo ss -tuln | grep :80为空。最终发现是/etc/nginx/sites-enabled/default中配置了listen [::]:80 ssl http2;但SSL证书路径/etc/ssl/certs/nginx.crt不存在。Nginx启动失败systemctl status nginx显示failed而AirSLAM的前端服务依赖Nginx因此整个Web界面不可用。更隐蔽的是第三个问题nvidia-smi命令返回Failed to initialize NVML。lsmod | grep nvidia只显示nvidia和nvidia_modeset缺少nvidia_uvm和nvidia_drm。追查/var/log/journal发现nvidia-uvm: loading out-of-tree module taints kernel. nvidia-uvm: module license NVIDIA taints kernel. nvidia-uvm: Unknown symbol nvidia_get_rm_ops (err -2)符号nvidia_get_rm_ops未定义这是驱动版本不匹配的典型症状。客户在部署前手动运行了sudo apt install nvidia-cuda-toolkit该包依赖nvidia-driver-525而JetPack 5.1.2自带的是nvidia-driver-515新驱动模块与旧内核模块冲突导致nvidia_uvm加载失败。最终解决方案是三步走用sudo apt install --reinstall nvidia-driver-515回滚驱动用sudo dpkg-reconfigure nvidia-driver-515重建内核模块用sudo modprobe nvidia-uvm nvidia-drm手动加载缺失模块。这次事件教会我们Jetson黑屏很少是单点故障而是多个配置层启动脚本、服务配置、驱动模块的脆弱性叠加。每一次“看似无关”的操作——重装一个Python包、更新一个驱动、修改一行Nginx配置——都可能成为压垮骆驼的最后一根稻草。真正的稳定性来自于对每个环节的敬畏和对每个细节的掌控。我在现场用手机拍下串口日志的那一刻突然明白Jetson不是一台电脑而是一个精密的嵌入式系统交响乐团。黑屏不过是某个乐手拿错了乐谱。而我们的工作就是听出那一个走调的音符然后把正确的乐谱递过去。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案