
1. 为什么要在LabVIEW里执行adb shell操作1.1 这套需求到底解决什么问题做自动化测试或者产线验收的上位机工程师大概率都遇到过这类需求被测设备是安卓平板、安卓手机甚至车机中控上位机用LabVIEW写好了界面和逻辑但还需要对设备做点系统级的操作比如安装/卸载App、抓取日志、读取设备序列号、模拟按键、设置系统属性、查看当前运行的进程、控制WiFi开关等。这些操作如果靠人去手动点屏幕产线上一台设备的测试时间会被拉得很长而且容易误触。如果用ADB工具去做又只能脱离LabVIEW单独跑命令行没法把数据整合到上位机软件里。于是“让LabVIEW直接执行adb命令”就成了刚需。我处理过的典型场景包括整机出厂前用LabVIEW跑功能测试第一步需要读取安卓设备SN号和主板条码做比对这时候直接用adb shell getprop ro.serialno把结果读进LabVIEW字符串比让操作员手动录入靠谱一万倍。老化测试过程中需要每隔5分钟抓一次logcat日志再把日志文件从设备里拉回来存档。UI自动化回归测试里需要用adb shell input tap x y去点击屏幕指定坐标让LabVIEW去驱动安卓App完成一系列操作不等App停留在某个界面。设备死机或者App崩溃之后通过adb shell执行重启、清缓存、恢复出厂等操作让整个测试流程自动继续。说白了这一套东西就是把安卓设备的底层操作能力整合进LabVIEW的上位机流程里做到自动化和数据可视化。1.2 方案选型为什么选择System Exec.vi而不是别的LabVIEW里调用外部程序最常用的就几条路System Exec.vi、OpenG Toolkit的Exec.vi、调用Windows API的CreateProcess、还有通过.NET的Process类封装。我一开始也纠结过因为System Exec.vi有它的短板比如它弹出的命令窗口容易闪一下返回的字符串编码存在坑。但实测之后发现对其他方案来说坑更多。CreateProcess虽然不会弹窗但你要自己处理管道重定向、等待结束、取退出码代码量一大截.NET Process类功能强但很多LabVIEW用户并不熟悉.NET语法和属性方法排错也费劲。选用System Exec.vi的理由很直接它是LabVIEW自带的官方原生节点不需要额外安装工具包干净。输入输出都是字符串和路径方便我们动态拼接命令参数。自带标准输出、标准错误输出和退出码输出端口做异常判断足够。可以设置是否等待命令结束、是否最小化运行窗口基本够应付绝大多数adb场景。在实际项目里我还见过有人用Python脚本包一层再由LabVIEW调Python也能做但多引入了一套Python环境跨设备部署时麻烦。优先把System Exec.vi用明白大部分时候根本不需要绕路。2. adb shell的核心机制和准备工作2.1 adb到底是什么shell又是怎么回事ADB的全称是Android Debug Bridge翻译过来就是安卓调试桥。它其实是一个CS架构的工具由三部分组成PC端的客户端、PC端的服务端守护进程、设备端的adbd守护进程。PC端发命令给服务端服务端通过USB或者TCP/IP把命令送到设备端的adbd去执行结果原路返回。理解了这个机制你就明白为什么在LabVIEW里执行adb命令时第一条命令往往会慢几百毫秒因为PC端的adb服务可能还没启动需要先拉起服务端。这也是为什么连续执行多条adb命令时第一次总是感觉卡一下的原因。而adb shell后面的内容是直接在设备的Linux内核里执行shell命令。注意这个shell不是安卓应用层的shell而是设备系统底层的shell环境。所以你可以执行getprop查看系统属性、用dumpsys查看系统服务状态、用top看CPU占用、用input模拟触摸甚至用settings修改系统配置项。有个关键点得说清楚adb shell命令是在设备端执行的但命令对应的进程是运行在设备上的而adb install这类不带shell的命令则是PC端和服务端直接交互走的是ADB协议同步通道。两者不是一回事拼接LabVIEW命令字符串时意识要清晰。2.2 准备工作先把PC端的adb环境搞干净在LabVIEW里写再好的程序如果PC端的adb环境本身有问题一切都是白搭。准备工作按这个顺序做第一步下载Android Platform Tools。Google官方提供了各平台的压缩包解压后里面有adb.exe、fastboot.exe等文件。不要只复制一个adb.exe出来整个目录最好保持完整因为后续可能会用fastboot而且adb运行时也依赖目录里的DLL文件。第二步配置环境变量或者干脆不配置。很多人习惯把platform-tools加进PATH环境变量这样在命令窗口里直接输adb就行。但在LabVIEW里调System Exec.vi时存在一个坑System Exec.vi默认继承LabVIEW进程的环境变量如果你改了系统环境变量LabVIEW必须重启才会生效否则运行时它可能根本找不到adb命令。我建议直接给System Exec.vi传完整的adb.exe路径别依赖环境变量少一个变数。第三步连接设备验证通路。用USB连上设备后先打开开发者选项和USB调试开关部分设备还要把USB模式从“仅充电”切到“传输文件”。然后在命令窗口输入adb devices正常情况下会看到类似输出List of devices attached ABCDEF123456 device如果显示unauthorized是设备上弹出的USB调试授权窗口没点允许如果显示offline通常是驱动问题或者USB线质量太差。建议在项目正式开始前先把这条命令跑到稳定输出。2.3 无线连接方式在某些场景下更好用做长期老化测试时设备放在温箱里USB线穿进去不方便或者产线上设备要频繁插拔这时候用无线ADB连接会舒服很多。先说有线连接做一次TCP/IP模式的开启。设备通过USB连上PC后执行adb tcpip 5555然后拔掉USB用设备IP连接adb connect 192.168.1.88:5555之后一切adb命令操作照旧。注意如果设备重启tcpip模式一般会自动保持但还是建议测试程序里做一个断线重连机制防止设备重启后adb通道失效导致后续命令全部超时。无线连接在LabVIEW里的优势是程序跑起来之后不再依赖USB物理链路设备放在哪里都行测试过程中还能腾出USB口给功率计、串口设备。缺点是稳定性和带宽不如USB传大文件时速度会慢一些。3. LabVIEW里执行adb命令的完整实操过程3.1 System Exec.vi的接线细节在LabVIEW的程序框图中函数选板里找到“互联接口”-“库与可执行程序”-“执行系统命令”这就是System Exec.vi。它长着一副很朴素的样子但每个端口都用得着command line你要执行的全部命令字符串比如C:\platform-tools\adb.exe devices。working directory工作目录一般不用填但如果你执行的命令需要相对路径读取文件就得设置。standard input标准输入流大多数情况不用。standard output命令的标准输出返回字符串。standard error标准错误输出命令报错信息走这里。exit code命令退出码。这个很重要adb命令执行成功返回0失败返回非0这是LabVIEW里判断命令是否成功的依据。run minimized和wait until completion建议把wait until completion设为True因为我们需要获取输出结果不等待就没意义了。run minimized设为True会让弹出的命令行窗口最小化体验好一点。接线示例命令字符串用拼接字符串函数动态生成比如要获取设备SNC:\platform-tools\adb.exe -s ABCDEF123456 shell getprop ro.serialno把这条字符串接进command line端口运行VI后standard output输出设备SN字符串注意这个字符串结尾带着换行符在LabVIEW里做字符串比较前最好用“截取字符串”或“搜索替换字符串”去掉首尾空白。3.2 参数拼接和字符串转义问题LabVIEW里做adb命令拼接最容易翻车的不是命令本身写错而是路径里的空格、引号、反斜杠。比如adb安装在C:\Program Files\platform-tools\adb.exe“Program Files”中间有空格如果直接拼成字符串传给System Exec.vicmd解析时会把路径拆成两段命令执行失败。解决办法是给可执行文件路径加双引号C:\Program Files\platform-tools\adb.exe devices在LabVIEW的字符串常量里输入双引号只需要直接敲字符不需要转义。这个和C语言不一样LabVIEW字符串里没有反斜杠转义的概念反斜杠就是普通字符所以路径里的\直接写就行不用写成\\。但传入shell层的内容就不一样了。设备端shell命令里有特殊字符时外层Windows的cmd会先做一次解析然后adb再传一层给设备端shell。两层解析意味着引号和特殊字符可能要套两层。举个例子想在设备端查看某个目录的详细内容adb shell ls -l /sdcard/test这条命令没有特殊字符直接执行就行。但如果要在设备端执行带空格的多个参数比如设置系统属性值adb shell setprop persist.sys.timezone Asia/Shanghai注意设备端shell要求路径或值带引号这个引号需要传到设备端所以PC端字符串里要写成adb shell setprop persist.sys.timezone \Asia/Shanghai\LabVIEW的字符串里写\Windows cmd会收到Asia/Shanghai然后adb把整个参数带上引号传给设备端shell设备端shell才能正确解析。这一层嵌套没想清楚命令就会莫名其妙地报错“bad argument”。另外还有一个脚本化技巧如果命令特别长、特别复杂与其在LabVIEW里拼一个超长字符串不如在PC端写个批处理脚本或者shell脚本再通过adb shell sh /sdcard/test.sh来执行。LabVIEW只需要调一次启动脚本的命令逻辑维护成本大大降低。3.3 输出字符串的编码处理尤其是中文乱码跑过dumpsys package或者logcat的人一定遇到过返回的中文在LabVIEW的前面板显示成乱码英文和数字正常看上去很奇怪。原因不复杂adb shell返回的是UTF-8编码的字节流Windows上的cmd默认代码页是GBK或者936System Exec.vi在接收输出时按照系统ANSI代码页去解析字符串UTF-8和GBK对不上中文自然就乱成了“锟斤拷”。这个问题有几种解法在命令字符串最前面加chcp 65001切换代码页比如cmd /c chcp 65001 adb shell getprop ro.product.name。实测大部分场景有效但偶尔会因为切换时机太慢导致前面几条输出还是乱码。用LabVIEW的字符串转字节数组功能拿到原始字节流再按UTF-8解码。这一步要用到“字符串至字节数组转换”和“还原字符串”组合前面板显示就正常了。麻烦是要区分哪些命令返回UTF-8、哪些返回ASCII好在大多数adb命令默认就是UTF-8。从源头避免中文输出。在脚本或命令中尽量用英文、数字作为关键输出必须保留的中文写成Unicode转义或者Base64编码LabVIEW拿到后再解码。这个思路在产线程序里很实用因为产线后台系统一般也不喜欢处理中文日志。我的习惯是如果只是为了解析数值和状态命令里就只输出英文关键词如果必须抓取中文内容在LabVIEW里做一次UTF-8解码并且把解码函数做成子VI复用。3.4 用退出码和输出内容双重判断命令执行情况在LabVIEW里判断adb命令是否成功只看exit code是不行的。adb shell命令在设备端执行设备端有没有报错返回给PC端的退出码有时候仍然是0。比如执行adb shell rm /sdcard/test.txt文件不存在时设备端会打印“rm: /sdcard/test.txt: No such file or directory”但退出码可能照样是0。更稳妥的做法是exit code等于0是基础条件同时还得在standard error或者standard output里检查有没有关键字比如“No such file”、“error”、“failed”。两重判断都通过了才认为命令真正执行成功。LabVIEW里可以用搜索替换字符串函数在输出里查找特征词找到就点亮错误指示灯。这个细节看着不起眼实际在产线自动化里非常重要——因为一个误判导致的测试假通过比直接报错还可怕它会放走不良品。4. 复杂自动化场景的进阶玩法4.1 Android UI自动化用input命令模拟点击和输入不需要安装任何Appadb shell自带的input命令就可以模拟触摸、滑动和按键。这在LabVIEW驱动安卓端App做功能测试时非常管用。常用命令举例点击坐标adb shell input tap 540 960滑动屏幕adb shell input swipe 540 1500 540 300 300最后的300是滑动耗时毫秒输入文字adb shell input text hello按返回键adb shell input keyevent KEYCODE_BACK也就是input keyevent 4按主页键adb shell input keyevent KEYCODE_HOME也就是input keyevent 3把这些命令组合起来LabVIEW就能像人一样操作安卓设备启动App、点击按钮、填写表单、返回退出。我用过的一个场景是批量给测试设备设置WiFi密码。设备出厂后第一次开机需要在设置界面输入WiFi账号和密码用LabVIEW控制坐标点击和文本输入一台设备40秒搞定比人工快多了。注意input text对中文字符支持很差有中文输入需求时最好用剪贴板方式或者先切到英文输入法再输入ASCII字符。坐标点击还有一个坑不同分辨率下坐标位置不一样程序里要做分辨率归一化用相对坐标计算。4.2 抓取logcat日志并拉取到PC端做App稳定性测试时logcat是排查崩溃和ANR的第一手资料。LabVIEW里分三步操作第一步清空旧日志adb logcat -c第二步执行测试动作让App跑一段时间。第三步抓取日志并保存到文件adb logcat -d C:\test\app_log.txt在System Exec.vi里输出重定向符号是可以直接用的但要注意如果你把 C:\test\app_log.txt写在命令字符串里LabVIEW的standard output端口就是空的内容全部进了文件这是正常现象。还有一种更灵活的办法不在命令里重定向而是用System Exec.vi的standard output字符串直接拿到logcat内容再用LabVIEW的“写入文本文件”函数保存。这样可以在保存前对日志做初步过滤比如只保留包含“AndroidRuntime”或者“FATAL EXCEPTION”的行减少存储压力。logcat的坑在于它和崩溃日志的时序。如果App是瞬间崩溃然后立即重启-d模式抓到的日志可能已经把崩溃信息滚过去了这时候需要用-t参数指定日志条数比如adb logcat -d -t 500抓取最后500行。4.3 性能数据采集CPU、内存、帧率LabVIEW做性能测试工具也有绕不开的场景一台设备跑游戏或者跑导航每隔一段时间记录CPU占用率、内存占用和帧率。CPU和内存信息可以通过top命令拿adb shell top -n 1 -b-n 1表示只取一次-b是batched模式适合脚本解析。输出里能找到CPU总体使用率、各进程的CPU占比和内存占用。在LabVIEW里用“匹配模式”函数解析出目标App的进程行就行。帧率用dumpsys gfxinfo拿adb shell dumpsys gfxinfo com.example.myapp输出末尾的Histogram和统计信息里有帧时间数据能算出平均帧率、丢帧率。这块解析起来稍微复杂但把关键字定位写清楚以后后面就是一劳永逸的事情。性能采集要特别注意采样频率。adb命令本身有执行开销一条dumpsys可能耗时几百毫秒如果采样间隔设得太短采到的数据其实是上一轮命令还没执行完就发了新命令导致数据错乱。我一般把采样周期设在5秒以上除非特殊情况才缩短。4.4 安装、卸载和批量管理App产线上经常要给一批设备批量安装同一个版本App。传统做法是拿U盘一个个人肉点费时费力。用LabVIEW加adb做批量安装不过是遍历设备号list然后逐个adb install -r的问题。安装命令adb -s serial install -r C:\package\app_release.apk-r是覆盖安装保留数据和缓存做升级测试非常合适。如果要做干净环境测试则去掉-r先卸载再安装adb -s serial uninstall com.example.myapp adb -s serial install C:\package\app_release.apk批量管理多台设备时adb devices的输出会列出所有已连接设备LabVIEW循环解析出每个序列号再用-s参数指定设备执行命令就实现了并行管理。实测下来一台PC同时管理6-8台设备的adb连接问题不大但连接设备过多后adb server偶尔会假死处理办法后面问题排查部分细说。5. 常见问题与排查技巧实录5.1 adb devices显示unauthorized或者offline这是遇到最多的问题。unauthorized意味着设备端没有信任这台PC需要在设备屏幕上勾选“始终允许使用这台计算机进行调试”并确定。如果是产线大批量部署第一次连接时如果没人点允许程序就卡住了。解决办法是用adb keygen预生成adbkey部署时把公钥烧录到设备的系统镜像里实现首次连接即已授权。offline状态更复杂一点可能是USB接触不良、USB线只用来充电不支持数据传输、驱动没装对。排查顺序换一根短的原装USB线试更新设备驱动重启adb serveradb kill-server adb start-serverLabVIEW程序里我一般会做一个“adb环境自检”按钮运行这个子VI后自动执行adb devices然后根据返回结果提示用户如何处理而不是等到正式用例跑挂了才发现连不上。5.2 System Exec.vi弹出黑窗口闪一下有人接受不了执行命令时窗口一闪而过觉得影响UI体验。解决办法是给System Exec.vi的run minimized接True同时把wait until completion设为True。这样黑窗口会在后台最小化状态跑完几乎看不到闪烁。如果想彻底不弹窗那就要绕道Windows API或者.NET的Process类设置CreateNoWindow True。这一方法的代价是代码复杂度上升除非产品对UI效果有严格洁癖否则我觉得没必要。产线工人本来就要面对各种窗口一个一闪而过的cmd窗口不会造成什么困扰。5.3 中文乱码和数据解析错误前面提过UTF-8和ANSI编码冲突的问题。在代码里做一层万能的编码处理流程是最好的所有adb标准输出先转成字节数组再按UTF-8解码。对于纯ASCII内容按UTF-8解码也不会出错。解析数据时还要警惕ANSI转义字符。LabVIEW的字符串显示控件默认会解释某些字符比如\r\n显示成两个特殊符号。建议所有解析用的字符串都先经过“搜索替换字符串”把\r\n统一成\n避免前后台不一致导致匹配失败。5.4 adb server端口冲突和假死电脑上如果装了多个安卓工具比如刷机工具、手机助手它们可能自带adb或者占用adb的5037端口导致LabVIEW里的adb命令时好时坏。排查方法netstat -ano | findstr 5037看到端口被其他PID占用时要么关掉那个进程要么进入自己的platform-tools目录重新指定端口启动服务。在LabVIEW里动态指定端口的操作比较繁琐我没实际用过提一句供参考。adb server假死的典型场景是长时间跑脚本连续执行几千条命令后某条命令会卡住不返回。处理策略是在LabVIEW里给System Exec.vi加超时控制超时后先尝试adb kill-server再重启。这个看门狗逻辑最好独立成一个并行线程运行由主界面控制它的启停。5.5 执行多条命令时的同步策略LabVIEW的System Exec.vi是同步阻塞执行一条命令没返回后面代码不会继续。这是好事因为逻辑天然是串行的。但如果你需要并行操作多台设备而每一台设备又有好几条命令要执行就得设计成生产者-消费者模式用队列把每台设备的命令串分发到不同的执行循环里去。我踩过的坑是一开始图省事把所有设备的命令全部放到一个循环里串行执行结果一台设备卡住所有设备跟着卡。后来改成按设备号创建独立的执行任务每个任务维护一个队列互不干扰整体效率提升了不止一倍。5.6 设备重启后adb重连技巧设备在执行adb reboot之后会短暂断开连接再重新以device状态出现。LabVIEW里的等待逻辑不要用固定延时最好循环执行adb get-stateping到device状态再继续后续步骤。写得健壮一点要区分三种状态空字符串是设备完全消失offline是设备还在但没准备好device是可用状态。只有第三种才允许往下走。每次轮询间隔1秒钟最多等待180秒超时就报异常。6. 代码组织与封装建议做LabVIEW项目时间长了你就会发现程序框图上直接堆一堆adb字符串和执行节点一大小心就变成蜘蛛网。我建议从最开始就把adb操作封装成子VI每个子VI做一种基础操作对外暴露参数即可。我在自己项目里整理了一组基础子VI核心几个是ADB_执行命令.vi通用入口输入命令字符串输出标准输出、错误输出、退出码。ADB_获取设备列表.vi内部执行adb devices解析出在线设备序列号数组。ADB_获取设备属性.vi传入属性名返回属性值内部自动处理getprop和字符串清理。ADB_安装App.vi传入APK路径自动处理安装结果判断。ADB_抓取日志.vi传入输出文件路径自动执行logcat并保存。这些子VI封装好以后主程序里只需要关心业务逻辑比如“是用例1还是用例2操作的设备是哪一台”不会深陷在命令拼接的泥潭里。属性节点和这个封装结合有个小技巧把ADB_执行命令.vi的输入输出做成strict类型的自定义控件命令名称下拉选择避免靠手敲字符串出错。这一点在程序交接给其他同事时挺重要交互一下你就明白复用性到底差别在哪里。7. 两个实际项目里的运行效果参考某款安卓智能终端的产线测试程序LabVIEW做上位机通过adb完成SN读取、Firmware版本校验、App预装检查、模拟点击完成引导设置。整条线体8个工位每台设备从插上USB到测试完成约5分钟。之前人工操作要10分钟而且经常出现漏点、误点的场面。用LabVIEW接管adb之后过程数据自动存入SQL Server一键生成测试报告产线组长终于不用每天手抄报表了。另外一个是车载中控屏的老化测试。8台设备放在架子上主机通过USB HUB连接LabVIEW每5分钟采集一次CPU、内存、帧率同时检查后台App进程是否还在。连续跑了72小时数据画成趋势图哪台设备开始出现内存泄漏一目了然。这活儿要是靠人半夜起来记录没人撑得住。从这些实际效果就能看出LabVIEW和adb shell的结合重点不在于单个命令会不会写而在于怎么把它变成一套稳定、可维护、能处理异常的自动化系统。8. 最后说几句实操心得我做了这么多年LabVIEW集成最大的体会是工具本身都不难难的是把边界条件都想清楚。adb命令的特点是看起来简单但它在PC、ADB服务、设备daemon三层之间传输每一层都可能出现环境差异和异常程序里必须都照顾到。几个具体建议收个尾第一所有adb相关配置包括adb路径、默认等待时间、设备序列号列表都放进配置文件或者LabVIEW配置VI里读取。换一台电脑部署时不用改程序框图的任何一根线只改配置就能跑起来。第二给adb执行流程加统一的日志记录。谁在什么时间执行了什么命令返回了什么内容全部记录到日志文件里。线上出问题时这份日志是定位问题的利器比靠回忆靠谱得多。第三长期运行的自动化程序里哪怕你觉得“不会出问题”也建议加上看门狗和重试机制。adbd偶尔会没有理由地退出重启一下服务就能恢复但如果没有自动重试逻辑整个测试流程就会卡死在半路上。第四命令执行字符串务必用英文路径工程目录下带中文时System Exec.vi解析路径偶尔会出幺蛾子这是Windows编码老问题绕开比修补划算。如果能把上面这些细节都处理好LabVIEW执行adb shell就不是一个单独的技术点而是一整套靠谱的安卓自动化测试基础设施。这套东西在消费电子、车机、智能家居的产线和实验室里都能直接复用省下来的时间够你多喝好几杯咖啡。