Aosp开发磨刀石之ADB速查

yaml 复制代码
# 系列推荐

[ubuntu编译android12源码](https://mp.weixin.qq.com/s/jR6vpjvk6TSkFmGt3m8cwg)

[使用AndroidStudio阅读源码](https://mp.weixin.qq.com/s/PbzNo64ARHJCv_RxCc20-Q)

[Aosp开发神器Cuttlefish](https://mp.weixin.qq.com/s/94q8ldtVQzxHE30cDUr_5g)

[Aosp源码学习之目录介绍](https://mp.weixin.qq.com/s/kg9Tq5hPdVbyiCdxl4TlHA)

[Aosp之mk文件简介](https://mp.weixin.qq.com/s/cyPFvQ6IeCRXig12vllipQ)

[AOSP实战之bp文件介绍](https://mp.weixin.qq.com/s/rggXZIGccv1UuzRmObSDgQ)

[Aosp15之添加自己的产品Product](https://mp.weixin.qq.com/s/A8p5CBjErcMKS7Cts636wQ)

[Aosp之编译命令介绍](https://mp.weixin.qq.com/s/JTEQgp9PJD_8ieX5GGBRZQ)

[Aosp之添加C++可执行程序](https://mp.weixin.qq.com/s/lahaVLAMLjGiHhw8S-t0Lw)

[Aosp之添加C++动态库](https://mp.weixin.qq.com/s/ZlThBG4W7Y_tNhBxjYMB5Q)

[SEAndroid理论基础](https://mp.weixin.qq.com/s/inY7KfYXnctsaEW61bkyHA)

[Aosp实战之SEAndroid实战](https://mp.weixin.qq.com/s/RcUBB3msDbv6oyUe5VGlNw)

今天我们来回忆一下Aosp开发常用的ADB命令。。。

## 一、设备连接与管理

### 1.1 基本连接

```bash
adb devices              # 查看已连接设备
adb devices -l           # 带详情(型号、序列号、usb 口)
```

正常输出:

```
List of devices attached
emu32a08        device product:aosp_x86_64 model:Android_SDK_built_for_x86_64
```

**状态含义**:

| 状态             | 含义              | 怎么办                                        |
| :------------- | :-------------- | :----------------------------------------- |
| `device`       | 正常可用            | 直接用                                        |
| `offline`      | 连上了但没就绪         | 拔插 USB;`adb kill-server && adb devices` 重来 |
| `unauthorized` | 手机上弹了授权框没点      | 看手机屏幕,点"允许 USB 调试"                         |
| `no devices`   | 没检测到            | 检查开发者选项里 USB 调试开了没;换线换口                    |
| `recovery`     | 设备在 recovery 模式 | 只能用部分命令(logcat 可用)                         |
| `bootloader`   | 设备在刷机模式         | adb 不可用,要用 fastboot                        |

### 1.2 多台设备同时插着

```bash
adb devices -l                          # 先看序列号
adb -s R58M123ABC shell                 # 用 -s 指定设备
adb -s R58M123ABC install app.apk
```

### 1.3 无线连接(手机不插线)

**传统方式(需要先用一次 USB)**:

```bash
adb tcpip 5555                          # 让 adbd 监听网络端口
adb connect 192.168.1.100:5555          # 连手机 IP(手机设置里看)
adb devices                             # 确认出现 ip:5555 device
# 用完切回 USB 模式
adb usb
```

**Android 11+ 无线配对(完全不用线)**:

```bash
# 手机:设置 → 开发者选项 → 无线调试 → 使用配对码配对设备
adb pair 192.168.1.100:配对端口           # 输入手机上显示的 6 位配对码
adb connect 192.168.1.100:连接端口        # 连接端口和配对端口不一样!
```

### 1.4 等设备就绪(刷机/重启后必备)

```bash
adb wait-for-device                     # 阻塞等设备出现
adb wait-for-device shell getprop sys.boot_completed   # 等 1 才算开机完成
```

刷完机别急着 `adb shell`------adbd 起来了不代表系统开机完成,用上面第二条判断。

### 1.5 重启全家桶

```bash
adb reboot                              # 重启
adb reboot recovery                     # 进 recovery(卡死救砖用)
adb reboot bootloader                   # 进 fastboot(刷机用)
adb reboot edl                          # 进 9008 深刷模式(救砖终极手段,高危)
```

---

## 二、安装卸载 App

### 2.1 安装

```bash
adb install app.apk                     # 基本安装
adb install -r app.apk                  # 覆盖安装(保留数据)
adb install -r -d app.apk               # 允许降级安装(新版本装回旧版本)
adb install -t app.apk                  # 允许安装测试包(testOnly 的 apk 必须加)
adb install -g app.apk                  # 安装时直接授予所有权限
adb install --bypass-low-target-sdk-block app.apk   # 安装 targetSdk 过低的包(Android 14+ 默认拦截)
```

**安装失败先看报错尾巴**,常见 `INSTALL_FAILED_*` 

### 2.2 卸载

```bash
adb uninstall com.example.app           # 普通卸载
adb uninstall -k com.example.app        # 卸载但保留数据和缓存(-k)
adb shell pm uninstall --user 0 com.example.app   # 给当前用户卸载(可卸系统内置 App,不删文件)
adb shell pm uninstall --user 0 com.miui.player   # 例:卸掉厂商预装音乐(慎用)
```

> `pm uninstall --user 0` 是"软卸载":对当前用户隐藏,恢复出厂能回来,比 root 删文件安全得多。删系统 App 前先 `adb shell pm list packages -s` 确认包名。

### 2.3 查 App 信息

```bash
adb shell pm list packages              # 所有包名
adb shell pm list packages -3           # 只看第三方 App
adb shell pm list packages -s           # 只看系统 App
adb shell pm list packages | grep video # 过滤
adb shell pm path com.example.app       # 查 apk 安装在哪个路径
adb shell dumpsys package com.example.app | grep -E "versionName|versionCode|firstInstallTime"   # 详见第七章
```

**提取已安装的 apk**(逆向/备份常备):

```bash
adb shell pm path com.example.app
# 输出: package:/data/app/~~xxxx==/com.example.app-yyyy==/base.apk
adb pull /data/app/~~xxxx==/com.example.app-yyyy==/base.apk ./app.apk
```

---

## 三、操控 App

### 3.1 启动 / 停止

```bash
adb shell am start -n com.example.app/.MainActivity          # 按 包名/Activity 启动
adb shell monkey -p com.example.app -c android.intent.category.LAUNCHER 1   # 不知道 Activity 名?用 monkey 模拟点击桌面图标
adb shell am force-stop com.example.app                     # 彻底杀掉进程
adb shell am kill com.example.app                           # 温和杀(等价于系统回收,会被重启)
```

启动用 URL/deep link:

```bash
adb shell am start -a android.intent.action.VIEW -d "https://example.com"
adb shell am start -a android.intent.action.VIEW -d "myapp://page/detail?id=123"   # 测试 deep link
```

### 3.2 清数据("重置"一个 App)

```bash
adb shell pm clear com.example.app      # 清全部数据+权限,等同设置里"清除存储"
```

调试 App 的祖传操作:"它坏了" → `pm clear` → 重新试 → 还坏 → 抓日志。

### 3.3 权限管理

```bash
adb shell pm list permissions -d -g     # 看危险权限分组
adb shell pm grant com.example.app android.permission.CAMERA     # 手动授权
adb shell pm revoke com.example.app android.permission.CAMERA    # 收回权限
adb shell dumpsys package com.example.app | grep -A 20 "runtime permissions"   # 查当前权限状态(详见第七章)
```

测试"拒绝权限后的降级表现",不用在设置里点来点去,`revoke` 一步到位。

### 3.4 广播与服务

```bash
adb shell am broadcast -a android.intent.action.TIME_SET           # 发广播
adb shell am startservice -n com.example.app/.MyService            # 启动服务(targetSdk 26+ 对后台服务有限制,可能失败)
adb shell dumpsys activity services com.example.app                # 查 App 的服务运行状态(详见第七章)
adb shell dumpsys activity receivers com.example.app               # 查注册的广播接收器(详见第七章)
```

---

## 四、文件传输

### 4.1 基本操作

```bash
adb push local.png /sdcard/Pictures/    # 电脑 → 手机
adb pull /sdcard/DCIM/Camera ./camera   # 手机 → 电脑(整个目录也行)
adb pull /sdcard/DCIM/Camera/img.jpg    # 单个文件
```

### 4.2 权限规则(少踩坑)

| 目标路径                             | shell 用户能直接写吗 | 说明                |
| :------------------------------- | :------------ | :---------------- |
| `/sdcard/`                       | ✅             | 随便读写              |
| `/data/local/tmp/`               | ✅             | shell 的自留地,临时文件放这 |
| `/data/anr/`、`/data/tombstones/` | ⚠️ root 才行    | 崩溃/ANR 记录在这       |
| `/system/`、`/vendor/`            | ❌ 只读          | 需要 root + remount |

root 机(userdebug 版)改系统文件:

```bash
adb root && adb remount
adb push framework.jar /system/framework/
adb reboot
```

### 4.3 传输二进制一定要用 exec-out

```bash
adb exec-out screencap -p > screen.png        # ✅ 正确
adb shell screencap -p > screen.png           # ❌ 可能坏(换行符被转义,图片打不开)
adb exec-out cat /proc/kmsg > kernel.log      # 拉内核日志同理
```

---

## 五、日志 logcat

这是定位问题**第一现场**,值得花最多篇幅。

### 5.1 基本过滤(按优先级/标签)

```bash
adb logcat                              # 全部日志(信息量巨大)
adb logcat *:E                          # 只看 Error 及以上(W/E/F)
adb logcat -s MyAppTag                  # 只看某个 tag(-s 会屏蔽其他所有)
adb logcat -s MyAppTag:E ActivityTaskManager:I   # 组合:我的 tag 报错级 + 系统调度信息级
adb logcat AndroidRuntime:E *:S         # 经典组合:只看 Java 崩溃(AndroidRuntime + *:S 屏蔽其余)
```

优先级从低到高:`V` < `D` < `I` < `W` < `E` < `F`(Fatal)。日志行格式:

```
10-25 16:20:01.123  1234  5678 E MyAppTag: something failed
                                │      │     └─ 写日志的线程 id
                                │      └─ 进程 pid
                                └─ 时间
```

### 5.2 按进程过滤(只看你的 App)

```bash
adb shell pidof com.example.app         # 先拿 pid,比如 12345
adb logcat --pid=12345                  # 只看这个进程的日志
# 或一条组合(macOS/Linux):
adb logcat --pid=$(adb shell pidof com.example.app)
```

### 5.3 缓冲区:崩溃了先去 crash 缓冲区

日志存在 4 个独立缓冲区里,**进程死了日志还在**:

```bash
adb logcat -b crash                     # ⭐ 只看崩溃记录,闪退排查第一步
adb logcat -b main                      # 主缓冲(App 的 System.out.println、Log.x 都在这)
adb logcat -b system                    # 系统缓冲(AMS/WMS 等系统服务日志)
adb logcat -b events                    # 事件流水(am_proc_start、am_anr 等结构化事件,查 ANR 必看)
adb logcat -b all                       # 全部缓冲区
adb logcat -c                           # 清空(复现问题前先清,日志更干净)
```

### 5.4 格式与导出

```bash
adb logcat -v time                      # 带日期时间
adb logcat -v threadtime                # 时间+pid+tid(推荐,默认就是它)
adb logcat -v color                     # 彩色(按级别着色)
adb logcat > crash_log.txt              # 边看边存文件
adb logcat -d > crash_log.txt           # -d = dump 当前已有日志后退出(不持续刷)
adb logcat -d -b crash                  # dump 崩溃缓冲区,复制给别人的标准姿势
```

**给别人报 bug 时**:`adb logcat -d -v threadtime -b crash -b main -b system > log.txt`,一条命令拿全证据。

### 5.5 实用组合拳

```bash
adb logcat | grep -i "exception|error|fatal"     # 抓关键词(macOS/Linux)
adb logcat | grep -E "ANR|FATAL|tombstone"          # 抓致命问题
adb logcat -s WifiHAL:V chatty:I                    # 关掉 chatty 抑制提示,看清真实日志
```

Windows 下没有 grep,用 `findstr`:`adb logcat | findstr /i "exception"`。

---

## 六、getprop:系统属性速查

系统把几百项配置以"属性"形式暴露出来,getprop 是读它们的标准工具:

```bash
adb shell getprop                       # 全部属性(几百条)
adb shell getprop ro.build.version.release      # Android 版本,如 14
adb shell getprop ro.build.version.sdk          # API 级别,如 34
adb shell getprop ro.build.fingerprint          # 构建指纹(报 bug 必带)
adb shell getprop ro.product.model              # 机型
adb shell getprop ro.product.cpu.abilist        # 支持的 CPU 架构(arm64-v8a 等)
adb shell getprop ro.build.type                 # 编译变体:user / userdebug / eng
adb shell getprop ro.debuggable                 # 1 = adb root 可用
adb shell getprop sys.boot_completed            # 1 = 开机完成

adb shell setprop debug.foo 1                   # 设置属性(调试开关常用,重启失效)
adb shell setprop persist.log.tag V             # persist. 开头的属性重启后仍保留
```

getprop是查询系统属性,而setprop是设置系统属性。

---

## 七、dumpsys 全解:所有系统状态查询汇总

dumpsys命令可以说是ADB中的重中之重了,可以说你的调试能力如何完全取决于你的dumpsys命令用得怎么样。。。

`dumpsys` 让系统里的每一个服务(AMS、WMS、电池、网络......)"交出体检报告"。

本章按用途分类:查界面(7.2)、查内存(7.3)、查 CPU/渲染(7.4)、查电量与后台(7.5)、查网络(7.6)、其余服务一张表(7.7)。

### 7.1 基本玩法:先学会"探索"

以activity为例,我们先来看看常用的玩法

```bash
adb shell dumpsys -l                    # ⭐ 列出设备上所有可查的服务名(几百个)
adb shell dumpsys activity              # 查某个服务的完整报告(输出可能几千行)
adb shell dumpsys activity -h           # 部分服务支持 -h 查看子命令帮助
adb shell dumpsys activity > ams.txt    # 输出太大?先存文件再慢慢看
adb shell dumpsys activity | head -50   # 只看前 50 行(Overview 摘要通常就在开头)
adb shell dumpsys activity | grep -A 10 -B 2 "com.example.app"   # 只关心自己的 App:grep 加上下文
```

三个探索技巧:

1. **报告开头都有 Overview/摘要段**,信息密度最高,先看开头再看细节;
2. **grep 必带上下文**(`-A 5` 看后 5 行、`-B 2` 看前 2 行),单行 grep 在 dumpsys 里等于白看;
3. 输出量太大时,存成文件用编辑器打开,比在终端里翻快 10 倍。

### 7.2 查界面与进程:activity / window


"App 白屏了","当前页面是谁"?"进程还在不在"?------都在这两个服务里。

```bash
# ---- activity:Activity 管理服务 ----
adb shell dumpsys activity top                    # ⭐ 当前栈顶 Activity 完整信息(含 View 层级、Fragment)
adb shell dumpsys activity activities             # 所有任务栈、回退栈、每个 Activity 的状态
adb shell dumpsys activity services               # 所有运行中的 Service
adb shell dumpsys activity services com.example.app   # 只看某 App 的 Service
adb shell dumpsys activity broadcasts             # 所有广播接收器 + 历史广播派发记录
adb shell dumpsys activity broadcasts | grep -A 3 com.example.app   # 查谁收不到广播
adb shell dumpsys activity processes              # 所有进程 + oom_adj 优先级(谁先被杀)
adb shell dumpsys activity providers              # 所有 ContentProvider
adb shell dumpsys activity recents                # 最近任务列表

# ---- window:窗口与显示 ----
adb shell dumpsys window | grep -E "mCurrentFocus|mFocusedApp"   # ⭐ 焦点在哪个窗口
adb shell dumpsys window displays          # 屏幕尺寸、旋转、DPI、显示区域
adb shell dumpsys window windows           # 所有窗口的 Z 序(谁盖着谁)
```

**activity 输出怎么读**(`dumpsys activity activities`,重点两段):

```
Display #0 (activities from top to bottom):
  Task id #123
    mResumedActivity: ActivityRecord{... u0 com.example.app/.DetailActivity t123}
    ↑ 当前"活着的"(onResume 的)Activity,白屏问题先看这行
    * ActivityRecord{... com.example.app/.MainActivity t123}
      mState=STOPPED       ↑ 每个 Activity 的生命周期状态:
                              RESUMED / PAUSED / STOPPED / DESTROYED
                              (卡在 PAUSED/STOPPED 不动 = 生命周期流程出了问题)
```

**判断 App 是否被杀/是否真的在前台**:

```bash
adb shell dumpsys activity processes | grep -B 1 -A 8 com.example.app
# 看 oom_adj 值:0 = 前台,几百 = 后台缓存进程(随时可被杀)
# 进程不在列表里 = 已被系统杀掉
```

**window 实战场景**:App 点了按钮没反应?第一嫌疑是"有个透明窗口/对话框抢了焦点"------`mCurrentFocus` 显示的不是你的 Activity 就是它。

这里可以列举附上排查手段:

```
# 第 1 步:看焦点现在在谁手上
adb shell dumpsys window | grep mCurrentFocus
# 正常输出应类似:mCurrentFocus=Window{abc1234 u0 com.example.app/com.example.app.MainActivity}
# 如果显示的是 Dialog、PopupWindow、Toast,或者根本是别的 App 的包名 → 就是它抢了焦点

# 第 2 步:焦点是弹窗?查它是谁弹的(按 uid 反查包名)
adb shell dumpsys window windows | grep -B 2 -A 5 "Window #"
# 在输出里找到焦点窗口的 u0=uid(如 u0a123 表示 uid 10123)
adb shell cmd package list packages --uid 10123
# 输出: package:com.suspect.app uid:10123   ← 找到真凶

# 第 3 步:验证猜想------按返回键关掉弹窗,再确认焦点回来了
adb shell input keyevent 4                          # 返回键关弹窗
adb shell dumpsys window | grep mCurrentFocus       # 焦点应回到你的 Activity
# 此时再点按钮,如果恢复了 → 实锤"弹窗抢焦点"

# 补充:点没反应也可能是"点击没生效"而不是"焦点被抢",用第 1 步确认后
# 若焦点正常,改查触摸事件是否到达:打开开发者选项 → 指针位置(显示触摸点),
# 或用 input tap 模拟点击对比手动点击的差异,排除触摸屏硬件/坐标偏移问题
```

### 7.3 查内存:meminfo

```bash
adb shell dumpsys meminfo com.example.app          # 按 App 查
adb shell dumpsys meminfo 12345                    # 按 pid 查(多进程 App 用这个)
adb shell dumpsys meminfo                          # 全系统所有进程内存排行
adb shell dumpsys meminfo --checkin com.example.app   # CSV 格式输出(适合写脚本采集)
```

详细输出怎么读(判断泄漏/内存优化的核心依据):

```
                 Pss(KB)   Private Dirty   Heap Size   Heap Alloc
  Java Heap:      45123          44800       61440       43210    ← Java 对象堆
  Native Heap:    60234          59800      102400       88700    ← C/C++ 内存、图片解码
  Graphics:       20000          19800                                ← GPU 纹理/缓冲
  ...
  TOTAL PSS:     145678                                               ← 总占用(持续涨 = 泄漏)

  Objects(对象统计):
    Views:      1234        View 数量异常大 = 布局泄漏/重复添加
    Activities: 8           ⭐ 理论上应 ≤ 当前存活的 Activity 数,
                            一直涨不降 = Activity 泄漏(经典 bug)
    AppContexts: 9          Context 泄漏同理

  SQL(数据库):
    MEMORY_USED: 2048       数据库内存;heap 一直涨 = Cursor 没 close
```

**泄漏判定黄金法则**:反复进出同一页面 10 次,每次执行 `dumpsys meminfo`,盯 `Activities` 和 `TOTAL PSS` 两行------只涨不降就是泄漏,有实锤再上 Memory Profiler 深挖。

### 7.4 查 CPU 与渲染:cpuinfo / gfxinfo

```bash
# CPU
adb shell dumpsys cpuinfo                    # 全系统 CPU 占用报表(用户态/内核态占比)
adb shell dumpsys cpuinfo | grep -A 3 com.example.app
adb shell top -m 10 -s 9                     # 非 dumpsys 但常用:按 CPU 排序的前 10 进程

# 渲染帧统计(查卡顿)
adb shell dumpsys gfxinfo com.example.app             # 渲染统计
adb shell dumpsys gfxinfo com.example.app reset       # ⭐ 重置统计后再复现,数据才准
adb shell dumpsys gfxinfo com.example.app framestats  # 最近 120 帧逐帧耗时(ns)
```

**gfxinfo 输出怎么读**:

```
Total frames rendered: 320
Janky frames: 45 (14.06%)          ← 超过 16.67ms 渲染的帧叫 janky,占比 >10% 肉眼可感卡顿
95th percentile: 24ms              ← 95% 的帧能在 24ms 内渲染完
```

`framestats` 的逐帧数据可以自己算出 measure/layout/draw 各阶段耗时,是定位"布局太深还是绘制太重"的依据。

### 7.5 查电量与后台管控:battery / batterystats / deviceidle / alarm / jobscheduler

```bash
# ---- battery:当前电池状态 + 模拟电池(测试神器)----
adb shell dumpsys battery                    # 电量、电压、温度、充电方式
adb shell dumpsys battery set ac 1           # 模拟插上充电器
adb shell dumpsys battery unplug             # 模拟拔电
adb shell dumpsys battery set level 15       # 模拟低电量(测省电模式降级逻辑)
adb shell dumpsys battery reset              # ⚠️ 恢复真实状态,改完必做

# ---- batterystats:耗电统计(查"谁在耗电")----
adb shell dumpsys batterystats --reset       # 重置统计
# ...正常使用一段时间或跑自动化...
adb shell dumpsys batterystats --charged > battery.txt   # 导出自上次充满后的耗电统计
# 在 battery.txt 里搜你的包名,看 Wake lock(后台唤醒锁持有时间)和 Network(后台流量)

# ---- deviceidle:Doze 省电模式 ----
adb shell dumpsys deviceidle                 # 当前 Doze 状态
adb shell dumpsys deviceidle force-idle      # ⭐ 强制进入 Doze(测后台被限流的表现)
adb shell dumpsys deviceidle step            # 手动推进 Doze 深睡流程
adb shell dumpsys deviceidle unforce         # 退出 Doze
adb shell dumpsys deviceidle whitelist       # Doze 白名单(谁不受限)

# ---- alarm / jobscheduler:定时任务 ----
adb shell dumpsys alarm | grep -A 5 com.example.app    # App 注册了哪些闹钟、下次触发时间
adb shell dumpsys jobscheduler | grep -B 2 -A 10 com.example.app   # JobScheduler 任务

# ---- power:电源状态 ----
adb shell dumpsys power | grep -iE "wakefulness|wake_lock"   # 亮灭屏、唤醒锁统计
```

**实战场景**:后台推送收不到、定时任务不跑?先 `dumpsys battery unplug && dumpsys deviceidle force-idle` 把设备推进 Doze 再观察------90% 的"后台收不到推送"是 Doze 限制,不是 bug。

### 7.6 查网络:connectivity / netstats / netpolicy

```bash
adb shell dumpsys connectivity          # 网络连接状态(默认网络是谁、验证状态)
adb shell dumpsys netstats detail       # 流量统计(查流量异常)
adb shell dumpsys netpolicy             # 后台网络限制状态(流量省电策略)
```

网络连通性测试(ping/ip 等)。

### 7.7 其他高频服务速查表

| 服务 | 命令 | 什么时候用 |
| :--- | :--- | :--- |
| package | `dumpsys package com.example.app` | 查版本、签名、权限、安装来源 |
| notification | `dumpsys notification --noredact` | 通知没显示?看通知队列和拦截状态 |
| dropbox | `dumpsys dropbox --print data_app_crash` | ⭐ 历史崩溃存档(没开 logcat 也能事后翻案) |
| procstats | `dumpsys procstats com.example.app` | 长时段内存/CPU 历史统计(评估后台占用) |
| usagestats | `dumpsys usagestats` | App 使用时长统计 |
| thermalservice | `dumpsys thermalservice` | 温度状态(降频/降亮度排查) |
| diskstats | `dumpsys diskstats` | 磁盘空间 |
| mount | `dumpsys mount` | 分区挂载状态(查 remount 问题) |
| media.session | `dumpsys media_session` | 音视频会话(谁在播、锁屏控件归谁) |
| audio | `dumpsys media.audio_flinger` | 音频焦点("为什么我的 App 没声音") |
| input_method | `dumpsys input_method` | 输入法状态(软键盘弹不出来) |
| vibrator | `dumpsys vibrator_manager` | 震动效果(测试震动反馈) |
| location | `dumpsys location` | 定位状态、有哪些 App 在请求定位 |
| account | `dumpsys account` | 系统账户 |
| backup | `dumpsys backup` | 备份服务状态 |

其中 **`dumpsys dropbox`** 最容易被忽略:系统把每次 App 崩溃都存档了,哪怕你没开着 logcat 也能事后翻案:

```bash
adb shell dumpsys dropbox --print data_app_crash | head -100   # 最近一次 Java 崩溃的完整堆栈
adb shell dumpsys dropbox --print data_app_anr | head -100     # 历史 ANR 记录
```

### 7.8 dumpsys 实战心法

1. **不知道查哪个服务?** `dumpsys -l` 找名字,服务名基本见名知义;
2. **查 App 相关问题,命令后面直接跟包名**(activity/services/alarm/jobscheduler/package/meminfo/procstats 都支持),避免在几千行里大海捞针;
3. **复现类测量先 reset**:`gfxinfo ... reset`、`batterystats --reset`,让统计数据从零开始;
4. **改完 battery / deviceidle 的模拟状态,记得 reset/unforce 恢复**,否则设备一直处于假状态;
5. **配合 logcat 交叉验证**:dumpsys 告诉你"现在是什么状态",logcat 告诉你"状态怎么变成这样的",两者对时间轴就能还原整个事件链。

### 7.9 配套的通用 Linux 信息命令

查硬件/内核这类"非服务"信息,用 cat /proc 即可:

```bash
adb shell cat /proc/cpuinfo             # CPU
adb shell cat /proc/meminfo             # 总内存
adb shell cat /proc/version             # 内核版本
adb shell df -h                         # 磁盘空间
adb shell free -m                       # 内存概况
adb shell uptime                        # 开机时长、负载
```

---

## 八、模拟操作

### 8.1 触摸与按键

```bash
adb shell input tap 500 800                          # 点击坐标 (x,y)
adb shell input swipe 300 1000 300 300               # 滑动(快速)
adb shell input swipe 300 1000 300 300 500           # 滑动,持续 500ms
adb shell input swipe 300 800 300 800 2000           # 长按(同点按住 2 秒)
adb shell input keyevent 4                           # 返回键
adb shell input keyevent 3                           # Home 键
adb shell input keyevent 26                          # 电源键
adb shell input text "hello"                         # 输入文字(焦点在输入框时)
adb shell input text "hello%sworld"                  # 空格用 %s 代替
```

常用 keyevent 码速查:`3` Home、`4` 返回、`5` 拨号、`6` 挂断、`24` 音量+、`25` 音量-、`26` 电源、`82` 菜单、`127` 暂停媒体、`164` 静音。

**怎么知道该点哪个坐标?** 开发者选项 → 指针位置(打开后屏幕显示坐标),或者:

```bash
adb shell uiautomator dump /sdcard/ui.xml    # 导出当前界面控件树
adb pull /sdcard/ui.xml && open ui.xml       # 找到目标控件的 bounds="[x1,y1][x2,y2]"
```

### 8.2 截屏 / 录屏

```bash
# 截屏
adb exec-out screencap -p > screen.png
# 或两步走:
adb shell screencap /sdcard/s.png && adb pull /sdcard/s.png

# 录屏(默认 3 分钟上限,Ctrl+C 停止)
adb shell screenrecord /sdcard/demo.mp4
adb shell screenrecord --time-limit 30 --bit-rate 8000000 /sdcard/demo.mp4   # 30 秒、高码率
adb pull /sdcard/demo.mp4
```

录屏报 bug 复现视频 + logcat 文本,是给同事/社区提 issue 的黄金组合。

### 8.3 模拟系统状态

```bash
# 电池模拟走 dumpsys(详见 7.5):
adb shell dumpsys battery set level 15 && adb shell dumpsys battery unplug

# 修改 DPI / 分辨率(适配测试神器!)
adb shell wm size 1080x1920                     # 改分辨率
adb shell wm density 320                        # 改 DPI
adb shell wm size reset && adb shell wm density reset    # 恢复
```

**`wm size/density` 是做屏幕适配测试的利器**:不用真机矩阵,一条命令把旗舰机变成小屏机。

---

## 九、性能定位 SOP

本章只讲**排查流程**(先做什么后做什么),命令细节和输出解读都可以参考上面的细节。

### 9.1 卡顿 / 掉帧

```bash
adb shell dumpsys gfxinfo com.example.app reset    # 1. 重置统计(输出解读见 7.4)
# 2. 手机上操作,复现卡顿
adb shell dumpsys gfxinfo com.example.app          # 3. 看 Janky frames 占比与 95th percentile
adb shell dumpsys gfxinfo com.example.app framestats  # 4. 逐帧数据定位慢在哪一阶段
```

进阶:抓完整渲染 trace(用 ui.perfetto.dev 打开):

```bash
adb shell perfetto -o /data/misc/perfetto-traces/trace.pftrace -t 15s sched freq gfx view am wm
adb pull /data/misc/perfetto-traces/trace.pftrace
```

### 9.2 内存泄漏嫌疑

```bash
adb shell dumpsys meminfo com.example.app | grep TOTAL    # 1. 记录基线(输出解读见 7.3)
# 2. 反复进出同一页面 10 次,每轮执行上面命令
# 3. TOTAL PSS / Activities 只涨不降 → 泄漏,转 Memory Profiler 或 LeakCanary 深挖
adb shell ps -eo PID,RSS,NAME --sort=-rss | head -20      # 顺带:全机内存排行
```

### 9.3 CPU 占用过高

```bash
adb shell top -m 10 -s 9                 # 1. 找出最耗 CPU 的进程(确认是不是你的)
adb shell dumpsys cpuinfo | grep -A 3 com.example.app   # 2. 看你的 App 用户态/内核态占比(见 7.4)
adb shell pidof com.example.app          # 3. 拿到 pid 后可抓 perfetto/simpleperf 深挖热点函数
```

### 9.4 启动时间

```bash
adb shell am force-stop com.example.app            # 1. 杀掉保证冷启动
adb shell am start -W -n com.example.app/.MainActivity
```

输出:

```
Status: ok
TotalTime: 456          ← 从启动到第一帧的总耗时(ms)
WaitTime: 512           ← 包括 AMS 等待的时间
```


跑 5 次取平均才是可信数据。

### 9.5 耗电

```bash
adb shell dumpsys batterystats --reset   # 1. 重置统计(见 7.5)
# 2. 正常使用一段时间或跑自动化
adb shell dumpsys batterystats --charged > battery.txt    # 3. 导出,搜包名看 Wake lock 和 Network
```

后台耗电大户基本就是唤醒锁(Wake lock)和后台流量(Network)两项。

---

## 十、网络调试

### 10.1 连通性与状态

```bash
adb shell ping -c 4 baidu.com           # 手机上 ping
adb shell ifconfig wlan0                # Wi-Fi IP 地址
adb shell ip route                      # 路由表
adb shell netstat -tlnp                 # 监听端口(部分版本需 root)
adb shell dumpsys connectivity          # 连接状态详情(见 7.6)
adb shell svc wifi enable / disable     # 开关 Wi-Fi
adb shell svc data enable / disable     # 开关移动数据
```

### 10.2 端口转发:电脑和手机互访

```bash
# 电脑访问手机上的服务(如手机上跑了个调试服务器在 8080)
adb forward tcp:8080 tcp:8080
# 然后浏览器打开 http://localhost:8080 就是手机的 8080

# 手机访问电脑上的服务(手机连不上你电脑的 mock 服务器?用它!)
adb reverse tcp:3000 tcp:3000
# 手机 App 里访问 http://localhost:3000,实际打到电脑的 3000

# 转发到手机内部的 Unix socket(调 Chrome 远程调试 WebView)
adb forward tcp:9222 localabstract:chrome_devtools_remote
# 电脑 Chrome 打开 chrome://inspect 即可调试手机 WebView
```

`adb reverse` 是真机调试的保命符------手机没公网 IP、和电脑不在同一段网,都拦不住它。

---

## 十一、实战剧本:常见问题排查

### 剧本 1:App 闪退(Crash)

```bash
# 1. 清日志,准备复现
adb logcat -c
# 2. (在手机上操作复现闪退)
adb logcat -d -b crash -v threadtime
```

看输出里的 `FATAL EXCEPTION` 段:异常类型(`NullPointerException` 等)+ 发生的类名行号,直接定位代码。如果闪退但 crash 缓冲区没东西,可能是 native 崩溃:

```bash
adb logcat -d | grep -E "SIGSEGV|SIGABRT|tombstone|Fatal signal"
```

**没抓到现场?崩溃记录有存档**(详见 7.7 的 dropbox):

```bash
adb shell dumpsys dropbox --print data_app_crash | head -100   # 系统存档的历史崩溃堆栈
```

### 剧本 2:App 无响应(ANR)

```bash
adb logcat -d | grep -i "ANR in"            # 1. 确认发生了 ANR 及哪个进程
adb logcat -d -b events | grep am_anr       # 2. 事件流里看 ANR 记录
adb shell ls /data/anr/                     # 3. root 机可看完整线程堆栈
adb shell cat /data/anr/anr_* | head -100   #    主线程堆栈第一段就是凶手
```

非 root 机拿不到 `/data/anr/`,用 `adb bugreport anr.zip`,解压后在 `FS/data/anr/` 里有同样的文件;历史 ANR 也可查 `dumpsys dropbox --print data_app_anr`。

### 剧本 3:App 越用越卡(内存泄漏嫌疑)

按 9.2 的 SOP 执行:`dumpsys meminfo` 反复采样 → 盯 TOTAL PSS 和 Activities → 只涨不降即泄漏。

### 剧本 4:页面白屏 / 界面卡住

```bash
adb shell dumpsys activity top | grep ACTIVITY       # 当前 Activity 是谁?(见 7.2)
adb shell dumpsys window | grep mCurrentFocus        # 焦点在哪个窗口?
adb exec-out screencap -p > now.png                  # 截屏留证
adb shell uiautomator dump /sdcard/ui.xml            # 界面树里有没有内容?(白屏还是数据空?)
adb pull /sdcard/ui.xml
```

### 剧本 5:App 装不上

```bash
adb install app.apk
# 看最后的 INSTALL_FAILED_XXX 是什么,对照第十二节速查表
adb shell dumpsys package com.example.app | grep version   # 是不是版本号冲突
```

### 剧本 6:怀疑 App 在后台偷偷活动

```bash
adb shell dumpsys activity processes | grep -A 5 com.example.app   # 进程还活着吗?(见 7.2)
adb shell dumpsys alarm | grep -A 3 com.example.app                # 注册了什么闹钟?(见 7.5)
adb shell dumpsys jobscheduler | grep -B 2 -A 8 com.example.app    # 有没有定时任务?
adb logcat -d -b events | grep "am_wake_lock"                      # 谁在拿唤醒锁?
```

### 剧本 7:系统起不来 / 反复重启

```bash
adb wait-for-device logcat -d -b all > boot.log    # 第一时间抢救日志!
adb logcat -d | grep -iE "fatal|crash|zygote"      # 看 zygote 有没有挂
adb reboot recovery                                # 进 recovery 清数据(会丢用户数据)
adb reboot bootloader                              # 进 fastboot 重刷(最后手段)
```

**血泪经验**:刷机/改系统后 bootloop,第一件事不是重启,而是 `wait-for-device` 抢日志------设备循环重启时 adbd 有一小段存活窗口,抓到日志就抓住了根因。

### 剧本 8:把完整证据包发给别人

```bash
adb exec-out screencap -p > screenshot.png
adb shell screenrecord --time-limit 20 /sdcard/repro.mp4   # 边录边复现
adb bugreport evidence.zip                                  # 全量体检包(所有 dumpsys/anr/日志全在)
adb pull /sdcard/repro.mp4
```

一个 `evidence.zip` + 一段录屏 + 一份 logcat,任何人都够定位 80% 的问题。

---

## 十二、报错速查表

| 报错 | 原因 | 解法 |
| :--- | :--- | :--- |
| `unauthorized` | 手机没点授权弹窗 | 看手机屏幕点允许;不行就撤销授权重连(开发者选项 → 撤销 USB 调试授权) |
| `offline` | 握手未完成 | 换线/换口;`adb kill-server && adb devices` |
| `adb server version doesn't match` | 装了两个版本的 adb | `which -a adb` 找出重复的,删一个 |
| `more than one device` | 多设备 | 加 `-s 序列号` 或设 `ANDROID_SERIAL` |
| `INSTALL_FAILED_ALREADY_EXISTS` | 已装同包名 | 加 `-r` 覆盖装 |
| `INSTALL_FAILED_SIGNATURE_CONFLICT` | 签名不一致 | 先 `adb uninstall` 再装 |
| `INSTALL_FAILED_UPDATE_INCOMPATIBLE` | 系统里有残留/版本冲突 | `adb uninstall` 后重装;还不行 `pm clear` |
| `INSTALL_FAILED_NO_MATCHING_ABIS` | apk 不含设备 CPU 架构 | 换含 arm64-v8a 的包 |
| `INSTALL_PARSE_FAILED_NO_CERTIFICATES` | apk 没签名 | 用 apksigner 签名后再装 |
| `Read-only file system` | push 到了系统分区 | 先 root + remount,或推到 `/data/local/tmp` |
| `device offline` during install | 安装过程中设备掉线 | 换好线,关掉省电 USB 休眠 |
| `adb: no devices/emulators found` | 没设备 | 查 USB 调试开关、驱动、`lsusb` 看设备有没有枚举到 |
| `protocol fault (no status)` | server 与 adbd 通信崩了 | `adb kill-server` 重来;频繁出现换线 |
| `cmd: Failure calling service` | 服务不存在或被裁剪 | `dumpsys -l` 确认服务名;定制 ROM 可能删了该服务 |

---

## 十三、效率技巧

### 13.1 组合命令

```bash
# 一行完成:截屏并拉回电脑
adb exec-out screencap -p > $(date +%H%M%S).png

# 一行完成:杀 App 重启(改代码后的快速验证)
adb shell am force-stop com.example.app && adb shell am start -n com.example.app/.MainActivity

# 一行完成:等设备 + 确认开机 + 提示
adb wait-for-device shell 'while [ "$(getprop sys.boot_completed)" != "1" ]; do sleep 1; done; echo BOOT_OK'
```

### 13.2 常用自带工具箱(adb shell 里的 Linux 命令)

```bash
adb shell ls -l /sdcard/        # 列目录
adb shell cat file.txt          # 看文件
adb shell grep -r "keyword" /data/local/tmp/   # 搜内容
adb shell stat file.txt         # 看文件属性
adb shell toybox                # 查看全部可用工具列表(Android 自带 toybox)
```

adb shell 里可用的是精简版 Linux 工具集(toybox),常用命令基本都有:`ls cp mv rm mkdir ps top netstat ifconfig df du free kill` 等。

后面有了再补充。。。
相关推荐
小此方1 小时前
C++ 工程组件与基础设施(三)详解RPC服务的概念与安装,图片介绍Brpc服务器和客户端的搭建过程
服务器·c++·rpc
qq_406981031 小时前
什么是顶层 const什么是底层const
开发语言·c++
zwc32104320552 小时前
第四周第五天——重构成类
c++·人工智能·opencv·算法·计算机视觉
凉茶钱2 小时前
多态:从虚函数语法到虚表寻址,一次讲透动态绑定
开发语言·c++·多态
01二进制代码漫游日记3 小时前
[C++]之内存管理(一)
jvm·c++·学习
codebolt3 小时前
C++程序crash分析和内存检测
开发语言·c++
ShineWinsu3 小时前
对于Qt:QLabel常见属性的解析
c++·qt·面试·笔试·gui·标签·qlabel
应用市场3 小时前
用本机跑的开源音乐模型,给安卓小游戏做 20 秒无缝循环背景音乐
android·python·游戏开发·soundpool·音频处理
企业数字化笔记3 小时前
表单发布前怎么验收?版本引用、字段兼容和历史数据回归
android·数据挖掘·回归