第一次拿到 OpenHarmony 开发板的人大概率都会经历同一个瞬间SDK 下载完了示例工程编译通过然后满怀信心地在终端敲下hdc_std list targets回车屏幕上回一句不是内部或外部命令或者更含蓄一点——什么都不输出光标静静闪在那里。工具确实已经在硬盘里躺着了只是系统根本不知道它在哪里。hdc_std 的安装配置以及常用命令看上去是入门级别的三件事实际上它横跨了环境变量、USB 驱动、设备鉴权、服务端端口、协议版本这五道关卡任何一道没过后面所有命令都是白敲。hdc_std 是设备连接器Device Connector的命令行实现作用跟 Android 生态里的调试桥几乎一一对应列设备、开 shell、推文件、装应用、抓日志、做端口转发。区别在于它服务的对象是 OpenHarmony 设备命令前缀、参数风格、错误提示全都是另一套东西。很多人在搜索hdc_std的时候会看到大量写着hdc的教程然后怀疑自己是不是找错了资料这件事本身就值得先讲清楚。我下面按自己的实际排查顺序来写先把工具本身讲明白再讲三平台的环境变量怎么配中间重点放在设备识别不出来这类高频坑上最后给出可以直接抄走的命令清单和自动化脚本。1. 为什么你的 SDK 里躺着的是 hdc_std而不是熟悉的 adb1.1 hdc_std 的定位它是通道不是管家先把一个常见的误解拆掉hdc_std 本身不负责编译、不负责打包、不负责签名它只做一件事——在你电脑和设备之间建立一条可控的命令通道。应用能不能装上去取决于 hap 包是否签名、设备是否允许安装hdc_std 只是那个把包推进去的人。搞不清这个边界就很容易在排查时走错方向装不上应用时反复重启 hdc 服务其实问题出在签名证书上。它最常用的能力大致分五类我按使用频率排一下设备发现与连接列设备、连接网络设备、切换设备。命令执行shell进设备或者直接把一条命令丢过去执行。文件搬运file send推上去file recv拉回来。应用生命周期安装、卸载、启动 Ability、强制停止。调试取证日志、快照、性能信息、整机报告。这五类里前两类占了日常操作的八成以上。真正需要翻文档的往往是第四类和第五类里那些带参数的子命令。1.2 客户端与服务端分离才是玄学问题的根源hdc_std 是典型的 C/S 结构。你在终端敲的每一条命令都是一个短命进程它把请求发给一个常驻在后台的 hdc 服务进程由服务进程去和设备通信。这个设计本身没问题但它带来了两个非常经典的故障第一服务进程是常驻的不随客户端退出而退出。所以你升级了 SDK命令行工具换成了新版本后台跑着的还是旧版服务两边协议对不上就会出现类似版本不匹配或命令行为异常的现象。解决办法不是重装 SDK而是把服务重启一遍。第二服务进程监听的端口是固定的。默认情况下这个端口是 8710但如果你同时装了 IDEIDE 启动时会拉起自己那一份 hdc 服务先到先得。于是命令行这边连上去以后操作的是 IDE 那份服务的上下文表现为命令结果和 IDE 里看到的不一致甚至直接连接失败。提示遇到说不清道不明的行为差异先执行一次hdc_std kill再执行hdc_std start让服务端和客户端来自同一份二进制。这一步能干掉相当一部分疑难杂症。我个人的习惯是把重启服务当成排查的第一步而不是最后一步。因为它代价极低几秒钟而收益是排除掉一整类干扰因素。1.3 它和 IDE 内置的那份 hdc 是同一套东西吗不是同一份文件但基本是同一套实现。SDK 里通常有两处可以找到这个工具一处在命令行工具包Command Line Tools的toolchains目录下一处在 IDE 安装目录自带的 SDK 副本里。两处的版本号可能不同功能集合也会有细微差别。这就解释了一个很常见的现象同一条命令在 IDE 的 Terminal 面板里能跑在系统终端里报错。原因往往不是命令写错了而是两边的 PATH 指向了不同版本。我的做法很明确环境变量只指向命令行工具包那份IDE 自带的只让 IDE 自己用。这样在系统终端里敲的命令、在 CI 里跑的命令、在 IDE 里跑的命令指向同一份二进制行为一致出了问题也好复现。顺带说一句命名的事。不同发行渠道里这个二进制可能叫hdc_std也可能直接叫hdc。它们的子命令高度一致文档里看到hdc xxx而自己手上是hdc_std时把前缀换掉即可不用怀疑人生。判断方法很简单敲一次hdc_std -h看帮助里列出的子命令清单只要清单里有list targets、file send、shell这些就是同一个东西。2. 三平台安装与环境变量配置路径、权限、PATH 的实操细节2.1 先找到 toolchains 目录几种典型位置这个工具不需要安装它是个绿色二进制找到它、让它能被系统搜到就完成了全部配置。所以第一步永远是定位路径。下面几种是我在不同环境下遇到过的典型位置实际以你本机的 SDK 版本为准平台典型路径形态备注Windows...\sdk\default\openharmony\toolchains\hdc_std.exe目录内通常还有依赖的动态库文件macOS.../sdk/default/openharmony/toolchains/hdc_std需要可执行权限Linux.../sdk/default/openharmony/toolchains/hdc_std同上且通常需要 udev 规则配合IDE 内置IDE 安装目录下的sdk/.../toolchains/只建议 IDE 自己使用有一个细节容易被忽略在 Windows 上toolchains目录里除了hdc_std.exe往往还有同名的动态库例如hdc_std.dll之类以及一些依赖项。这意味着你不能只把 exe 单独拷到别的地方那样运行时可能因为找不到依赖而直接退出而且退出得悄无声息。要么整目录加进 PATH要么把需要的文件一起带上。我见过不止一个人把 exe 拷到桌面然后双击运行窗口一闪而过以为工具坏了。它压根就不是双击运行的东西。2.2 WindowsPATH 配置和它的两个坑Windows 上的配置路径就两条图形界面里改环境变量或者命令行用setx。图形界面更稳妥命令行更快但是有坑。# 追加到当前用户 PATH注意不要滥用见下方说明 setx PATH $env:PATH;D:\sdk\default\openharmony\toolchains这里有两个必须知道的坑第一个坑是长度截断。setx对路径长度有上限历史实现里超过一定字符数会被截断而截断是无声的——它不会报错只是把后半段吃掉了然后你的 PATH 就永久性地残缺了一块。所以在 PATH 已经很长的情况下别用setx硬拼改用系统属性里的图形界面它支持更长的值而且不覆盖式写入。第二个坑是刷新时机。setx只影响之后新开的进程当前已经打开的终端窗口读不到新值。很多人改完立刻在同一个窗口里验证发现还是不是内部或外部命令就以为改错了来回折腾。正确做法是关掉窗口重开一个。如果只是想临时验证用会话级变量# PowerShell仅当前会话生效改错了重开窗口即可 $env:Path ;D:\sdk\default\openharmony\toolchains:: cmd同样只对当前窗口生效 set PATH%PATH%;D:\sdk\default\openharmony\toolchains我的建议是把会话级命令用来验证路径对不对确认没问题之后再写进持久化配置这样试错成本最低。2.3 macOS 与 Linux软链接比 alias 更靠谱这两个平台上很多人习惯写alias我在自己的机器上不用 alias原因是它会带来一种薛定谔的可用性交互式终端里能跑脚本里跑不了因为非交互式 shell 默认不加载别名。CI 流水线里踩这一脚尤其难受——本地明明好好的一上流水线就报命令找不到。我用的方案是软链接把它放进系统 PATH 已经包含的目录# 先给执行权限SDK 解压后有时会丢掉这一位 chmod x ~/sdk/default/openharmony/toolchains/hdc_std # 软链接到系统 PATH 目录这样交互式终端、脚本、CI 都能用 sudo ln -sf ~/sdk/default/openharmony/toolchains/hdc_std /usr/local/bin/hdc_std # 如果不想用 sudo也可以放到用户级目录前提是它在 PATH 里 mkdir -p ~/.local/bin ln -sf ~/sdk/default/openharmony/toolchains/hdc_std ~/.local/bin/hdc_std软链接还有一个额外好处换 SDK 版本时只需要改链接目标不用动环境变量。我在同时维护两个 SDK 版本的机器上就是这么干的切换版本就是一条ln -sf的事。如果确实想用环境变量那么 macOS 上根据 shell 类型写进~/.zshrc或~/.bash_profileLinux 上写进~/.bashrc# 追加到配置文件末尾注意用 $PATH 而不是覆盖它 export PATH$HOME/sdk/default/openharmony/toolchains:$PATH顺序上我习惯把 SDK 路径放在前面这样系统里如果存在同名的其他工具优先命中的是我们这份。2.4 验证配置成功的三条命令配置完别急着连设备先跑这三条逐级确认# 1. 二进制能不能被找到版本号能不能正常打印 hdc_std -v # 2. 服务能不能起来这一步会暴露依赖库缺失的问题 hdc_std start # 3. 帮助信息能不能出来用来确认子命令集合 hdc_std -h第 1 条失败说明 PATH 没配对第 2 条失败通常是依赖文件缺失或者端口被占第 3 条失败就奇怪了那多半是拿到了一份不完整的文件。这三条都过了再去插设备能省掉一半的排查时间——否则你根本无法区分工具没配好和设备没连上。3. 设备识别不出来时我会按这个顺序排查3.1 第一步永远是看状态Connected、Offline、Unauthorizedhdc_std list targets不输出内容或者说没有目标这是最常见的求助场景。但在下结论之前先把设备状态本身看清楚。加-v参数能看到更详细的信息hdc_std list targets -v输出里通常包含三样关键信息连接标识一串字母数字后面会用来指定设备、传输方式走 USB 还是走网络、以及设备状态。状态大致分三种处理方式完全不同已连接工具和设备握手成功可以直接操作。离线设备出现在列表里但握手没完成多发生在设备刚重启、或者服务端和设备端版本不匹配的时候。未授权设备在等你确认调试请求这一步是安全机制不是故障。很多人看到列表里有东西就以为通了其实状态是未授权然后所有命令都失败开始怀疑配置。加-v是省时间的关键动作一眼就能看出卡在哪一环。3.2 Linux 上绕不开的 udev 规则macOS 和 Windows 的差异USB 设备的访问权限问题三个平台的表现完全不同。macOS 上基本不需要额外配置插上就能识别这是 macOS 比较省心的地方。Windows 上需要驱动匹配。设备第一次接入时如果系统没找到合适的驱动会在设备管理器里显示成一个带感叹号的未知设备。这时候要做的事情是找到 SDK 或开发工具包里随附的驱动目录并安装而不是随便找个通用驱动凑合。驱动装完之后设备管理器里应该能看到对应的调试设备条目再执行hdc_std list targets才可能出结果。Linux 上是权限问题。默认情况下普通用户没有权限直接访问 USB 设备节点表现是工具能看到设备但状态一直不对或者干脆看不到。解决办法是加一条 udev 规则先确认设备的厂商 ID# 插上设备后查看 USB 设备信息找到厂商 ID 和产品 ID lsusb拿到 ID 之后写规则文件# 文件名前缀的数字决定加载顺序随意起个靠后的数字即可 sudo tee /etc/udev/rules.d/99-ohos-hdc.rules EOF SUBSYSTEMusb, ATTR{idVendor}你的厂商ID, MODE0666, GROUPplugdev EOF # 重新加载规则并触发让新规则对已插入的设备生效 sudo udevadm control --reload-rules sudo udevadm trigger规则里MODE0666的意思是让所有用户都能读写这个设备节点在个人开发机上够用。.rules文件里的引号和逗号都不能省格式错一行整条规则就静默失效这也是很多人配完没效果的原因——udev 不会告诉你哪行写错了配完必须重新插拔设备验证。3.3 鉴权弹窗没出现或者点了拒绝之后怎么办首次连接时设备端应该弹出调试授权请求。如果没有弹窗先确认设备是否处于解锁状态——锁屏状态下弹窗是出不来的这是最容易被忽略的一点。我在会议室里调试时经常遇到这个设备息屏了弹窗自然不来。如果误点了拒绝或者想重置授权关系处理方式取决于设备实现通常需要在设备的开发者选项里找到调试相关开关关掉再打开或者清理已授权的记录。不同设备的管理方式差异比较大我没有一个通吃的方法但有一条通用建议首次授权时勾选长期允许能少很多重复确认。还有一个实际使用中的细节授权关系是绑定电脑的。换一台电脑、换一个 USB 口某些情况下会重新枚举都需要重新授权。团队里共用一台调试机时最好固定用同一台电脑和同一个 USB 口避免每次都要去点弹窗。3.4 端口被占和版本打架两个不容易联想到的原因设备状态正常、授权也过了命令还是失败这时候要把注意力从设备转到本机。第一个怀疑对象是端口占用。默认端口 8710 如果被别的进程占了服务起不来客户端连不上。查法很简单# Windows netstat -ano | findstr 8710 # macOS / Linux lsof -i :8710如果确实被占了要么结束占用进程要么让 hdc 用另一个端口。需要注意端口是客户端和服务端两边都要一致才会生效只改一边等于没改。第二个怀疑对象是版本不匹配。客户端和设备的调试服务之间是有协议版本的版本相差太远会表现为设备频繁掉线、命令随机失败、或者状态一直在离线和已连接之间跳。这种情况的根治办法是让 SDK 和设备固件版本互相匹配。我在一块旧开发板上折腾过很久最后发现是固件太老、SDK 太新换回对应版本的 SDK 之后一切正常前面的排查全是白费功夫。注意排查到设备掉线这一步时先确认版本匹配再去查数据线和 USB 口。线材问题确实存在尤其是只供电不传数据的劣质线但它出现的概率远低于版本和驱动问题。4. list targets 之外的连接管理网络连接、多设备与端口转发4.1 让设备监听网络端口摆脱数据线的束缚USB 线连着调试有个现实问题设备要挪动位置、要拿在手上测试传感器线就碍事。hdc 支持网络连接但切换过程有个容易搞错的顺序。正确顺序是先用 USB 连上再让设备切到网络监听模式# 前提USB 已连接且设备状态正常 # 让设备在指定端口上监听调试连接 hdc_std tmode port 8710 # 记下设备当前 IP在设备端查或者到路由器管理界面看 hdc_std shell ifconfig拿到 IP 之后就可以拔掉 USB 线用网络方式连接hdc_std tconn 192.168.1.100:8710这里的关键点是必须先 USB 连上才能切模式。因为tmode这个命令本身要通过已有通道发给设备通道没建立起来命令发不出去。我见过有人直接tconn一个从没连过的 IP然后疑惑为什么连不上——设备端的监听根本没开。网络连接的几个实际注意点电脑和设备必须在同一网段跨网段基本连不上。设备重启后监听状态通常会失效需要重新切一次模式。网络连接的稳定性不如 USB抓日志这种长时间操作建议还是用 USB。如果设备 IP 是动态分配的重启后 IP 可能变化固定 IP 能省不少事。4.2 多设备同时在线时怎么指定目标同时插着开发板和手机、或者同时连着 USB 设备和网络设备时所有命令都会因为目标不明确而失败。这时候要用-t参数指定连接标识# 先列出所有设备把连接标识记下来 hdc_std list targets -v # 指定某个设备执行命令 hdc_std -t 连接标识 shell hdc_std -t 连接标识 install -r app.hap连接标识是list targets -v输出里的第一列通常是一串看起来像哈希的字符。不同版本里这个参数的写法可能有差异有的版本也接受-s以hdc_std -h的输出为准。在脚本里我强烈建议永远显式指定目标哪怕当前只有一台设备。因为某天同事插了一台设备进来你的脚本就会开始随机往别的设备上装包这种问题排查起来非常费劲。4.3 fport 端口转发让浏览器直接访问设备上的服务这个功能用的人不多但一旦用上就很难离开。场景是这样的设备上跑着一个 Web 服务或者调试用的 HTTP 端口你想在电脑浏览器里直接打开它。USB 连接的情况下电脑没法直接访问设备 IP这时候用端口转发把设备的端口映射到本机# 把本机 8080 映射到设备的 8080 hdc_std fport tcp:8080 tcp:8080 # 查看当前已经建立的转发规则 hdc_std fport ls # 用完之后删掉规则避免长期占用 hdc_std fport rm tcp:8080 tcp:8080映射成功后在电脑浏览器打开localhost:8080实际访问的就是设备上的服务。做嵌入式 Web 界面调试时这个方式比把文件导出来在电脑上看要真实得多。有一个失败的常见原因值得单独说设备上的服务只监听了 127.0.0.1。这种情况下转发规则建立成功但访问本机端口还是不通因为转发过去之后服务的监听地址不接受来自外部的连接。解决办法是让设备上的服务监听所有地址0.0.0.0不同服务的配置方式不同需要看具体实现的文档。5. 文件传输、应用安装与 Ability 调试的日常命令5.1 file send 与 file recv路径怎么写才不出错文件传输看起来最没有技术含量但路径写法确实坑过不少人。基本用法# 推送到设备 hdc_std file send D:\build\app.hap /data/local/tmp/app.hap # 从设备拉回来 hdc_std file recv /data/local/tmp/log.txt D:\logs\几个实践中的注意点第一目标目录必须已经存在。file recv里如果写的是一个不存在的目录命令会失败它不会帮你创建。拉文件之前先在电脑上把目录建好。第二Windows 路径里的反斜杠和空格。路径带空格时要加引号不加引号会被拆成两个参数报错信息往往指向文件不存在让人一头雾水。第三权限。往系统目录写文件会失败这是权限决定的不是命令写错了。/data/local/tmp是调试场景下最安全的落点几乎所有设备都允许往里写我默认都推到这儿。第四批量传输的效率。要推几十个小文件时逐个file send会慢得让人失去耐心。我的做法是在电脑上打成一个包推过去再在设备端解开# 电脑上打包Linux/macOS tar -czf bundle.tar.gz ./assets # 推送 hdc_std file send ./bundle.tar.gz /data/local/tmp/bundle.tar.gz # 设备端解包设备上通常有 tar 命令没有的话看具体版本 hdc_std shell tar -xzf /data/local/tmp/bundle.tar.gz -C /data/local/tmp/一次性传输在耗时上通常有数量级的差距尤其是文件多而小的时候。5.2 安装与卸载包必须签名这一点绕不过去安装应用的命令在不同版本里有新老两套写法# 老写法 hdc_std install -r app.hap # 新写法部分版本 hdc_std app install app.hap # 卸载 hdc_std uninstall com.example.myapplication-r的含义是覆盖安装也就是已经装了同一个包名时直接替换。不带这个参数时如果设备上已有同包名应用安装会失败。日常调试一定要带上否则每次改代码都要先卸载再安装来回浪费时间。装不上应用时按这个顺序查包有没有签名。调试版本要用调试证书签正式版本要用正式证书签未签名的包设备不会接受。这是新手最常撞的一堵墙。设备上是不是装了同包名但签名不同的应用。签名不一致的覆盖安装会被拒绝必须先卸载旧包。设备存储空间够不够。空间不足时安装失败报错信息有时候不够直白。推包的方式。直接install时工具自己负责把包传到设备再装如果先file send到设备再在设备端用bm install装路径和参数写法是另一套别混用。设备端安装的写法是这样适合包已经在设备上的场景# 包先推到设备 hdc_std file send app.hap /data/local/tmp/app.hap # 在设备端安装 hdc_std shell bm install -p /data/local/tmp/app.hap # 卸载并保留数据 hdc_std shell bm uninstall -n com.example.myapplication -k5.3 aa 与 bm启动、停止、查版本这两个设备端工具是应用调试的主力。aa管 Ability 的生命周期bm管应用包信息。# 启动指定应用的指定 Ability hdc_std shell aa start -a EntryAbility -b com.example.myapplication # 强制停止应用 hdc_std shell aa force-stop com.example.myapplication # 查看应用包信息包括版本号、安装路径、权限等 hdc_std shell bm dump -n com.example.myapplication # 列出所有已安装应用 hdc_std shell bm dump -abm dump -n是我用得最多的一个。改完代码装上去之后最怕的是装了个旧包——构建产物没更新、装错了路径、缓存没清都可能发生。查一下版本号或者安装时间立刻就能确认装的是不是新的。这个习惯帮我省过好几次代码明明改了但行为没变的困惑。aa start更实用的场景是配合日志使用先清空日志缓冲然后启动应用再抓日志这样拿到的是纯粹的启动过程日志没有其他进程的干扰。具体的操作顺序我放在下一节讲。5.4 shell 里能用的系统命令进到设备 shell 之后能用的命令取决于设备的系统自带工具集。常用的有hdc_std shell ps -ef # 看进程 hdc_std shell df -h # 看磁盘占用 hdc_std shell param get const.product.model # 读系统参数 hdc_std shell power-shell wakeup # 唤醒屏幕 hdc_std shell reboot # 重启设备param get值得单独提一句系统参数里存放着设备和系统的各种信息型号、版本、各种开关状态。想知道设备到底跑的是什么版本读参数比翻设置界面快得多。参数名记不住的话可以不带参数名执行一次把全部参数打出来再找。要注意的是设备端工具集裁剪得比较厉害很多在桌面系统上用过瘾的参数比如某些top的-n在设备上可能不支持。命令报参数错误时先试试不带参数执行或者用设备端工具自己的帮助参数看看支持哪些选项。6. 日志抓取、性能观测与截图把调试证据留在本地6.1 hilog 的正确抓法先清、再抓、后过滤设备端日志系统的命令行入口是hilog通过 shell 调用# 先看支持哪些参数不同版本有差异 hdc_std shell hilog -h # 清空日志缓冲区这一步很关键 hdc_std shell hilog -r # 抓取并落盘到电脑 hdc_std shell hilog hilog.txt先清空再抓这个习惯很重要。设备的日志缓冲区里通常还残留着很久以前的记录不清就直接抓你会得到一个几十兆的文件里面绝大部分内容和当前问题无关。清空之后再复现问题日志量能小一个数量级定位效率完全不一样。如果你的设备不支持清空参数退而求其次的做法是记下当前时间戳抓完之后按时间过滤。效果差一些但也能用。日志量大时的处理思路用管道配合grep在电脑侧过滤别把全部日志都落盘再处理。抓日志期间尽量只做目标操作减少无关进程的干扰。长时间抓取会占用较多磁盘空间提前估算一下时长和速率。很多版本的 hdc 还提供了直接抓日志的子命令形式上更简洁本质还是转发到设备端的日志工具。我的建议是优先用 shell 方式因为它对版本差异的容忍度更高换设备换 SDK 都不容易失效。6.2 bugreport 和 hidumper出问题时该留什么证据应用崩溃、系统行为异常、需要向别人求助时最有效的做法不是描述现象而是把证据打包带走。# 生成整机状态报告输出重定向到本地文件 hdc_std bugreport bugreport.txt # 部分版本需要用 shell 方式调用 hdc_std shell bugreport bugreport.txt这份报告包含系统信息、进程状态、日志片段等是排查系统级问题的第一手材料。它的体积通常不小抓取也要花一些时间所以不适合日常频繁执行只在确实需要的时候抓一次。hidumper是另一个查看系统服务状态的工具可以按服务名查询# 查看某个系统服务的信息 hdc_std shell hidumper -s 服务名 # 查看屏幕和渲染相关信息做性能初筛时有用 hdc_std shell hidumper -s RenderService -a screen服务名和参数在不同系统版本里可能不一样常见的是渲染、窗口、显示这几个。做帧率相关的初步判断时这个命令能给出屏幕刷新和渲染的基本情况够用来判断是不是卡在渲染上不够用来做精细的性能分析。6.3 截图和 UI 操作不用手按屏幕也能测试设备屏幕小、或者设备放在架子上不方便碰的时候用命令截图非常方便# 截图保存到设备临时目录 hdc_std shell snapshot_display -f /data/local/tmp/screen.jpeg # 拉到电脑上看 hdc_std file recv /data/local/tmp/screen.jpeg ./UI 自动化相关的命令走uitest这个入口可以获取当前界面的布局信息和模拟输入# 导出当前界面布局用于分析控件位置 hdc_std shell uitest dumpLayout # 模拟点击指定坐标 hdc_std shell uitest uiInput click 500 1200 # 模拟滑动 hdc_std shell uitest uiInput swipe 500 1500 500 500做重复性验证时这套命令能拼出一个简易的自动化流程截图确认当前界面、点击目标控件、再截图确认结果。虽然不如成熟的测试框架灵活但在快速验证、批量设备操作这类场景下非常实用。坐标值建议从导出的布局文件里读别靠肉眼估不同分辨率下估计出来的坐标很容易点偏。6.4 性能初筛三个够用的观察角度真要做性能分析得上专业工具但日常判断这个应用卡不卡是不是内存泄漏几条命令就能给出方向CPU 和进程状态hdc_std shell top看实时占用。设备端的top参数支持和桌面版不一样先不带参数跑一次看效果。磁盘空间hdc_std shell df -h看分区占用。空间写满会导致各种奇怪现象包括应用启动失败、日志写不进去这个要先排除。内存相关信息通过hidumper或者系统参数读取。不同版本的接口不一样从hidumper -h开始查比较稳。我是这么用的现象是启动慢先df -h排除空间问题再top看启动瞬间哪个进程吃 CPU然后针对性地抓那一段的日志。整个过程五分钟内能有个方向比漫无目的地翻代码高效得多。7. 报错速查表与一个可以直接复用的调试脚本7.1 高频报错对照表把前面几节遇到的问题整理成一张表方便对着症状查原因现象最可能的原因先试什么提示命令不存在PATH 没配好或没刷新重开终端用绝对路径验证启动服务失败端口被占或依赖文件缺失查端口占用确认文件完整设备列表为空驱动、权限、线材、设备未解锁换线换口查 udev 规则或驱动设备状态未授权设备端弹窗未确认解锁设备后重插重新授权状态反复离线版本不匹配或线材问题对齐 SDK 与设备版本换线装机失败包未签名或签名不一致用调试证书重签先卸载旧包推送文件失败目标目录不存在或无权限改用/data/local/tmp转发成功但访问不通设备端服务只监听本机地址让服务监听所有地址日志文件巨大抓之前没清缓冲先清缓冲再复现问题这张表覆盖了我自己踩过的绝大部分坑。用法很简单先看状态再看报错最后才怀疑代码。7.2 一个批量安装加抓日志的脚本骨架下面这个脚本我把骨架和注释都写清楚按自己的实际路径和包名改一改就能用适合在流水线或者日常重复调试里跑#!/usr/bin/env bash # 用法./debug_deploy.sh 连接标识 hap路径 包名 set -euo pipefail TARGET$1 HAP_PATH$2 BUNDLE_NAME$3 LOG_DIR./logs STAMP$(date %Y%m%d_%H%M%S) REMOTE_HAP/data/local/tmp/deploy_${STAMP}.hap mkdir -p ${LOG_DIR} # 0. 确认设备在线避免后续命令全部失败才回头查 hdc_std -t ${TARGET} list targets -v # 1. 先卸载旧版本规避签名不一致导致的覆盖安装失败 hdc_std -t ${TARGET} uninstall ${BUNDLE_NAME} || true # 2. 推包并安装-r 允许覆盖 hdc_std -t ${TARGET} file send ${HAP_PATH} ${REMOTE_HAP} hdc_std -t ${TARGET} install -r ${HAP_PATH} # 3. 确认装上去的确实是新包版本信息记进日志便于追溯 hdc_std -t ${TARGET} shell bm dump -n ${BUNDLE_NAME} \ ${LOG_DIR}/bundle_${STAMP}.txt # 4. 清空日志缓冲然后启动应用 hdc_std -t ${TARGET} shell hilog -r || true hdc_std -t ${TARGET} shell aa start \ -a EntryAbility -b ${BUNDLE_NAME} # 5. 抓一段日志时长按需要调整 timeout 30 hdc_std -t ${TARGET} shell hilog \ ${LOG_DIR}/hilog_${STAMP}.txt || true echo 完成日志目录${LOG_DIR}这个脚本里有三个设计上的取舍值得说明一下。第一uninstall后面跟了|| true。第一次部署时设备上根本没有这个包卸载必然失败加了容错之后脚本不会因为这一步中断。这是先卸载再安装策略能落地的前提。第二每一步都用-t显式指定目标。前面说过原因避免多设备环境下误操作。第三用timeout控制抓日志的时长。日志抓取是个阻塞操作不加限制会一直挂着流水线里会直接超时。30 秒是我常用的默认值实际操作按复现问题所需时间调整。7.3 版本对齐这件事值得单独提醒一次最后说一个我吃过亏的地方SDK 和设备端调试服务的版本要一起升级。很多人只升级了 SDK或者在多台设备之间来回切换用同一套工具就会遇到在这块板子上好好的换一块就不行的现象。前面提到的状态反复离线、命令随机失败很多都源自这里。我的做法是在项目里记录一组经过验证的版本组合——SDK 版本、设备固件版本、工具二进制版本三个一起记遇到换设备换环境时照着这份记录走。看起来有点啰嗦但比在调试现场花两小时查版本号要划算得多。还有一点新增的调试设备最好先做一次完整验证列设备、开 shell、推一个文件、装一个测试包、抓一段日志。这五步都过了说明这台设备和这套工具是匹配的后面的调试就能专心在应用本身不用再分心怀疑环境。这五步走下来也就两三分钟但能省掉的麻烦远不止两三分钟。