乐于分享
好东西不私藏

strace安卓linux系统调用跟踪神器相关实战案例

strace安卓linux系统调用跟踪神器相关实战案例

  • 一、什么是strace?
  • 二、strace的工作原理
  • 三、strace的核心作用
  • 四、常用参数与用法
  • 五、典型使用场景与案例
    • 场景一:程序启动失败,排查缺少文件或配置
    • 场景二:定位“Permission denied”的具体原因
    • 场景三:诊断进程卡死(hang)或无响应
    • 场景四:分析程序启动慢的原因
    • 场景五:跟踪多进程/多线程程序
  • 六、进阶技巧
    • 1. 过滤输出
    • 2. 显示系统调用的耗时
    • 3. 输出更完整的字符串
    • 4. 将strace作为调试器使用
  • 七、安卓中strace一些实战案例技巧
  • 八、注意事项

本文将全面介绍 strace 命令的作用、工作原理、常见使用场景以及实战案例,帮助你掌握这一强大的调试工具。

一、什么是strace?

strace 是一个集诊断、调试、分析于一体的Linux系统工具,它可以拦截并记录进程发起的所有系统调用(system call)以及接收到的信号。简单来说,它能让你“看见”一个程序在运行时,向内核发出了什么请求,内核又是如何响应的。

系统调用是用户态程序与内核交互的唯一入口,比如读写文件(openreadwrite)、创建进程(forkclone)、网络通信(socketconnectsend)等。通过观察这些调用,我们可以精准地定位程序在哪个环节出现了问题。

二、strace的工作原理

strace 的背后依赖于Linux内核提供的 ptrace 系统调用。ptrace 允许一个进程(trace)监视和控制另一个进程(tracee)的执行,并可以读取和修改其内存和寄存器。

当一个进程被 strace 附加后,每次该进程执行系统调用时,内核都会暂停该进程,并将控制权转交给 strace 进程。strace 会解析系统调用的编号、参数、返回值,并将其以人类可读的格式输出,然后恢复原进程的执行。这个过程中,原进程的性能会有所下降,但对于诊断问题来说,这种开销通常是可接受的。

三、strace的核心作用

  1. 故障排查:当程序崩溃、无响应、权限错误或找不到文件时,strace 可以快速定位失败的系统调用及其错误码。
  2. 性能分析:通过统计系统调用的耗时和频次,可以找出程序性能瓶颈。例如,过多的 open 或 stat 调用可能意味着频繁的文件访问,导致I/O等待。
  3. 理解程序行为:对于没有源代码或文档的程序,strace 可以揭示其工作流程:读取了哪些配置文件、打开了哪些动态库、监听了哪些端口等。

四、常用参数与用法

参数
说明
-p PID
跟踪指定进程ID
-o file
将输出重定向到文件
-e trace=set
指定要跟踪的系统调用集,如 -e trace=file 只跟踪文件操作
-t

 / -tt / -ttt
显示时间戳,精度逐级提高
-T
显示每个系统调用的耗时
-f
跟踪由当前进程创建的子孙进程
-c
统计每个系统调用的次数、时间、错误数,生成汇总报告
-s size
指定显示字符串的最大长度(默认32字节)

五、典型使用场景与案例

Android与Linux跟踪方式的区别 必须获取root权限。因为strace需要访问内核空间的信息,未root设备不允许此操作。

场景一:程序启动失败,排查缺少文件或配置

假设我们运行一个名为 myapp 的程序,但它启动后立即退出,没有输出任何错误信息。

strace -o strace.log ./myapp

查看 strace.log 文件,通常会看到类似这样的内容:

openat(AT_FDCWD, "/etc/myapp/config.conf", O_RDONLY) = -1 ENOENT (No such file or directory)

这就明确指出了程序因为找不到 /etc/myapp/config.conf 而退出,问题一目了然。

场景二:定位“Permission denied”的具体原因

有时程序报告权限错误,但不知道是哪个文件或目录的权限有问题。

strace -e trace=open,openat -o strace.log ./myapp

通过过滤只跟踪文件打开操作,可以快速找到第一个返回 EACCES 的调用。

场景三:诊断进程卡死(hang)或无响应

当发现一个服务进程没有响应,但进程还在,可能是死锁、等待资源或陷入某个系统调用。可以用 strace 附加到进程看看它在做什么:

strace -p 12345

如果输出反复出现:

futex(0x7f1234567890, FUTEX_WAIT_PRIVATE, 2, NULL) = ?

说明进程正在等待一个互斥锁,可能发生了死锁。如果输出是:

