ADB 用法大全
olnx6079
8年前
<h2>基本用法</h2> <h3>命令语法</h3> <p>adb 命令的基本语法如下:</p> <pre> adb [-d|-e|-s <serialNumber>] <command></pre> <p>如果只有一个设备/模拟器连接时,可以省略掉 <code>[-d|-e|-s <serialNumber>]</code> 这一部分,直接使用 <code>adb <command></code>。</p> <h3>为命令指定目标设备</h3> <p>如果有多个设备/模拟器连接,则需要为命令指定目标设备。</p> <table> <thead> <tr> <th>参数</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>-d</td> <td>指定当前唯一通过 USB 连接的 Android 设备为命令目标</td> </tr> <tr> <td>-e</td> <td>指定当前唯一运行的模拟器为命令目标</td> </tr> <tr> <td><code>-s <serialNumber></code></td> <td>指定相应 serialNumber 号的设备/模拟器为命令目标</td> </tr> </tbody> </table> <p>在多个设备/模拟器连接的情况下较常用的是 <code>-s <serialNumber></code> 参数,serialNumber 可以通过 <code>adb devices</code> 命令获取。如:</p> <pre> $ adb devices List of devices attached cf264b8f device emulator-5554 device</pre> <p>输出里的 <code>cf264b8f</code> 和 <code>emulator-5554</code> 即为 serialNumber。比如这时想指定 <code>cf264b8f</code> 这个设备来运行 adb 命令获取屏幕分辨率:</p> <pre> adb -s cf264b8f shell wm size</pre> <p>遇到多设备/模拟器的情况均使用这几个参数为命令指定目标设备,下文中为简化描述,不再重复。</p> <h3>启动/停止</h3> <p>启动 adb server 命令:</p> <pre> adb start-server</pre> <p>(一般无需手动执行此命令,在运行 adb 命令时若发现 adb server 没有启动会自动调起。)</p> <p>停止 adb server 命令:</p> <pre> adb kill-server</pre> <h3>查看 adb 版本</h3> <p>命令:</p> <pre> adb version</pre> <p>示例输出:</p> <pre> Android Debug Bridge version 1.0.32 Revision 09a0d98bebce-android</pre> <h3>以 root 权限运行 adbd</h3> <p>adb 的运行原理是 PC 端的 adb server 与手机端的守护进程 adbd 建立连接,然后 PC 端的 adb client 通过 adb server 转发命令,adbd 接收命令后解析运行。</p> <p>所以如果 adbd 以普通权限执行,有些需要 root 权限才能执行的命令无法直接用 <code>adb xxx</code> 执行。这时可以 <code>adb shell</code> 然后<code>su</code> 后执行命令,也可以让 adbd 以 root 权限执行,这个就能随意执行高权限命令了。</p> <p>命令:</p> <pre> adb root</pre> <p>正常输出:</p> <pre> restarting adbd as root</pre> <p>现在再运行 <code>adb shell</code>,看看命令行提示符是不是变成 <code>#</code> 了?</p> <p>有些手机 root 后也无法通过 <code>adb root</code> 命令让 adbd 以 root 权限执行,比如三星的部分机型,会提示 <code>adbd cannot run as root in production builds</code>,此时可以先安装 adbd Insecure,然后 <code>adb root</code> 试试。</p> <p>相应地,如果要恢复 adbd 为非 root 权限的话,可以使用 <code>adb unroot</code> 命令。</p> <h3>指定 adb server 的网络端口</h3> <p>命令:</p> <pre> adb -P <port> start-server</pre> <p>默认端口为 5037。</p> <h2>设备连接管理</h2> <h3>查询已连接设备/模拟器</h3> <p>命令:</p> <pre> adb devices</pre> <p>输出示例:</p> <pre> List of devices attached cf264b8f device emulator-5554 device</pre> <p>输出格式为 <code>[serialNumber] [state]</code>,serialNumber 即我们常说的 SN,state 有如下几种:</p> <ul> <li> <p><code>offline</code> —— 表示设备未连接成功或无响应。</p> </li> <li> <p><code>device</code> —— 设备已连接。注意这个状态并不能标识 Android 系统已经完全启动和可操作,在设备启动过程中设备实例就可连接到 adb,但启动完毕后系统才处于可操作状态。</p> </li> <li> <p><code>no device</code> —— 没有设备/模拟器连接。</p> </li> </ul> <p>以上输出显示当前已经连接了两台设备/模拟器,<code>cf264b8f</code> 与 <code>emulator-5554</code> 分别是它们的 SN。从 <code>emulator-5554</code> 这个名字可以看出它是一个 Android 模拟器。</p> <p>常见异常输出:</p> <ol> <li> <p>没有设备/模拟器连接成功。</p> <pre> List of devices attached</pre> </li> <li> <p>设备/模拟器未连接到 adb 或无响应。</p> <pre> List of devices attached cf264b8f offline</pre> </li> </ol> <h3>USB 连接</h3> <p>通过 USB 连接来正常使用 adb 需要保证几点:</p> <ol> <li> <p>硬件状态正常。</p> <p>包括 Android 设备处于正常开机状态,USB 连接线和各种接口完好。</p> </li> <li> <p>Android 设备的开发者选项和 USB 调试模式已开启。</p> <p>可以到「设置」-「开发者选项」-「Android 调试」查看。</p> <p>如果在设置里找不到开发者选项,那需要通过一个彩蛋来让它显示出来:在「设置」-「关于手机」连续点击「版本号」7 次。</p> </li> <li> <p>设备驱动状态正常。</p> <p>这一点貌似在 Linux 和 Mac OS X 下不用操心,在 Windows 下有可能遇到需要安装驱动的情况,确认这一点可以右键「计算机」-「属性」,到「设备管理器」里查看相关设备上是否有黄色感叹号或问号,如果没有就说明驱动状态已经好了。否则可以下载一个手机助手类程序来安装驱动先。</p> </li> <li> <p>通过 USB 线连接好电脑和设备后确认状态。</p> <pre> adb devices</pre> <p>如果能看到</p> <pre> xxxxxx device</pre> <p>说明连接成功。</p> </li> </ol> <h3>无线连接</h3> <p>除了可以通过 USB 连接设备与电脑来使用 adb,也可以通过无线连接——虽然连接过程中也有需要使用 USB 的步骤,但是连接成功之后你的设备就可以在一定范围内摆脱 USB 连接线的限制啦!</p> <p>操作步骤:</p> <ol> <li> <p>将 Android 设备与将运行 adb 的电脑连接到同一个局域网,比如连到同一个 WiFi。</p> </li> <li> <p>将设备与电脑通过 USB 线连接。</p> <p>应确保连接成功(可运行 <code>adb devices</code> 看是否能列出该设备)。</p> </li> <li> <p>让设备在 5555 端口监听 TCP/IP 连接:</p> <pre> adb tcpip 5555</pre> </li> <li> <p>断开 USB 连接。</p> </li> <li> <p>找到设备的 IP 地址。</p> <p>一般能在「设置」-「关于手机」-「状态信息」-「IP地址」找到。</p> </li> <li> <p>通过 IP 地址连接设备。</p> <pre> adb connect <device-ip-address></pre> <p>这里的 <code><device-ip-address></code> 就是上一步中找到的设备 IP 地址。</p> </li> <li> <p>确认连接状态。</p> <pre> adb devices</pre> <p>如果能看到</p> <pre> <device-ip-address>:5555 device</pre> <p>说明连接成功。</p> </li> </ol> <p>如果连接不了,请确认 Android 设备与电脑是连接到了同一个 WiFi,然后再次执行 <code>adb connect <device-ip-address></code> 那一步;</p> <p>如果还是不行的话,通过 <code>adb kill-server</code> 重新启动 adb 然后从头再来一次试试。</p> <p><strong>断开无线连接</strong></p> <p>命令:</p> <pre> adb disconnect <device-ip-address></pre> <h2>应用管理</h2> <h3>查看应用列表</h3> <p>查看应用列表的基本命令格式是</p> <pre> adb shell pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]</pre> <p>即在 <code>adb shell pm list packages</code> 的基础上可以加一些参数进行过滤查看不同的列表,支持的过滤参数如下:</p> <table> <thead> <tr> <th>参数</th> <th>显示列表</th> </tr> </thead> <tbody> <tr> <td>无</td> <td>所有应用</td> </tr> <tr> <td>-f</td> <td>显示应用关联的 apk 文件</td> </tr> <tr> <td>-d</td> <td>只显示 disabled 的应用</td> </tr> <tr> <td>-e</td> <td>只显示 enabled 的应用</td> </tr> <tr> <td>-s</td> <td>只显示系统应用</td> </tr> <tr> <td>-3</td> <td>只显示第三方应用</td> </tr> <tr> <td>-i</td> <td>显示应用的 installer</td> </tr> <tr> <td>-u</td> <td>包含已卸载应用</td> </tr> <tr> <td><code><FILTER></code></td> <td>包名包含 <code><FILTER></code> 字符串</td> </tr> </tbody> </table> <p>所有应用</p> <p>命令:</p> <pre> adb shell pm list packages</pre> <p>输出示例:</p> <pre> package:com.android.smoketest package:com.example.android.livecubes package:com.android.providers.telephony package:com.google.android.googlequicksearchbox package:com.android.providers.calendar package:com.android.providers.media package:com.android.protips package:com.android.documentsui package:com.android.gallery package:com.android.externalstorage ... // other packages here ...</pre> <p>系统应用</p> <p>命令:</p> <pre> adb shell pm list packages -s</pre> <p>第三方应用</p> <p>命令:</p> <pre> adb shell pm list packages -3</pre> <p>包名包含某字符串的应用</p> <p>比如要查看包名包含字符串 <code>mazhuang</code> 的应用列表,命令:</p> <pre> adb shell pm list packages mazhuang</pre> <p>当然也可以使用 grep 来过滤:</p> <pre> adb shell pm list packages | grep mazhuang</pre> <h3>安装 APK</h3> <p>命令:</p> <pre> adb install <apk file></pre> <p>参数:</p> <p><code>adb install</code> 后面可以跟一些参数来控制安装 APK 的行为,常用参数及含义如下:</p> <table> <thead> <tr> <th>参数</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>-r</td> <td>允许覆盖安装。</td> </tr> <tr> <td>-s</td> <td>将应用安装到 sdcard。</td> </tr> <tr> <td>-d</td> <td>允许降级覆盖安装。</td> </tr> </tbody> </table> <p>完整参数列表及含义可以直接运行 <code>adb</code> 命令然后查看 <code>adb install [-lrtsdg] <file></code> 一节。</p> <p>如果见到类似如下输出(状态为 <code>Success</code>)代表安装成功:</p> <pre> 12040 KB/s (22205609 bytes in 1.801s) pkg: /data/local/tmp/SogouInput_android_v8.3_sweb.apk Success</pre> <p>而如果状态为 <code>Failure</code> 则表示安装失败。常见安装失败输出代码、含义及可能的解决办法如下:</p> <table> <thead> <tr> <th>输出</th> <th>含义</th> <th>解决办法</th> </tr> </thead> <tbody> <tr> <td>INSTALL_FAILED_ALREADY_EXISTS</td> <td>应用已经存在</td> <td>使用 <code>-r</code> 参数</td> </tr> <tr> <td>INSTALL_FAILED_INVALID_APK</td> <td>无效的 APK 文件</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_INVALID_URI</td> <td>无效的 APK 文件名</td> <td>确保 APK 文件名里无中文</td> </tr> <tr> <td>INSTALL_FAILED_INSUFFICIENT_STORAGE</td> <td>空间不足</td> <td>清理空间</td> </tr> <tr> <td>INSTALL_FAILED_DUPLICATE_PACKAGE</td> <td>已经存在同名程序</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_NO_SHARED_USER</td> <td>请求的共享用户不存在</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_UPDATE_INCOMPATIBLE</td> <td>已经安装过签名不一样的同名应用,且数据没有移除</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_SHARED_USER_INCOMPATIBLE</td> <td>请求的共享用户存在但签名不一致</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_MISSING_SHARED_LIBRARY</td> <td>安装包使用了设备上不可用的共享库</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_REPLACE_COULDNT_DELETE</td> <td>替换时无法删除</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_DEXOPT</td> <td>dex 优化验证失败或空间不足</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_OLDER_SDK</td> <td>设备系统版本低于应用要求</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_CONFLICTING_PROVIDER</td> <td>设备里已经存在与应用里同名的 content provider</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_NEWER_SDK</td> <td>设备系统版本高于应用要求</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_TEST_ONLY</td> <td>应用是 test-only 的,但安装时没有指定 <code>-t</code>参数</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_CPU_ABI_INCOMPATIBLE</td> <td>包含不兼容设备 CPU 应用程序二进制接口的 native code</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_MISSING_FEATURE</td> <td>应用使用了设备不可用的功能</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_CONTAINER_ERROR</td> <td>sdcard 访问失败</td> <td>确认 sdcard 可用,或者安装到内置存储</td> </tr> <tr> <td>INSTALL_FAILED_INVALID_INSTALL_LOCATION</td> <td>不能安装到指定位置</td> <td>切换安装位置,添加或删除<code>-s</code> 参数</td> </tr> <tr> <td>INSTALL_FAILED_MEDIA_UNAVAILABLE</td> <td>安装位置不可用</td> <td>一般为 sdcard,确认 sdcard 可用或安装到内置存储</td> </tr> <tr> <td>INSTALL_FAILED_VERIFICATION_TIMEOUT</td> <td>验证安装包超时</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_VERIFICATION_FAILURE</td> <td>验证安装包失败</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_PACKAGE_CHANGED</td> <td>应用与调用程序期望的不一致</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_UID_CHANGED</td> <td>以前安装过该应用,与本次分配的 UID 不一致</td> <td>清除以前安装过的残留文件</td> </tr> <tr> <td>INSTALL_FAILED_VERSION_DOWNGRADE</td> <td>已经安装了该应用更高版本</td> <td>使用 <code>-d</code> 参数</td> </tr> <tr> <td>INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE</td> <td>已安装 target SDK 支持运行时权限的同名应用,要安装的版本不支持运行时权限</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_NOT_APK</td> <td>指定路径不是文件,或不是以 <code>.apk</code> 结尾</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_BAD_MANIFEST</td> <td>无法解析的 AndroidManifest.xml 文件</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION</td> <td>解析器遇到异常</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_NO_CERTIFICATES</td> <td>安装包没有签名</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES</td> <td>已安装该应用,且签名与 APK 文件不一致</td> <td>先卸载设备上的该应用,再安装</td> </tr> <tr> <td>INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING</td> <td>解析 APK 文件时遇到<code>CertificateEncodingException</code></td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME</td> <td>manifest 文件里没有或者使用了无效的包名</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID</td> <td>manifest 文件里指定了无效的共享用户 ID</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_MANIFEST_MALFORMED</td> <td>解析 manifest 文件时遇到结构性错误</td> <td> </td> </tr> <tr> <td>INSTALL_PARSE_FAILED_MANIFEST_EMPTY</td> <td>在 manifest 文件里找不到找可操作标签(instrumentation 或 application)</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_INTERNAL_ERROR</td> <td>因系统问题安装失败</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_USER_RESTRICTED</td> <td>用户被限制安装应用</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_DUPLICATE_PERMISSION</td> <td>应用尝试定义一个已经存在的权限名称</td> <td> </td> </tr> <tr> <td>INSTALL_FAILED_NO_MATCHING_ABIS</td> <td>应用包含设备的应用程序二进制接口不支持的 native code</td> <td> </td> </tr> <tr> <td>INSTALL_CANCELED_BY_USER</td> <td>应用安装需要在设备上确认,但未操作设备或点了取消</td> <td>在设备上同意安装</td> </tr> <tr> <td>INSTALL_FAILED_ACWF_INCOMPATIBLE</td> <td>应用程序与设备不兼容</td> <td> </td> </tr> <tr> <td>does not contain AndroidManifest.xml</td> <td>无效的 APK 文件</td> <td> </td> </tr> <tr> <td>is not a valid zip file</td> <td>无效的 APK 文件</td> <td> </td> </tr> <tr> <td>Offline</td> <td>设备未连接成功</td> <td>先将设备与 adb 连接成功</td> </tr> <tr> <td>unauthorized</td> <td>设备未授权允许调试</td> <td> </td> </tr> <tr> <td>error: device not found</td> <td>没有连接成功的设备</td> <td>先将设备与 adb 连接成功</td> </tr> <tr> <td>protocol failure</td> <td>设备已断开连接</td> <td>先将设备与 adb 连接成功</td> </tr> <tr> <td>Unknown option: -s</td> <td>Android 2.2 以下不支持安装到 sdcard</td> <td>不使用 <code>-s</code> 参数</td> </tr> <tr> <td>No space left on devicerm</td> <td>空间不足</td> <td>清理空间</td> </tr> <tr> <td>Permission denied ... sdcard ...</td> <td>sdcard 不可用</td> <td> </td> </tr> </tbody> </table> <p>参考:<a href="/misc/goto?guid=4959677439605494834">PackageManager.java</a></p> <h3>卸载应用</h3> <p>命令:</p> <pre> adb uninstall [-k] <packagename></pre> <p><code><packagename></code> 表示应用的包名,<code>-k</code> 参数可选,表示卸载应用但保留数据和缓存目录。</p> <p>命令示例:</p> <pre> adb uninstall com.qihoo360.mobilesafe</pre> <p>表示卸载 360 手机卫士。</p> <h3>清除应用数据与缓存</h3> <p>命令:</p> <pre> adb shell pm clear <packagename></pre> <p><code><packagename></code> 表示应用名包,这条命令的效果相当于在设置里的应用信息界面点击了「清除缓存」和「清除数据」。</p> <p>命令示例:</p> <pre> adb shell pm clear com.qihoo360.mobilesafe</pre> <p>表示清除 360 手机卫士的数据和缓存。</p> <h3>查看前台 Activity</h3> <p>命令:</p> <pre> adb shell dumpsys activity activities | grep mFocusedActivity</pre> <p>输出示例:</p> <pre> mFocusedActivity: ActivityRecord{8079d7e u0 com.cyanogenmod.trebuchet/com.android.launcher3.Launcher t42}</pre> <p>其中的 <code>com.cyanogenmod.trebuchet/com.android.launcher3.Launcher</code> 就是当前处于前台的 Activity。</p> <h2>与应用交互</h2> <p>主要是使用 <code>am <command></code> 命令,常用的 <code><command></code> 如下:</p> <table> <thead> <tr> <th>command</th> <th>用途</th> </tr> </thead> <tbody> <tr> <td><code>start [options] <INTENT></code></td> <td>启动 <code><INTENT></code> 指定的 Activity</td> </tr> <tr> <td><code>startservice [options] <INTENT></code></td> <td>启动 <code><INTENT></code> 指定的 Service</td> </tr> <tr> <td><code>broadcast [options] <INTENT></code></td> <td>发送 <code><INTENT></code> 指定的广播</td> </tr> <tr> <td><code>force-stop <packagename></code></td> <td>停止 <code><packagename></code> 相关的进程</td> </tr> </tbody> </table> <p><code><INTENT></code> 参数很灵活,和写 Android 程序时代码里的 Intent 相对应。</p> <p>用于决定 intent 对象的选项如下:</p> <table> <thead> <tr> <th>参数</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td><code>-a <ACTION></code></td> <td>指定 action,比如 <code>android.intent.action.VIEW</code></td> </tr> <tr> <td><code>-c <CATEGORY></code></td> <td>指定 category,比如 <code>android.intent.category.APP_CONTACTS</code></td> </tr> <tr> <td><code>-n <COMPONENT></code></td> <td>指定完整 component 名,用于明确指定启动哪个 Activity,如 <code>com.example.app/.ExampleActivity</code></td> </tr> </tbody> </table> <p><code><INTENT></code> 里还能带数据,就像写代码时的 Bundle 一样:</p> <table> <thead> <tr> <th>参数</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td><code>--esn <EXTRA_KEY></code></td> <td>null 值(只有 key 名)</td> </tr> <tr> <td><code>-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE></code></td> <td>string 值</td> </tr> <tr> <td><code>--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE></code></td> <td>boolean 值</td> </tr> <tr> <td><code>--ei <EXTRA_KEY> <EXTRA_INT_VALUE></code></td> <td>integer 值</td> </tr> <tr> <td><code>--el <EXTRA_KEY> <EXTRA_LONG_VALUE></code></td> <td>long 值</td> </tr> <tr> <td><code>--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE></code></td> <td>float 值</td> </tr> <tr> <td><code>--eu <EXTRA_KEY> <EXTRA_URI_VALUE></code></td> <td>URI</td> </tr> <tr> <td><code>--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE></code></td> <td>component name</td> </tr> <tr> <td><code>--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]</code></td> <td>integer 数组</td> </tr> <tr> <td><code>--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]</code></td> <td>long 数组</td> </tr> </tbody> </table> <h3>调起 Activity</h3> <p>命令格式:</p> <pre> adb shell am start [options] <INTENT></pre> <p>例如:</p> <pre> adb shell am start -n com.tencent.mm/.ui.LauncherUI</pre> <p>表示调起微信主界面。</p> <pre> adb shell am start -n org.mazhuang.boottimemeasure/.MainActivity --es "toast" "hello, world"</pre> <p>表示调起 <code>org.mazhuang.boottimemeasure/.MainActivity</code> 并传给它 string 数据键值对 <code>toast - hello, world</code>。</p> <h3>调起 Service</h3> <p>命令格式:</p> <pre> adb shell am startservice [options] <INTENT></pre> <p>例如:</p> <pre> adb shell am startservice -n com.tencent.mm/.plugin.accountsync.model.AccountAuthenticatorService</pre> <p>表示调起微信的某 Service。</p> <h3>发送广播</h3> <p>命令格式:</p> <pre> adb shell am broadcast [options] <INTENT></pre> <p>例如:</p> <pre> adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n org.mazhuang.boottimemeasure/.BootCompletedReceiver</pre> <p>表示向 <code>org.mazhuang.boottimemeasure/.BootCompletedReceiver</code> 发送一个 <code>BOOT_COMPLETED</code> 广播,这类用法在测试的时候很实用,比如某个广播的场景很难制造,可以考虑通过这种方式来发送广播。</p> <h3>强制停止应用</h3> <p>命令:</p> <pre> adb shell am force-stop <packagename></pre> <p>命令示例:</p> <pre> adb shell am force-stop com.qihoo360.mobilesafe</pre> <p>表示停止 360 安全卫士的一切进程与服务。</p> <h2>文件管理</h2> <h3>复制设备里的文件到电脑</h3> <p>命令:</p> <pre> adb pull <设备里的文件路径> [电脑上的目录]</pre> <p>其中 <code>电脑上的目录</code> 参数可以省略,默认复制到当前目录。</p> <p>例:</p> <pre> adb pull /sdcard/sr.mp4 ~/tmp/</pre> <p><em>小技巧:</em>设备上的文件路径可能需要 root 权限才能访问,如果你的设备已经 root 过,可以先使用 <code>adb shell</code> 和 <code>su</code> 命令在 adb shell 里获取 root 权限后,先 <code>cp /path/on/device /sdcard/filename</code> 将文件复制到 sdcard,然后 <code>adb pull /sdcard/filename /path/on/pc</code>。</p> <h3>复制电脑里的文件到设备</h3> <p>命令:</p> <pre> adb push <电脑上的文件路径> <设备里的目录></pre> <p>例:</p> <pre> adb push ~/sr.mp4 /sdcard/</pre> <p><em>小技巧:</em>设备上的文件路径普通权限可能无法直接写入,如果你的设备已经 root 过,可以先 <code>adb push /path/on/pc /sdcard/filename</code>,然后 <code>adb shell</code> 和 <code>su</code> 在 adb shell 里获取 root 权限后,<code>cp /sdcard/filename /path/on/device</code>。</p> <h2>模拟按键/输入</h2> <p>在 <code>adb shell</code> 里有个很实用的命令叫 <code>input</code>,通过它可以做一些有趣的事情。</p> <p><code>input</code> 命令的完整 help 信息如下:</p> <pre> Usage: input [<source>] <command> [<arg>...] The sources are: mouse keyboard joystick touchnavigation touchpad trackball stylus dpad gesture touchscreen gamepad The commands and default sources are: text <string> (Default: touchscreen) keyevent [--longpress] <key code number or name> ... (Default: keyboard) tap <x> <y> (Default: touchscreen) swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen) press (Default: trackball) roll <dx> <dy> (Default: trackball)</pre> <p>比如使用 <code>adb shell input keyevent <keycode></code> 命令,不同的 keycode 能实现不同的功能,完整的 keycode 列表详见<a href="/misc/goto?guid=4959677439687183377">KeyEvent</a>,摘引部分我觉得有意思的如下:</p> <table> <thead> <tr> <th>keycode</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>3</td> <td>HOME 键</td> </tr> <tr> <td>4</td> <td>返回键</td> </tr> <tr> <td>5</td> <td>打开拨号应用</td> </tr> <tr> <td>6</td> <td>挂断电话</td> </tr> <tr> <td>24</td> <td>增加音量</td> </tr> <tr> <td>25</td> <td>降低音量</td> </tr> <tr> <td>26</td> <td>电源键</td> </tr> <tr> <td>27</td> <td>拍照(需要在相机应用里)</td> </tr> <tr> <td>64</td> <td>打开浏览器</td> </tr> <tr> <td>82</td> <td>菜单键</td> </tr> <tr> <td>85</td> <td>播放/暂停</td> </tr> <tr> <td>86</td> <td>停止播放</td> </tr> <tr> <td>87</td> <td>播放下一首</td> </tr> <tr> <td>88</td> <td>播放上一首</td> </tr> <tr> <td>122</td> <td>移动光标到行首或列表顶部</td> </tr> <tr> <td>123</td> <td>移动光标到行末或列表底部</td> </tr> <tr> <td>126</td> <td>恢复播放</td> </tr> <tr> <td>127</td> <td>暂停播放</td> </tr> <tr> <td>164</td> <td>静音</td> </tr> <tr> <td>176</td> <td>打开系统设置</td> </tr> <tr> <td>187</td> <td>切换应用</td> </tr> <tr> <td>207</td> <td>打开联系人</td> </tr> <tr> <td>208</td> <td>打开日历</td> </tr> <tr> <td>209</td> <td>打开音乐</td> </tr> <tr> <td>210</td> <td>打开计算器</td> </tr> <tr> <td>220</td> <td>降低屏幕亮度</td> </tr> <tr> <td>221</td> <td>提高屏幕亮度</td> </tr> <tr> <td>223</td> <td>系统休眠</td> </tr> <tr> <td>224</td> <td>点亮屏幕</td> </tr> <tr> <td>231</td> <td>打开语音助手</td> </tr> <tr> <td>276</td> <td>如果没有 wakelock 则让系统休眠</td> </tr> </tbody> </table> <p>下面是 <code>input</code> 命令的一些用法举例。</p> <h3>电源键</h3> <p>命令:</p> <pre> adb shell input keyevent 26</pre> <p>执行效果相当于按电源键。</p> <h3>菜单键</h3> <p>命令:</p> <pre> adb shell input keyevent 82</pre> <h3>HOME 键</h3> <p>命令:</p> <pre> adb shell input keyevent 3</pre> <h3>返回键</h3> <p>命令:</p> <pre> adb shell input keyevent 4</pre> <h3>音量控制</h3> <p>增加音量:</p> <pre> adb shell input keyevent 24</pre> <p>降低音量:</p> <pre> adb shell input keyevent 25</pre> <p>静音:</p> <pre> adb shell input keyevent 164</pre> <h3>媒体控制</h3> <p>播放/暂停:</p> <pre> adb shell input keyevent 85</pre> <p>停止播放:</p> <pre> adb shell input keyevent 86</pre> <p>播放下一首:</p> <pre> adb shell input keyevent 87</pre> <p>播放上一首:</p> <pre> adb shell input keyevent 88</pre> <p>恢复播放:</p> <pre> adb shell input keyevent 126</pre> <p>暂停播放:</p> <pre> adb shell input keyevent 127</pre> <h3>点亮/熄灭屏幕</h3> <p>可以通过上文讲述过的模拟电源键来切换点亮和熄灭屏幕,但如果明确地想要点亮或者熄灭屏幕,那可以使用如下方法。</p> <p>点亮屏幕:</p> <pre> adb shell input keyevent 224</pre> <p>熄灭屏幕:</p> <pre> adb shell input keyevent 223</pre> <h3>滑动解锁</h3> <p>如果锁屏没有密码,是通过滑动手势解锁,那么可以通过 <code>input swipe</code> 来解锁。</p> <p>命令(参数以机型 Nexus 5,向上滑动手势解锁举例):</p> <pre> adb shell input swipe 300 1000 300 500</pre> <p>参数 <code>300 1000 300 500</code> 分别表示<code>起始点x坐标 起始点y坐标 结束点x坐标 结束点y坐标</code>。</p> <h3>输入文本</h3> <p>在焦点处于某文本框时,可以通过 <code>input</code> 命令来输入文本。</p> <p>命令:</p> <pre> adb shell input text hello</pre> <p>现在 <code>hello</code> 出现在文本框了。</p> <h2>查看日志</h2> <p>Android 系统的日志分为两部分,底层的 Linux 内核日志输出到 /proc/kmsg,Android 的日志输出到 /dev/log。</p> <h3>Android 日志</h3> <p>命令格式:</p> <pre> [adb] logcat [<option>] ... [<filter-spec>] ...</pre> <p>常用用法列举如下:</p> <p>按级别过滤日志</p> <p>Android 的日志分为如下几个级别:</p> <ul> <li>V —— Verbose(最低,输出得最多)</li> <li>D —— Debug</li> <li>I —— Info</li> <li>W —— Warning</li> <li>E —— Error</li> <li>F —— Fatal</li> <li>S —— Silent(最高,啥也不输出)</li> </ul> <p>按某级别过滤日志则会将该级别及以上的日志输出。</p> <p>比如,命令:</p> <pre> adb logcat *:W</pre> <p>会将 Warning、Error、Fatal 和 Silent 日志输出。</p> <p>按 tag 和级别过滤日志</p> <p>比如,命令:</p> <pre> adb logcat ActivityManager:I MyApp:D *:S</pre> <p>表示输出 tag <code>ActivityManager</code> 的 Info 以上级别日志,输出 tag <code>MyApp</code> 的 Debug 以上级别日志,及其它 tag 的 Silent 级别日志(即屏蔽其它 tag 日志)。</p> <p>日志格式</p> <p>可以用 <code>adb logcat -v <format></code> 选项指定日志输出格式。</p> <p>日志支持按以下几种 <code><format></code>:</p> <ul> <li> <p>brief</p> <p>默认格式。格式为:</p> <pre> <priority>/<tag>(<pid>): <message></pre> <p>示例:</p> <pre> D/HeadsetStateMachine( 1785): Disconnected process message: 10, size: 0</pre> </li> <li> <p>process</p> <p>格式为:</p> <pre> <priority>(<pid>) <message></pre> <p>示例:</p> <pre> D( 1785) Disconnected process message: 10, size: 0 (HeadsetStateMachine)</pre> </li> <li> <p>tag</p> <p>格式为:</p> <pre> <priority>/<tag>: <message></pre> <p>示例:</p> <pre> D/HeadsetStateMachine: Disconnected process message: 10, size: 0</pre> </li> <li> <p>raw</p> <p>格式为:</p> <pre> <message></pre> <p>示例:</p> <pre> Disconnected process message: 10, size: 0</pre> </li> <li> <p>time</p> <p>格式为:</p> <pre> <datetime> <priority>/<tag>(<pid>): <message></pre> <p>示例:</p> <pre> 08-28 22:39:39.974 D/HeadsetStateMachine( 1785): Disconnected process message: 10, size: 0</pre> </li> <li> <p>threadtime</p> <p>格式为:</p> <pre> <datetime> <pid> <tid> <priority> <tag>: <message></pre> <p>示例:</p> <pre> 08-28 22:39:39.974 1785 1832 D HeadsetStateMachine: Disconnected process message: 10, size: 0</pre> </li> <li> <p>long</p> <p>格式为:</p> <pre> [ <datetime> <pid>:<tid> <priority>/<tag> ] <message></pre> <p>示例:</p> <pre> [ 08-28 22:39:39.974 1785: 1832 D/HeadsetStateMachine ] Disconnected process message: 10, size: 0</pre> </li> </ul> <p>指定格式可与上面的过滤同时使用。比如:</p> <pre> adb logcat -v long ActivityManager:I *:S</pre> <p>清空日志</p> <pre> adb logcat -c</pre> <h3>内核日志</h3> <p>命令:</p> <pre> adb shell dmesg</pre> <p>输出示例:</p> <pre> <6>[14201.684016] PM: noirq resume of devices complete after 0.982 msecs <6>[14201.685525] PM: early resume of devices complete after 0.838 msecs <6>[14201.753642] PM: resume of devices complete after 68.106 msecs <4>[14201.755954] Restarting tasks ... done. <6>[14201.771229] PM: suspend exit 2016-08-28 13:31:32.679217193 UTC <6>[14201.872373] PM: suspend entry 2016-08-28 13:31:32.780363596 UTC <6>[14201.872498] PM: Syncing filesystems ... done.</pre> <p>中括号里的 <code>[14201.684016]</code> 代表内核开始启动后的时间,单位为秒。</p> <p>通过内核日志我们可以做一些事情,比如衡量内核启动时间,在系统启动完毕后的内核日志里找到 <code>Freeing init memory</code> 那一行前面的时间就是。</p> <h2>查看设备信息</h2> <h3>型号</h3> <p>命令:</p> <pre> adb shell getprop ro.product.model</pre> <p>输出示例:</p> <pre> Nexus 5</pre> <h3>电池状况</h3> <p>命令:</p> <pre> adb shell dumpsys battery</pre> <p>输入示例:</p> <pre> Current Battery Service state: AC powered: false USB powered: true Wireless powered: false status: 2 health: 2 present: true level: 44 scale: 100 voltage: 3872 temperature: 280 technology: Li-poly</pre> <p>其中 <code>scale</code> 代表最大电量,<code>level</code> 代表当前电量。上面的输出表示还剩下 44% 的电量。</p> <h3>屏幕分辨率</h3> <p>命令:</p> <pre> adb shell wm size</pre> <p>输出示例:</p> <pre> Physical size: 1080x1920</pre> <p>该设备屏幕分辨率为 1080px * 1920px。</p> <h3>屏幕密度</h3> <p>命令:</p> <pre> adb shell wm density</pre> <p>输出示例:</p> <pre> Physical density: 420</pre> <p>该设备屏幕密度为 420dpi。</p> <h3>显示屏参数</h3> <p>命令:</p> <pre> adb shell dumpsys window displays</pre> <p>输出示例:</p> <pre> WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays) Display: mDisplayId=0 init=1080x1920 420dpi cur=1080x1920 app=1080x1794 rng=1080x1017-1810x1731 deferred=false layoutNeeded=false</pre> <p>其中 <code>mDisplayId</code> 为 显示屏编号,<code>init</code> 是初始分辨率和屏幕密度,<code>app</code> 的高度比 <code>init</code> 里的要小,表示屏幕底部有虚拟按键,高度为 1920 - 1794 = 126px 合 42dp。</p> <h3>android_id</h3> <p>命令:</p> <pre> adb shell settings get secure android_id</pre> <p>输出示例:</p> <pre> 51b6be48bac8c569</pre> <h3>IMEI</h3> <p>在 Android 4.4 及以下版本可通过如下命令获取 IMEI:</p> <pre> adb shell dumpsys iphonesubinfo</pre> <p>输出示例:</p> <pre> Phone Subscriber Info: Phone Type = GSM Device ID = 860955027785041</pre> <p>其中的 <code>Device ID</code> 就是 IMEI。</p> <p>而在 Android 5.0 及以上版本里这个命令输出为空,得通过其它方式获取了(需要 root 权限):</p> <pre> adb shell su service call iphonesubinfo 1</pre> <p>输出示例:</p> <pre> Result: Parcel( 0x00000000: 00000000 0000000f 00360038 00390030 '........8.6.0.9.' 0x00000010: 00350035 00320030 00370037 00350038 '5.5.0.2.7.7.8.5.' 0x00000020: 00340030 00000031 '0.4.1... ')</pre> <p>把里面的有效内容提取出来就是 IMEI 了,比如这里的是 <code>860955027785041</code>。</p> <p>参考:<a href="/misc/goto?guid=4959677439762497266">adb shell dumpsys iphonesubinfo not working since Android 5.0 Lollipop</a></p> <h3>Android 系统版本</h3> <p>命令:</p> <pre> adb shell getprop ro.build.version.release</pre> <p>输出示例:</p> <pre> 5.0.2</pre> <h3>Mac 地址</h3> <p>命令:</p> <pre> adb shell cat /sys/class/net/wlan0/address</pre> <p>输出示例:</p> <pre> f8:a9:d0:17:42:4d</pre> <h3>CPU 信息</h3> <p>命令:</p> <pre> adb shell cat /proc/cpuinfo</pre> <p>输出示例:</p> <pre> Processor : ARMv7 Processor rev 0 (v7l) processor : 0 BogoMIPS : 38.40 processor : 1 BogoMIPS : 38.40 processor : 2 BogoMIPS : 38.40 processor : 3 BogoMIPS : 38.40 Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt CPU implementer : 0x51 CPU architecture: 7 CPU variant : 0x2 CPU part : 0x06f CPU revision : 0 Hardware : Qualcomm MSM 8974 HAMMERHEAD (Flattened Device Tree) Revision : 000b Serial : 0000000000000000</pre> <p>这是 Nexus 5 的 CPU 信息,我们从输出里可以看到使用的硬件是 <code>Qualcomm MSM 8974</code>,processor 的编号是 0 到 3,所以它是四核的,采用的架构是 <code>ARMv7 Processor rev 0 (v71)</code>。</p> <h3>内存信息</h3> <p>命令:</p> <pre> adb shell cat /proc/meminfo</pre> <p>输出示例:</p> <pre> MemTotal: 1027424 kB MemFree: 486564 kB Buffers: 15224 kB Cached: 72464 kB SwapCached: 24152 kB Active: 110572 kB Inactive: 259060 kB Active(anon): 79176 kB Inactive(anon): 207736 kB Active(file): 31396 kB Inactive(file): 51324 kB Unevictable: 3948 kB Mlocked: 0 kB HighTotal: 409600 kB HighFree: 132612 kB LowTotal: 617824 kB LowFree: 353952 kB SwapTotal: 262140 kB SwapFree: 207572 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 265324 kB Mapped: 47072 kB Shmem: 1020 kB Slab: 57372 kB SReclaimable: 7692 kB SUnreclaim: 49680 kB KernelStack: 4512 kB PageTables: 5912 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 775852 kB Committed_AS: 13520632 kB VmallocTotal: 385024 kB VmallocUsed: 61004 kB VmallocChunk: 209668 kB</pre> <p>其中,<code>MemTotal</code> 就是设备的总内存,<code>MemFree</code> 是当前空闲内存。</p> <h3>更多硬件与系统属性</h3> <p>设备的更多硬件与系统属性可以通过如下命令查看:</p> <pre> adb shell cat /system/build.prop</pre> <p>这会输出很多信息,包括前面几个小节提到的「型号」和「Android 系统版本」等。</p> <p>输出里还包括一些其它有用的信息,它们也可通过 <code>adb shell getprop <属性名></code> 命令单独查看,列举一部分属性如下:</p> <table> <thead> <tr> <th>属性名</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>ro.build.version.sdk</td> <td>SDK 版本</td> </tr> <tr> <td>ro.build.version.release</td> <td>Android 系统版本</td> </tr> <tr> <td>ro.build.version.security_patch</td> <td>Android 安全补丁程序级别</td> </tr> <tr> <td>ro.product.model</td> <td>型号</td> </tr> <tr> <td>ro.product.brand</td> <td>品牌</td> </tr> <tr> <td>ro.product.name</td> <td>设备名</td> </tr> <tr> <td>ro.product.board</td> <td>处理器型号</td> </tr> <tr> <td>ro.product.cpu.abilist</td> <td>CPU 支持的 abi 列表</td> </tr> <tr> <td>persist.sys.isUsbOtgEnabled</td> <td>是否支持 OTG</td> </tr> <tr> <td>dalvik.vm.heapsize</td> <td>每个应用程序的内存上限</td> </tr> <tr> <td>ro.sf.lcd_density</td> <td>屏幕密度</td> </tr> </tbody> </table> <h2>实用功能</h2> <h3>屏幕截图</h3> <p>命令:</p> <pre> adb shell screencap -p /sdcard/sc.png</pre> <p>然后将 png 文件导出到电脑:</p> <pre> adb pull /sdcard/sc.png</pre> <p>可以使用 <code>adb shell screencap -h</code> 查看 <code>screencap</code> 命令的帮助信息,下面是两个有意义的参数及含义:</p> <table> <thead> <tr> <th>参数</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>-p</td> <td>指定保存文件为 png 格式</td> </tr> <tr> <td>-d display-id</td> <td>指定截图的显示屏编号(有多显示屏的情况下)</td> </tr> </tbody> </table> <p>实测如果指定文件名以 <code>.png</code> 结尾时可以省略 -p 参数;否则需要使用 -p 参数。如果不指定文件名,截图文件的内容将直接输出到 stdout。</p> <h3>录制屏幕</h3> <p>录制屏幕以 mp4 格式保存到 /sdcard:</p> <pre> adb shell screenrecord /sdcard/filename.mp4</pre> <p>需要停止时按 Ctrl-C,默认录制时间和最长录制时间都是 180 秒。</p> <p>如果需要导出到电脑:</p> <pre> adb pull /sdcard/filename.mp4</pre> <p>可以使用 <code>adb shell screenrecord --help</code> 查看 <code>screenrecord</code> 命令的帮助信息,下面是常见参数及含义:</p> <table> <thead> <tr> <th>参数</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>--size WIDTHxHEIGHT</td> <td>视频的尺寸,比如 <code>1280x720</code>,默认是屏幕分辨率。</td> </tr> <tr> <td>--bit-rate RATE</td> <td>视频的比特率,默认是 4Mbps。</td> </tr> <tr> <td>--time-limit TIME</td> <td>录制时长,单位秒。</td> </tr> <tr> <td>--verbose</td> <td>输出更多信息。</td> </tr> </tbody> </table> <h3>重新挂载 system 分区为可写</h3> <p><strong>注:需要 root 权限。</strong></p> <p>/system 分区默认挂载为只读,但有些操作比如给 Android 系统添加命令、删除自带应用等需要对 /system 进行写操作,所以需要重新挂载它为可读写。</p> <p>步骤:</p> <ol> <li> <p>进入 shell 并切换到 root 用户权限。</p> <p>命令:</p> <pre> adb shell su</pre> </li> <li> <p>查看当前分区挂载情况。</p> <p>命令:</p> <pre> mount</pre> <p>输出示例:</p> <pre> rootfs / rootfs ro,relatime 0 0 tmpfs /dev tmpfs rw,seclabel,nosuid,relatime,mode=755 0 0 devpts /dev/pts devpts rw,seclabel,relatime,mode=600 0 0 proc /proc proc rw,relatime 0 0 sysfs /sys sysfs rw,seclabel,relatime 0 0 selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0 debugfs /sys/kernel/debug debugfs rw,relatime 0 0 none /var tmpfs rw,seclabel,relatime,mode=770,gid=1000 0 0 none /acct cgroup rw,relatime,cpuacct 0 0 none /sys/fs/cgroup tmpfs rw,seclabel,relatime,mode=750,gid=1000 0 0 none /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0 tmpfs /mnt/asec tmpfs rw,seclabel,relatime,mode=755,gid=1000 0 0 tmpfs /mnt/obb tmpfs rw,seclabel,relatime,mode=755,gid=1000 0 0 none /dev/memcg cgroup rw,relatime,memory 0 0 none /dev/cpuctl cgroup rw,relatime,cpu 0 0 none /sys/fs/cgroup tmpfs rw,seclabel,relatime,mode=750,gid=1000 0 0 none /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0 none /sys/fs/cgroup/freezer cgroup rw,relatime,freezer 0 0 /dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0 /dev/block/platform/msm_sdcc.1/by-name/userdata /data ext4 rw,seclabel,nosuid,nodev,relatime,noauto_da_alloc,data=ordered 0 0 /dev/block/platform/msm_sdcc.1/by-name/cache /cache ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0 /dev/block/platform/msm_sdcc.1/by-name/persist /persist ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0 /dev/block/platform/msm_sdcc.1/by-name/modem /firmware vfat ro,context=u:object_r:firmware_file:s0,relatime,uid=1000,gid=1000,fmask=0337,dmask=0227,codepage=cp437,iocharset=iso8859-1,shortname=lower,errors=remount-ro 0 0 /dev/fuse /mnt/shell/emulated fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0 /dev/fuse /mnt/shell/emulated/0 fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0</pre> <p>找到其中我们关注的带 /system 的那一行:</p> <pre> /dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0</pre> </li> <li> <p>重新挂载。</p> <p>命令:</p> <pre> mount -o remount,rw -t yaffs2 /dev/block/platform/msm_sdcc.1/by-name/system /system</pre> <p>这里的 <code>/dev/block/platform/msm_sdcc.1/by-name/system</code> 就是我们从上一步的输出里得到的文件路径。</p> </li> </ol> <p>如果输出没有提示错误的话,操作就成功了,可以对 /system 下的文件为所欲为了。</p> <h3>查看连接过的 WiFi 密码</h3> <p><strong>注:需要 root 权限。</strong></p> <p>命令:</p> <pre> adb shell su cat /data/misc/wifi/*.conf</pre> <p>输出示例:</p> <pre> network={ ssid="TP-LINK_9DFC" scan_ssid=1 psk="123456789" key_mgmt=WPA-PSK group=CCMP TKIP auth_alg=OPEN sim_num=1 priority=13893 } network={ ssid="TP-LINK_F11E" psk="987654321" key_mgmt=WPA-PSK sim_num=1 priority=17293 }</pre> <p><code>ssid</code> 即为我们在 WLAN 设置里看到的名称,<code>psk</code> 为密码,<code>key_mgmt</code> 为安全加密方式。</p> <h3>设置系统日期和时间</h3> <p><strong>注:需要 root 权限。</strong></p> <p>命令:</p> <pre> adb shell su date -s 20160823.131500</pre> <p>表示将系统日期和时间更改为 2016 年 08 月 23 日 13 点 15 分 00 秒。</p> <h3>重启手机</h3> <p>命令:</p> <pre> adb reboot</pre> <h3>检测设备是否已 root</h3> <p>命令:</p> <pre> adb shell su</pre> <p>此时命令行提示符是 <code>$</code> 则表示没有 root 权限,是 <code>#</code> 则表示已 root。</p> <h3>使用 Monkey 进行压力测试</h3> <p>Monkey 可以生成伪随机用户事件来模拟单击、触摸、手势等操作,可以对正在开发中的程序进行随机压力测试。</p> <p>简单用法:</p> <pre> adb shell monkey -p <packagename> -v 500</pre> <p>表示向 <code><packagename></code> 指定的应用程序发送 500 个伪随机事件。</p> <p>Monkey 的详细用法参考 <a href="/misc/goto?guid=4959677439852545329">官方文档</a>。</p> <h3>开启/关闭 WiFi</h3> <p><strong>注:需要 root 权限。</strong></p> <p>有时需要控制设备的 WiFi 状态,可以用以下指令完成。</p> <p>开启 WiFi:</p> <pre> adb root adb shell svc wifi enable</pre> <p>关闭 WiFi:</p> <pre> adb root adb shell svc wifi disable</pre> <p>若执行成功,输出为空;若未取得 root 权限执行此命令,将执行失败,输出 <code>Killed</code>。</p> <h2>刷机相关命令</h2> <h3>重启到 Recovery 模式</h3> <p>命令:</p> <pre> adb reboot recovery</pre> <h3>从 Recovery 重启到 Android</h3> <p>命令:</p> <pre> adb reboot</pre> <h3>重启到 Fastboot 模式</h3> <p>命令:</p> <pre> adb reboot bootloader</pre> <h3>通过 sideload 更新系统</h3> <p>如果我们下载了 Android 设备对应的系统更新包到电脑上,那么也可以通过 adb 来完成更新。</p> <p>以 Recovery 模式下更新为例:</p> <ol> <li> <p>重启到 Recovery 模式。</p> <p>命令:</p> <pre> adb reboot recovery</pre> </li> <li> <p>在设备的 Recovery 界面上操作进入 <code>Apply update</code>-<code>Apply from ADB</code>。</p> <p>注:不同的 Recovery 菜单可能与此有差异,有的是一级菜单就有 <code>Apply update from ADB</code>。</p> </li> <li> <p>通过 adb 上传和更新系统。</p> <p>命令:</p> <pre> adb sideload <path-to-update.zip></pre> </li> </ol> <h2>更多 adb shell 命令</h2> <p>Android 系统是基于 Linux 内核的,所以 Linux 里的很多命令在 Android 里也有相同或类似的实现,在 <code>adb shell</code> 里可以调用。本文档前面的部分内容已经用到了 <code>adb shell</code> 命令。</p> <h3>查看进程</h3> <p>命令:</p> <pre> adb shell ps</pre> <p>输出示例:</p> <pre> USER PID PPID VSIZE RSS WCHAN PC NAME root 1 0 8904 788 ffffffff 00000000 S /init root 2 0 0 0 ffffffff 00000000 S kthreadd ... u0_a71 7779 5926 1538748 48896 ffffffff 00000000 S com.sohu.inputmethod.sogou:classic u0_a58 7963 5926 1561916 59568 ffffffff 00000000 S org.mazhuang.boottimemeasure ... shell 8750 217 10640 740 00000000 b6f28340 R ps</pre> <p>各列含义:</p> <table> <thead> <tr> <th>列名</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>USER</td> <td>所属用户</td> </tr> <tr> <td>PID</td> <td>进程 ID</td> </tr> <tr> <td>PPID</td> <td>父进程 ID</td> </tr> <tr> <td>NAME</td> <td>进程名</td> </tr> </tbody> </table> <h3>查看实时资源占用情况</h3> <p>命令:</p> <pre> adb shell top</pre> <p>输出示例:</p> <pre> User 0%, System 6%, IOW 0%, IRQ 0% User 3 + Nice 0 + Sys 21 + Idle 280 + IOW 0 + IRQ 0 + SIRQ 3 = 307 PID PR CPU% S #THR VSS RSS PCY UID Name 8763 0 3% R 1 10640K 1064K fg shell top 131 0 3% S 1 0K 0K fg root dhd_dpc 6144 0 0% S 115 1682004K 115916K fg system system_server 132 0 0% S 1 0K 0K fg root dhd_rxf 1731 0 0% S 6 20288K 788K fg root /system/bin/mpdecision 217 0 0% S 6 18008K 356K fg shell /sbin/adbd ... 7779 2 0% S 19 1538748K 48896K bg u0_a71 com.sohu.inputmethod.sogou:classic 7963 0 0% S 18 1561916K 59568K fg u0_a58 org.mazhuang.boottimemeasure ...</pre> <p>各列含义:</p> <table> <thead> <tr> <th>列名</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>PID</td> <td>进程 ID</td> </tr> <tr> <td>PR</td> <td>优先级</td> </tr> <tr> <td>CPU%</td> <td>当前瞬间占用 CPU 百分比</td> </tr> <tr> <td>S</td> <td>进程状态(R=运行,S=睡眠,T=跟踪/停止,Z=僵尸进程)</td> </tr> <tr> <td>#THR</td> <td>线程数</td> </tr> <tr> <td>VSS</td> <td>Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)</td> </tr> <tr> <td>RSS</td> <td>Resident Set Size 实际使用物理内存(包含共享库占用的内存)</td> </tr> <tr> <td>PCY</td> <td>调度策略优先级,SP_BACKGROUND/SPFOREGROUND</td> </tr> <tr> <td>UID</td> <td>进程所有者的用户 ID</td> </tr> <tr> <td>NAME</td> <td>进程名</td> </tr> </tbody> </table> <p><code>top</code> 命令还支持一些命令行参数,详细用法如下:</p> <pre> Usage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ] -m num 最多显示多少个进程 -n num 刷新多少次后退出 -d num 刷新时间间隔(单位秒,默认值 5) -s col 按某列排序(可用 col 值:cpu, vss, rss, thr) -t 显示线程信息 -h 显示帮助文档</pre> <h3>其它</h3> <p>如下是其它常用命令的简单描述,前文已经专门讲过的命令不再额外说明:</p> <table> <thead> <tr> <th>命令</th> <th>功能</th> </tr> </thead> <tbody> <tr> <td>cat</td> <td>显示文件内容</td> </tr> <tr> <td>cd</td> <td>切换目录</td> </tr> <tr> <td>chmod</td> <td>改变文件的存取模式/访问权限</td> </tr> <tr> <td>df</td> <td>查看磁盘空间使用情况</td> </tr> <tr> <td>grep</td> <td>过滤输出</td> </tr> <tr> <td>kill</td> <td>杀死指定 PID 的进程</td> </tr> <tr> <td>ls</td> <td>列举目录内容</td> </tr> <tr> <td>mount</td> <td>挂载目录的查看和管理</td> </tr> <tr> <td>mv</td> <td>移动或重命名文件</td> </tr> <tr> <td>ps</td> <td>查看正在运行的进程</td> </tr> <tr> <td>rm</td> <td>删除文件</td> </tr> <tr> <td>top</td> <td>查看进程的资源占用情况</td> </tr> </tbody> </table> <p> </p> <p>来自:https://github.com/mzlogin/awesome-adb#%E9%87%8D%E5%90%AF%E5%88%B0-recovery-%E6%A8%A1%E5%BC%8F</p> <p> </p>