---
title: 'ADB 基礎'
disqus: kyleAlien
---
ADB 基礎
===
## OverView of Content
```shell=
# adb 基本指令格式
adb [-d|-e|-s <serialNumber>] <command>
```
[TOC]
## ADB 概述
全名是 Android Debug Bridge (ADB),可以用命令行與設備進行通訊,ADB 工具在 <android_sdk\>/platform-tools/ 資料夾下,或 [**單獨下載**](https://developer.android.com/studio/releases/platform-tools) 該工具
> 
### 工作原理
* **++服務器 (電腦)++ 在啟動時會與本地 TCP 端口 ==5037== 綁定**,所有 adb 客戶端均通過端口 5037 與 adb 服務器通訊
> Window 使用 cmd 並輸入 `netstat` 就可以獲得所有網路 Port,當然也可以指定 5037 `netstat -ano | findstr 5037`
> 
* 服務器會與所有正在運行的設備建立連接,它會掃描 5555 ~ 5585 之間的基數號端口(eg. 5555、5557、5559...) 總共可以有 16 個裝置,服務器一旦發現手機的 adb 守護程序 (adbd),便會與該端口進行連接
* 每個模擬器都會使用一對按照順序排列的端口
1. 偶數:控制台連接的端口
2. 奇數:adb 連接的端口
> 
* 以下來判斷 5037 Port 到底被誰占用 (Window 系統),使用到指令 ^1^netstat、^2^tasklist、^3^findstr
> 
## 基礎命令
### adb 版本
* 可以查出 adb 版本 & 該指令安裝的位置
```shell=
adb version
```
> 
### 啟動/停止 adb 服務
1. 啟動
```shell=
adb start-server
```
> 
2. 停止
```shell=
adb kill-server
```
> 
3. 重新連接裝置 (下面小節會說明 connect)
```shell=
adb reconnect
# 也可以指定重連接的 device
adb reconnect ca6b55ed
```
> 
## 設備 adb 調適
* 在 Android 4.2 及更高版本的設備上,**開發者選項默認是隱藏狀態**,需要轉到`設置手機` -> `關於手機` 接著按版本號 7 次
* 之後進入 `開發人員選項` 中,並開啟 **==USB偵錯==**
> 
```shell=
# 基礎使用,查看裝置是否有被 adb 連接
adb devices
```
> 
| 狀態欄位(依序) | 說明 |
| -------- | -------- |
| 序列號 | adb 所創建的字符串,用於通過端口號唯一設備裝置,**之後會透過該序列號傳送指令** |
| 狀態 | 有三種狀態 ^1^ offline:設備未連接到 adb or 沒響應、^2^device:設備以連接到服務器、^3^no device:尚未連接任何設備 |
| 說明 | 需要添加參數 `-l`,這會說明該設備產品名、模組等等 |
* 添加 l 參數可以清楚看到目前是哪個裝置被連接,它的產品名、模組等等
```shell=
# 裝置的詳細訊息
adb devices -l
```
> 
### 無線連線
| 使用指令 & 格式 | 說明 |
| -------- | -------- |
| tcpip <PORT_NUM\> | 連線 PORT 號設定 |
| connect HOST[:PORT] | 透過 TCP/IP 連線設備 (PORT 預設為 5555) |
| disconnect [HOST[:PORT]] | 斷開 TCP/IP 連線,若未設定則全部斷開 |
0. 在 Android 裝置中設定開發人員選項,**開啟 `無線偵錯` 開關**
1. 將 Android 裝置與執行 adb 的服務端(PC) 連線到同一個網域(eg. 同一個 WIFI)
2. 使用 USB 將 Android 裝置與電腦連線,並開啟 USB 偵測模式,使用 `adb devices` 查看
> 
3. 設定 adbd 監聽的 PORT 號
```shell=
# 設定 adbd 監聽 Port 為 5555
adb tcpip 5555
```
> 
4. 斷開 USB
5. 去手機中找 `IP 位置` 並記錄下來 (通常在 設定 -> 網路設定 or WIFI 裡面)
6. 通過 剛剛紀錄的 IP 位置與連線裝置 (或斷開)
```shell=
# 連線
adb connect 192.168.1.101:5555
# 斷開
adb disconnect 192.169.1.101:5555
```
7. 確認連線狀態
```shell=
adb devices
```
> 
:::info
* 若尚未連線就使用 kill-server 重新啟動 adb 重試試
:::
### 有線連線
| 使用指令 | 指令格式 |
| -------- | -------- |
| usb | 重新設定 adbd 的連線 |
```shell=
adb usb
```
> 
### 指定 adb server port
* ADB Port 號預設為 5037,但也可以自己指定
```shell=
# 指令格式
adb -P <port_num> start-server
```
```shell=
# 停止當前 adb 服務
adb kill-server
# 連接指定 Port 號
adb -P 8888 start-server
# 找 window 當前對應的 prot 號
netstat -ano | findstr 8888
# 找到該 port 號使用的應用程式
tasklist | findstr 19704
```
> 
### 模擬器未被列出
// TODO: 參考官方
## 發送命令
* 若需要對設備發送命令的話,就必須指定你要發送命令的序列號,該序列號可以透過 adb devices 獲得
設備連接指令
| adb options | 解釋 |
| -------- | -------- |
| -s | 指定序列號(須查詢) |
| -e | **若只有一個模擬器,可以直接用 -e 安裝** (多個模擬器則必須指定) |
| -d | **若只有一個實體裝置,可以直接用 -d 安裝** (多個實體裝置則必須指定) |
```shell=
// 查看序列號
adb devices -l
// 指定序列號 -s
adb -s R58N70X9XFX shell dumpsys activity | findstr mResume
```
> 
### 安裝 APK install
* 使用關鍵字 **install** 安裝 APK 到設備,以下說明幾個較常使用的 options (配合 install 使用)
```shell=
# 指令格式
adb <連接設備方式> install [options] <APK_PATH>
```
| options | 說明 |
| -------- | -------- |
| -r | 允許覆蓋已有的 APP 應用 |
| -t | 允許安裝測試 APP,該測試 APP 必須在 AndroidManifest.xml#application 中設置,**android:testOnly="true"** |
| -d | 允許安裝版本低的 APP (一般來說裝置上的 version code = 11,就不能安裝 version code 是 10 的應用) |
| -s | 安裝 APK 到 SDK card 中 |
| -g | 授權 Runtime 時所需的權限 (eg. 外部儲存、位置...) |
* 安裝 APP,使用 -r 覆蓋,並且使用 -d 允與安裝較低版本的 APP
```shell=
# 目前我使用實體機,而且只有一台,所以直接使用 -d 安裝
adb -d install -r -d C:\Users\alien\StudioProjects\MyApp\app\build\outputs\apk\prodUniversal\release\ReleaseApp.apk
```
> 
:::warning
* 以下狀況是裝置上的 version 比起目前要安裝的App version 還要高所以無法安裝,這時候只要使用 `-d` 就可以安裝 APP
```shell=
adb -d install -r C:\Users\alien\StudioProjects\MyApp\app\build\outputs\apk\prodUniversal\release\ReleaseApp.apk
```
> 
:::
* 安裝錯誤提示,**詳細的可以參考 PackageManager**
| 錯誤內容 | 說明 | 解法 |
| -------- | -------- | -------- |
| `INSTALL_FAILED_ALREADY_EXISTS` | 應用已經存在 | -r |
| `INSTALL_FAILED_INVALID_APK` | 無效的 APK **檔案** | APK 問題 |
| `INSTALL_FAILED_INVALID_URI` | 無效的 APK **檔名** | APK 檔名建議不要使用中文 |
| `INSTALL_FAILED_INSUFFICIENT_STORAGE` | 空間不足 | 清理空間 |
| `INSTALL_FAILED_DUPLICATE_PACKAGE` | 應用程式同名 | |
| `INSTALL_FAILED_NO_SHARED_USER` | 請求的共享使用者不存在 | |
| `INSTALL_FAILED_UPDATE_INCOMPATIBLE` | 已經安裝過簽名不一樣的同名應用,且資料沒有移除 | |
| `INSTALL_FAILED_SHARED_USER_INCOMPATIBLE` | 請求的共享使用者存在但簽名不一致 | |
| `INSTALL_FAILED_MISSING_SHARED_LIBRARY` | 安裝包使用了裝置上不可用的共享庫 | |
| `INSTALL_FAILED_REPLACE_COULDNT_DELETE` | 替換時無法刪除 | |
| `INSTALL_FAILED_DEXOPT` | dex 優化驗證失敗或空間不足 | |
| `INSTALL_FAILED_OLDER_SDK` | 裝置系統版本低於應用要求 | |
| `INSTALL_FAILED_CONFLICTING_PROVIDER` | 裝置裡已經存在與應用裡同名的 content provider | |
| `INSTALL_FAILED_NEWER_SDK` | 裝置系統版本高於應用要求 | |
| `INSTALL_FAILED_TEST_ONLY` | 應用是 test-only 的,但安裝時沒有指定 -t 引數 | -t |
| `INSTALL_FAILED_CPU_ABI_INCOMPATIBLE` | 包含不相容裝置 CPU 應用程式二進位制介面的 native code | |
| `INSTALL_FAILED_MISSING_FEATURE` | 應用使用了裝置不可用的功能 | |
| `INSTALL_FAILED_CONTAINER_ERROR` | sdcard 訪問失敗 | 確認 sdcard 可用,或者安裝到內建儲存 |
| `INSTALL_FAILED_INVALID_INSTALL_LOCATION` | 不能安裝到指定位置 | 切換安裝位置,新增或刪除 **-s** 引數 |
| `INSTALL_FAILED_MEDIA_UNAVAILABLE` | 安裝位置不可用 | 一般為 sdcard,確認 sdcard 可用或安裝到內建儲存 |
| `INSTALL_FAILED_VERIFICATION_TIMEOUT` | 驗證安裝包超時 | |
| `INSTALL_FAILED_VERIFICATION_FAILURE` | 驗證安裝包失敗 | |
| `INSTALL_FAILED_PACKAGE_CHANGED` | 應用與呼叫程式期望的不一致 | |
| `INSTALL_FAILED_UID_CHANGED` | 以前安裝過該應用,與本次分配的 UID 不一致 | 清除以前安裝過的殘留檔案 |
| `INSTALL_FAILED_VERSION_DOWNGRADE` | 已經安裝了該應用更高版本 | 使用 -d 引數 |
| `INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE` | 已安裝 target SDK 支援執行時許可權的同名應用,要安裝的版本不支援執行時許可權 | |
| `INSTALL_PARSE_FAILED_NOT_APK` | 指定路徑不是檔案,或不是以 .apk 結尾 | |
| `INSTALL_PARSE_FAILED_BAD_MANIFEST` | 無法解析的 AndroidManifest.xml 檔案 | |
| `INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION` | 解析器遇到異常 | |
| `INSTALL_PARSE_FAILED_NO_CERTIFICATES` | 安裝包沒有簽名 | |
| `INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES` | 已安裝該應用,且簽名與 APK 檔案不一致 | 先解除安裝裝置上的該應用,再安裝 |
| `INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING` | 解析 APK 檔案時遇到 CertificateEncodingException | |
| `INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME` | manifest 檔案裡沒有或者使用了無效的包名 | |
| `INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID` | manifest 檔案裡指定了無效的共享使用者 ID | |
| `INSTALL_PARSE_FAILED_MANIFEST_MALFORMED` | 解析 manifest 檔案時遇到結構性錯誤 | |
| `INSTALL_PARSE_FAILED_MANIFEST_EMPTY` | 在 manifest 檔案裡找不到找可操作標籤(instrumentation 或 application) | |
| `INSTALL_FAILED_INTERNAL_ERROR` | 因系統問題安裝失敗 | |
| `INSTALL_FAILED_USER_RESTRICTED` | 使用者被限制安裝應用 | |
| `INSTALL_FAILED_DUPLICATE_PERMISSION` | 應用嘗試定義一個已經存在的許可權名稱 | |
| `INSTALL_FAILED_NO_MATCHING_ABIS` | 應用包含裝置的應用程式二進位制介面不支援的 native code | |
| `INSTALL_CANCELED_BY_USER` | 應用安裝需要在裝置上確認,但未操作裝置或點了取消 | 在裝置上同意安裝 |
| `INSTALL_FAILED_ACWF_INCOMPATIBLE` | 應用程式與裝置不相容 | |
|does not contain AndroidManifest.xml、is not a valid zip file | 無效的 APK 檔案 | |
| Offline | 裝置未連線成功 | 先將裝置與 adb 連線成功 |
| unauthorized | 裝置未授權允許除錯 | |
| error: device not found | 沒有連線成功的裝置 | 先將裝置與 adb 連線成功 |
| protocol failure | 裝置已斷開連線 | 先將裝置與 adb 連線成功 |
| Unknown option: -s | Android 2.2 以下不支援安裝到 sdcard | 不使用 -s 引數 |
| No space left on devicerm | 空間不足 | 清理空間 |
| Permission denied … sdcard … | sdcard 不可用 | |
### 解除安裝 uninstall
* 使用關鍵字 uninstall 卸載指定應用
```shell=
# 指令格式
adb uninstall [options] <PACKAGE_NAME>
```
| options | 說明 |
| -------- | -------- |
| -k | 保留應用的 data & cache 資料夾 |
解除 flutter_hello_world 應用
```shell=
adb uninstall com.demo.flutter_hello_world
```
> 
### 傳送/接收檔案 push / pull
| 指令關鍵字 | 說明 |
| -------- | -------- |
| push [Options] <file_name\> | 複製檔案到手機中 |
| pull [Options] <file_name\> | 把檔案從手機拉到 PC |
> 
| Options | 說明 |
| -------- | -------- |
| -p | 顯示傳輸進度 |
| -a | 拷貝時保留時間搓 & 模式,相當於 Linux 中 cp -p 的 options |
:::info
* Linux 中可以使用 `man cp` 的指令查找 cp 到相關 options
> 
:::
1. push
```shell=
# 複製圖片到手機 push
adb push C:\Users\alien\Pictures\no_problem.png /sdcard/
```
> 
:::info
* 如果使用 Android studio 模擬器,該路徑在 `storage/self/primary` 下
:::
2. pull
```shell=
# 從手機裝置中拉下圖片到 桌面
adb pull /sdcard/yoyo.png Desktop/
```
> 
### logcat 分級 & tag 分類
| 級別 | 說明 |
| -------- | -------- |
| V \ Verbose | 全都輸出 |
| D \ Debug | |
| I \ Info | |
| W \ Warning | |
| E \ Error | |
| F \ Fatal | |
| S \ Silent | 都不輸出 |
指令格式
```shell=
# 指令格式,Level 是指定輸出的 Logcat 級別
adb logcat *:<Level>
# 輸出 Error tag
adb logcat *:E
```
指定 tag 輸出
```shell=
# 輸出 Tag 為 LobbyActivity & LaunchActivity Debug 級別以上的日誌,其他的都不輸出
adb logcat LobbyActivity:D LaunchActivity:D *:S
```
### locat 日誌格式
```shell=
# 指令格式
adb logcat [options] [filterspecs]
```
* 詳細的使用可以用 `adb locat --help` 查詢 (需要連接手機 or 開啟模擬器),大部分拿來查看 crash 問題
| 通用 Options | 說明 |
| -------- | -------- |
| -f <file\> | 將日誌輸出到檔案中 (測試失敗) |
| -b/ --buffer=<buffer\> | 備用環形緩衝區,**允許多個 -b 參數或逗號分隔緩衝區列表**,默認 -b 為 ^1^main、^2^system、^3^crash、^4^kernal |
| -L/ --last | 彈出所有 **pstore(下面說明)** 的 logcat |
| -c/ --clear | 清除 logcat 訊息 |
| -d | 輸出日誌並不堵塞 |
| -t <count\> | 輸出最近日誌,並且可以指定數量,可以配合 `-d` 使用 |
| -T <time\> | 指定時間到當前時間的日誌,時間格式 |
| -B/ --binary | 二進位的方式輸出日誌`'MM-DD hh:mm:ss.mmm...`、`YYYY-MM-DD hh:mm:ss.mmm...`、`sssss.mmm...` |
| -g | 輸出 Buffer size |
| -v <format\> | 指定輸出的格式,**==只能指定一種格式==** |
:::info
* What is [**pstore**](http://huaqianlee.github.io/2020/11/13/Android/pstore/) ?
> pstore 又稱為 persistent storage,這是一個儲存內核日誌 & 內核 panic 文件系統,內核會把相關信息儲存,**在一個不能被其他用戶重寫的 RAM 區**
> 下次啟動時,這個區域會被掛載到 `pstore`,一般在 `/sys/fs/pstore` 這樣我們才可以訪問這些數據
:::
* 若有多個裝置則必須使用 -s 指定裝置,下面的範例都只有一台測試,所以沒有指定
1. 緩衝區指定 -b
```shell=
# 以下指定三個緩衝區 crash、system、kernel
adb logcat -b crash -b system -b kernel
```
> 
2. 指定日誌輸出數量
```shell=
# 輸出最近 10 筆日誌
adb logcat -t 10
```
> 
3. 查看 Buffer 大小
```shell=
# 可以看到 system、main、crash buffer size
adb logcat -g
```
> 
4. -v options 介紹
| Column 1 | Column 2 |
| -------- | -------- |
| brief | 顯示 priority/tag、pid、message |
| long | 顯示所有元數據(metadata field),並且 message 換行 |
| process | 只顯示 PID |
| raw | 輸出數據原型,並且沒有 metadata field |
| tag | 只顯示 priority/tag |
| thread | 顯示 PID and TID 訊息 |
| threadtime | 顯示 調用時間、PID、TID、Date time |
| time | 調用時間、priority/tag、PID |
```shell=
# 指定 PID
adb logcat -t 10 -v process
```
> 
## [Shell](https://developer.android.com/studio/command-line/adb#shellcommands) 指令
```shell=
# shell 基礎格式
adb [-d |-e | -s serial_number] shell shell_command
# 直接進行 shell 交互,使用 `Crtl + D` 結束戶交
adb [-d |-e | -s serial_number] shell
# 查看所有 Unix 指令
adb shell ls /system/bin/
```
* 幾個較常使用的 shell command 如下
| shell command | 功能 |
| -------- | -------- |
| am | Activity 管理器 |
| pm | Package 管理器 |
| dumpsys | 調出系統資訊 |
| wn | Window 管理器 |
| settings | 手機設定的資訊 |
:::info
* 大部分命令都是由 [**toyBox**](http://landley.net/toybox/) 提通,可以透過命令查看 toybox 的所有命令
```shell=
toybox --help
```
:::
### Activity 管理器 [am](https://developer.android.com/studio/command-line/adb#am)
* 可以用來啟動 Activity、強行停止進程、廣播 intent、修改設備螢幕屬性等等功能
```shell=
# 指令格式
adb shell am <command>
```
| Command | 功能 |
| -------- | -------- |
| start [options] <Intent\> | 啟動指定的 Activity |
| start-services [options] <Intent\> | 啟動指定的 |
| broadcast [options] <Intent\> | 傳送指定的廣播 |
| force-stop <packagename\> | 停止 Package 相關應用 |
| kill [options] <package\> | 終止與 package 相關的所有進程,與 force-stop 不同在於,該命令可以安全的停止應用而不影響用戶體驗 |
| kill-all | 終止所有後台進程 |
* start intent options
| intent options | 功能 | 範例 |
| -------- | -------- | -------- |
| -a <ACTION\> | 指定 Action | android.intent.action.VIEW |
| -c <CATEGORY\> | 指定 Category | android.intent.category.APP_CONTACTS |
| -n <COMPONENT\> | 指定完整 component 名,明確指出要啟動哪個 Activity | com.example.app.\ExampleActivity |
1. 啟動 intent VIEW
```shell=
adb shell am start -a android.intent.action.VIEW
```
> 
| 帶 Bundle 參數 | 說明 |
| -------- | -------- |
| --esn <EXTRA_KEY> | null 值(只有 key 名) |
| –es <EXTRA_KEY> <EXTRA_STRING_VALUE> | string |
| --ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> | boolean |
| --ei <EXTRA_KEY> <EXTRA_INT_VALUE> | integer |
| --el <EXTRA_KEY> <EXTRA_LONG_VALUE> | long |
| --ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> | float |
| --eu <EXTRA_KEY> <EXTRA_URI_VALUE> | URI |
| --ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE> | component name |
| --eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...] | integer array |
| --ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...] | long array |
2. 使用 adb 指令開啟 APP
```shell=
# adb 啟動 <Pack name> / <Launch activity>
adb -e shell am start -n com.test.example/.activity.LobbyActivity
# 也可以使用 start-activity 啟動 Activity
adb -e shell am start-activity com.test.example/.activity.LobbyActivity
```
> IDE 替我們執行的指令 (範例)
> 
:::warning
* 要啟動的 Activity 必須有宣告 intent-filter 為 LAUNCH,否則不能啟動,並且會拋出錯誤
```xml=
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
```
> 
:::
### 應用管理 pm
* pm 可以記憶成 Package Manager
```shell=
# 指令格式
adb shell pm <Command> [options]
# 若是沒有 options 則會列出所有應用
adb shell pm list packages [options]
```
* 較常使用的 pm's command
| pm's command | 功能 |
| -------- | -------- |
| list package | 可列出所有的 package,**查看相關指令要到 `adb shell cmd package`** |
| dump <package_name> | 與該 package 相關的訊息(啟動 Activity & 權限 & meminfo 等等資訊...) |
| path <package_name> | **該 APP 安裝路徑** |
| install <package_name> | 安裝 APP |
| uninstall <package_name> | 解除 APP |
| enable <package_name> | 啟用 APP |
| disable <package_name> | 禁用 APP,**同時會隱藏 APP** |
| hide <package_name> | 隱藏 APP (測試失敗...?) |
| grant <package_name> <permission_item> | 同意某個權限 |
| revoke <package_name> <permission_item> | 撤銷某個權限 |
| reset-permissions <package_name> | **應用的權限 reset**,若沒有指定包名,則全部應用 reset |
| clear <package_name> | 清除所有 App 儲存的資料 |
```shell=
adb shell pm reset-permissions
# 查看安裝路徑
adb shell pm path tw.com.alien.www.bluetooth_le
```
> 
* 較常使用的 list's packages options
| list's packages options | 功能 |
| -------- | -------- |
| -f | 顯示應用關聯的 apk 檔案 (A 應用 與 B 應用的差異) |
| -d (disable) | 顯示無法使用的應用 |
| -e (enable) | 顯示可使用的應用 |
| -s (system) | 系統應用 |
| -3 (thired) | 第三方應用 (自己開發的應用就算是一個) |
| -i (installer) | 該應用的安裝者 |
| -u | 顯示當前有的應用程式,包括之前已解除安裝的應用 |
| <filter\> | 也可輸入相關字串查詢應用 |
1. -d 無法使用的應用
> 
2. -s 查看系統應用
> 
3. 輸入相關字串查詢應用
```shell=
# 查找 vivo 相關應用
adb shell pm list packages vivo
```
> 
* 可以使用 `findstr (Window)`、`grep (Linux)` 鎖定命標應用
```shell=
adb shell pm list packages | findstr android
```
> 
### 系統訊息 dumpsys
* dumpsys 可以調用出許多資料,在優化程式時也可以調出許多數據
```shell=
# 查詢 shell dumpsys 使用
adb -d shell dumpsys --help
# 查詢指定 command 使用
```
| Command | 功能 |
| -------- | -------- |
| <options\> | |
| cpuinfo | 當前 CPU 訊息,`adb shell cat /proc/cpuinfo` 可以查看 CPU 型號 |
| memory | 當前記憶體狀態 & 使用量 (包含 PID) |
| package | 顯示 package 包名 |
| battery <options\> | 電池資訊 |
| window <options\> | 屏幕資訊 |
| status | 狀態欄訊息 |
| alarm | 警告訊息 |
1. 電池資訊 battery
```shell=
adb -d shell dumpsys battery
```
> 
2. 屏幕引數
```shell=
adb -d shell dumpsys window displays
```
下圖的資訊
a. init:1080 x 2400 420dpi 是螢幕初始解析度 & 密度
b. app:1080 x 2274 高度稍微比 init 小
c. 虛擬按鍵:2400 - 2274 = 126px
> 
### 螢幕訊息 wm
```shell=
# 查詢 shell wm 使用
adb -d shell wm help
```
| Options | 功能 |
| -------- | -------- |
| size | 螢幕大小,其單位是 **pixels** |
| density | 密度,其單位是 **dpi**,算法可以參考 [**螢幕兼容**](https://hackmd.io/tVarTmeBSOO9YBT-PbcAzA?view) |
1. 螢幕 Size
```shell=
# 絕對單位 px
adb -d shell wm size
```
> 
2. 螢幕密度 (DPI)
```shell=
# dpi 像素密度
adb -d shell wm density
```
> 
:::info
* 計算出螢幕 Inch
```shell=
# dpi = pixels / inch
inch = 2400 / 420
Ans. 5.71 (inch)
```
:::
### [Android id](https://oldgrayduck.blogspot.com/2017/08/androidandroidid-android.html)
* Android ID 代表了該 Android 裝置唯一值,在手機第一次開機時就已經設定完成 (**恢復原廠設定時又會再次更改**),若需要判斷唯一值時,相當好判別
```java=
// Java 可以這樣取得設定
Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID)
```
* 使用 adb 取得 Android id
```shell=
adb -d shell settings get secure android_id
```
### 系統訊息 - 其他
* 大部分都是使用 Linux cat 命令去遊覽系統資訊,所以需要對 Linux 系統較孰悉,有興趣可以參考 [**Linux 基礎**](https://hackmd.io/MtOap5UaR7KcJpdTisc75g?view)
1. CPU 資訊
```shell=
# proc 目錄是系統映射
adb shell cat /proc/cpuinfo
```
2. 硬體訊息,存在 sys 目錄下 (瀏覽該目錄必須要 root 裝置)
### Bugreport
* Bugreport 是 Android 系統自帶的日誌分析系統,它包含系統的啟動 Log,以及詳細的進程資訊、VM、Cacahe、Memory 等等訊息,對於上層 APP 作用較小,大致上理解就可以
```shell=
# 指令格式
adb bugreport <輸出檔案名稱>
```
> 
## 實用功能
### 螢幕節圖 screencap
```shell=
# 截圖指令格式
adb -d shell screencap <options>
# 詳細使用方法
adb shell screencap --help
```
| Options | 說明 |
| -------- | -------- |
| -h | 訊息 (不清楚) |
| -p | 以 PNG 儲存圖片 |
| -d <display-id\> | 指定截圖的顯示屏編號(default: 0),display-id 可以透過 `dumpsys SurfaceFlinger` 只到合法 ID |
1. 螢幕截圖並移動至桌面
```shell=
# 截圖
adb -d shell screencap -p helloWorld.png
# 移動到桌面
adb pull /sdcard/helloWorld.png ./Desktop
```
> 
### 螢幕錄製 screenrecord
```shell=
# 錄影指令格式
adb -d shell screenrecord [options] <filename>
# 使用方法
adb -d shell screenrecord --h
```
| options | Column 3 |
| -------- | -------- |
| --size <Width\*Height\> | 設定錄影寬高 |
| --bit-rate <\RATE> | 設定錄影的畫素,預設 20Mbps,設定 400000 -> 4M |
| --bugreport | 添加其他信息 eg. 時間戳 |
| --time-limit <TIME\> | 設定錄影的時間,**==最長 180 秒==**,單位 ms |
| -display-id <ID\> | 指定截圖的顯示屏編號(default: 0),display-id 可以透過 `dumpsys SurfaceFlinger` 只到合法 ID |
| --verbose | 顯示相關資訊 |
## Appendix & FAQ
目前還沒測試 root 的手機,所以部分目錄無法訪問
:::info
:::
###### tags: `Android 工具`