read(3, 

并一直停在那里,说明进程在等待从文件描述符3读取数据,可能是网络或管道输入卡住了。

场景四:分析程序启动慢的原因

一个应用启动时间过长,可以使用 strace 跟踪启动过程,并统计耗时:

strace -c -f ./slow_app

命令执行后,strace 会输出一张汇总表:

% time     seconds  usecs/call     calls    errors syscall------ ----------- ----------- --------- --------- ---------------- 72.34    2.345678       23456       100           read 15.12    0.490000        4900       100           open  8.21    0.266000         266      1000           stat  4.33    0.140000         140      1000           mmap

从表中可以看出,read 调用占据了大部分时间,且平均耗时很高,这提示我们程序可能在大量读取数据,或者读取操作本身存在性能问题。

场景五:跟踪多进程/多线程程序

对于会创建子进程的程序(如web服务器),需要使用 -f 参数来跟踪所有子进程:

strace -f -o strace.log ./nginx

对于多线程程序,使用 -f 同样可以跟踪所有线程的系统调用,因为Linux内核中线程是通过轻量级进程实现的。

六、进阶技巧

1. 过滤输出

当输出信息过多时,可以使用 -e 过滤:

  • -e trace=file:仅跟踪文件操作
  • -e trace=process:仅跟踪进程管理(fork, exec等)
  • -e trace=network:仅跟踪网络操作
  • -e trace=signal:仅跟踪信号处理

也可以使用 -e trace=!xxx 来排除某些调用,如 -e trace=!futex 排除干扰较多的锁操作。

2. 显示系统调用的耗时

使用 -T 参数,每个系统调用后会显示耗时(括号内的数字):

open("/etc/passwd", O_RDONLY) = 3 <0.000015>

3. 输出更完整的字符串

默认情况下,字符串参数只显示前32个字符。使用 -s 1024 可以显示更长的内容,对查看完整的路径名或数据包内容很有帮助。

4. 将strace作为调试器使用

结合 -i 参数,可以显示系统调用发生的指令指针地址,配合 objdump 或 gdb 可以进一步定位到源代码行。

七、安卓中strace一些实战案例技巧

一般debug版本会自带strace,没有的话大家可以自己编译make strace后进行push

追踪apk启动过程

上面介绍是linux和android都通用的命令strace命令,一般都是针对具体的native的bin文件启动,但是在android上面,如果要监测某个apk启动时候会触发哪些系统调用呢?

步骤1:获取zygote进程PID

emulator_car64_x86_64:/ # ps -A | grep zygoteroot           523     1   17187420 174404 do_sys_poll         0 S zygote64webview_zygote 1174  523   33899408 115312 do_sys_poll         0 S webview_zygote

记录zygote的PID为523.

步骤2:启动strace跟踪zygote

# 跟踪zygote及其所有子进程,输出到文件strace -f -tt -T -s 500 -p 523 -o /sdcard/strace_output.txt

参数说明:

-f:跟踪所有子进程(必须!)

-tt:显示微秒级时间戳

-T:显示每个系统调用的耗时

-s 500:显示更多字符串内容(默认32字节)

-p 523:附加到zygote进程

-o:输出到文件

步骤3:启动目标APK 保持terminal中的strace运行抓取中,然后在桌面点击app打开既可以。 步骤4:停止跟踪 应用启动完成后,在strace终端按 Ctrl+C 停止跟踪,然后拉取日志:

adb pull /sdcard/strace_output.txt .

追踪app进程被卡住案例

假设代码中故意加入一个卡顿10s的sleep,看看是否使用strace可以定位出来:查看audiotrackdemo的pid号:

 ps -A|grep track                                                                                                                                                      u10_a211      4563   523   16282832 168612 do_epoll_wait       0 S com.example.audiotrackdemo

使用strace追踪上面的pid对应进程:

strace -tt -T  -p 4563 -o /sdcard/strace.txt 

点击app按钮触发sleep 10s行为,然后等待10s以后中断strace抓取行为,pull出对应文件:

adb pull /sdcard/strace.txt/sdcard/strace.txt: 1 file pulled, 0 skipped. 62.9 MB/s (1025485 bytes in 0.016s)

查看strace.txt文件定位: 确实看到有10s的系统调用

11:19:12.988345 futex(0x7c33ed933b90, FUTEX_WAIT_PRIVATE, 352, {tv_sec=10, tv_nsec=0}) = -1 ETIMEDOUT (Connection timed out) <10.000084>

八、注意事项

  1. 权限:普通用户只能 strace 自己启动的进程,跟踪其他用户的进程需要 root 权限。
  2. 性能开销strace 会显著降低目标进程的执行速度,尤其是在大量系统调用的场景下。生产环境使用时需谨慎,或仅在短期诊断时使用。
  3. 安全风险strace 可以读取进程的内存数据,可能泄露敏感信息(如密码、密钥)。在跟踪涉及敏感数据的进程时,应妥善处理输出文件。

    更多vip免费系统开发经典大厂面试题库获取,课程优惠购买成为vip学员进入vip群,积极讨论各种行业难点痛点疑难问题,答疑服务等。

    请联系马哥:

    目前所有专题课程如下:
    1、经典fw的入门到精通实战八件套专题
    详细课表:
    Android Framework开发rom实战合集课表/车载车机手机高级系统开发工程必会技能