banner
fwrite

fwrite

好好生活
twitter
github
email

AOSP調試指南

編譯 Android#

使用 envsetup.sh 腳本初始化環境:source build/envsetup.sh 或者. build/envsetup.sh

如需查看可用命令的完整列表,請運行以下命令:hmm

Framework 調試#

top#

image

  1. VIRT:這個內存使用就是一個應用佔有的地址空間,只是要應用程序要求的,就全算在這裡,而不管它真的用了沒有。寫程序怕出錯,又不在乎佔用的時候,多開點內存也是很正常的;
  2. RES: resident memory usage。常駐內存。這個值就是該應用程序真的使用的內存,但還有兩個小問題,一是有些東西可能放在交換盤上了(SWAP),二是有些內存可能是共享的;
  3. SHR:shared memory。共享內存。就是說這一塊內存空間有可能也被其他應用程序使用著;
  4. DATA:數據佔用的內存。這一塊是真正的該程序要求的數據空間,是真正在運行中要使用的。

vmstat#

image

vmstat 是一個顯示系統信息的命令。例如,它顯示主存儲器的可用容量和 CPU 的操作狀態。如果按原樣執行 vmstat 命令,則會顯示有關當前進程,內存,交換,設備,中斷和 CPU 的信息。此外,如果附加 “- d” 或 “ - p” 選項,將顯示分區和磁碟上的讀 / 寫狀態等。指定 “-f” 選項時,從系統啟動到命令執行將顯示創建進程的次數。

meminfo#

cat /proc/meminfo

image

free#

-b	以字節顯示容量(默認)
-k	顯示容量,以千字節為單位
-m	顯示容量,以MB為單位
-h  顯示容量單位,包含G、M
-t	還顯示物理內存和交換內存的總和

strace#

常用來跟蹤進程執行時的系統調用和所接收的信號。

time#

測量從調用指定命令到結束所花費的時間,用戶 CPU 時間和系統 CPU 時間。在指定命令的輸出結果之後,將測量結果輸出到標準錯誤輸出。命令代碼實際使用 CPU 的時間是用戶 CPU 時間。因此,如果將不存在的命令作為 time 命令的參數,則用戶 CPU 時間變為 0。睡眠時間不計算在內。

size#

顯示一個目標文件或者鏈接庫文件中的目標文件的各個段的大小

file#

確定並顯示文件類型

addr2line#

解析 so 文件

跳過開機引導#

adb shell settings put global device_provisioned 1

readelf#

查看 ELF 格式的文件信息

logcat#

adb root;adb remount

清除緩存  adb logcat -c

如果不能清除,就指定區域清除  adb logcat -c main/system/event/kernel/all(日誌緩衝區)

查看緩存  adb logcat -g
設置最大logcat緩存   adb logcat -G 100M

dump meminfo#

adb shell dumpsys meminfo
或者具體包
adb shell dumpsys meminfo packageName

printk#

  • 打印調試 log
printk("%d",intA);
  • 打印變量所佔內存大小
printk("sizeof(*intA)=%d",sizeof(*intA);

查看 cpu 架構#

adb shell getprop ro.product.cpu.abi

image

service 服務#

服務列表:    adb shell service list
檢測某服務是否存在:   adb shell service check SurfaceFlinger

Activity#

adb shell dumpsys activity top|grep ACTIVITY

adb shell am start -n ActivityName

獲取參數#

getprop 查看機器的全部信息參數
getprop ro.serialno 查看機器的序列號
getprop ro.carrier 查看機器的CID號
getprop ro.hardware 查看機器板子代號
getprop ro.bootloader 查看SPL(Hboot)版本號
getprop ro.build.version.release 查看系統版本(8、9...)
getprop ro.build.display.id  獲得廠商系統版本

cpu 頻率#

root權限(直接輸入su命令)
cd sys/devices/system/cpu/cpu0/cpufreq
ls文件如下

cpuinfo_cur_freq: 當前cpu正在運行的工作頻率
cpuinfo_max_freq:該文件指定了處理器能夠運行的最高工作頻率 (單位: 千赫茲)
cpuinfo_min_freq :該文件指定了處理器能夠運行的最低工作頻率 (單位: 千赫茲)

屏幕#

查看:
adb shell
wm   size  獲得手機當前分辨率
wm  density   獲得手機當前屏幕密度(例如560dpi)

修改:
wm size 1096*2560
wm density 420

恢復:
wm size reset
wm density reset

查看虛擬地址#

adb root;adb remount
adb shell  
ps -A|grep camera 查看服務的進程號(例如4712)  
cd proc/4712  進入進程號的文件夾  
more maps 查看虛擬內存地址  

SELinux 模式#

  • adb shell setenforce 0(臨時生效,關閉SELinux模式)
  • adb shell setenforce 1(啟用,開啟SELinux模式)

獲取路徑#

  • adb shell dumpsys SurfaceFlinger 最下方查看正在運行的APK
  • adb shell pm path "com.**" 獲取路徑

屬性系統#

android 通過 SystemProperties 的 set 和 get 方法來控制很多東西,一般上層添加一個控制開關可以使用這個方法,在系統裡面存在很多個 prop 文件。它們分別是 system/build.prop,system/etc/prop.default,vendor/build.prop,vendor/default.prop。下面分別來說下這幾個文件的構成。

  • system/build.prop

這個主要是由 device\(platform) sample\product/system.prop, 還有在 build 目錄下添加的 ADDITIONAL_BUILD_PROPERTIES

  • system/etc/prop.default

主要是系統添加的 PRODUCT_SYSTEM_DEFAULT_PROPERTIES

  • vendor/build.prop(比較重要)

主要是系統添加的 PRODUCT_PROPERTY_OVERRIDES,添加在 device.mk 的這個屬性會被編譯到這裡,但是在 9.0 的系統,加到這裡會無效,獲取不到值。

  • vendor/default.prop(會被同目錄的 build.prop 相同 property 覆蓋)

主要是系統添加的 PRODUCT_DEFAULT_PROPERTY_OVERRIDES

前綴:

  • ro:只讀屬性,不能修改。
  • persist:修改屬性後,重啟依然有效。數據會保存到 /data/property 目錄。其他前綴的屬性被設置後,只是保存在內存中而已,並沒有保存到磁碟,所有重啟後就恢復默認值了。
  • ctrl:用來啟動和停止服務。每一項服務必須在 init.rc 中定義。init 一旦收到設置 ctrl.start 屬性的請求,屬性服務將使用該屬性值作為服務名找到該服務,啟動該服務。這項服務的啟動結果將會放入 init.svc.<服務名> 屬性中。

Android 簽名#

Android 源碼中的系統簽名統一存放路徑:build/target/product/security

  • .pem 類型文件:在 android 對 apk 簽名的時候,.pem 這種文件就是一個 X.509 的數字證書,裡面有用戶的公鑰等信息,是用來解密的。文件格式裡面不僅可以存儲數字證書,還能存各種 key, 這個可以公開,主要用於驗證某個 App 或者其它的是否由相應的私鑰簽名。

  • .pk8 類型文件:以.pk8 為擴展名的文件,應該和 PKCS 8 是對應的,用來保存 private key, 並且這個私鑰需要保密保存,不能公開。

Android 系統簽名路徑下一共有 5 種 key:

  1. testkey:平台默認 key。如果沒有做特殊變更的話,系統編譯默認使用該 key。由於 testkey 是公開的,任何人都可以獲取,所以存在一定的風險。如果項目由特殊需求,則一般使用自己創建 key 作為系統默認 key。
  2. platform:平台的核心應用簽名之一,簽名的 apk 是完成系統的核心功能。這些 apk 所在的進程 UID 是 system。manifest 節點中有添加 sharedUserId=”android.uid.system”。
  3. shared:這個簽名的 apk 可以和 home/contacts 進程共享數據。manifest 節點中有添加 android=”android.uid.shared”。一般用在與 tel 相關的 apk。
  4. media: 這個簽名的 apk 是 media/download 的一部分。manifest 節點中有添加 android=”android.media”。一般應用在 media 相關的一些 apk。每個 Apk 包會在其對應的 Android.mk 中設置 LOCAL_CERTIFICATE 屬性,指定其中一個密鑰。(如果沒有設置此變量,則默認使用 testkey)
  5. verity:一種特殊的系統簽名。在系統編譯時會對系統進行編譯處理。需要單獨生成

生成簽名#

在 Android 根目錄下執行命令生成 releasekey、platform、shared、media。以 platform 為例,其他 key 以相同方式生成

development/tools/make_key platform'/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

釋義:

  • 所在國家 (Country) 簡稱:C ,只能是國家字母縮寫,如中國:CN
  • 所在省份 (State/Provice) 簡稱 S
  • 所在城市 (Locality) 簡稱 L
  • 單位名稱 (Organization Name) :簡稱 O
  • 部門名稱( Organizational Unit Name (eg, section) ):簡稱 OU
  • 公用名稱 (Common Name) :簡稱 CN。代碼簽名證書申請單位名稱或網站域名。
  • 郵箱(Email)

系統會提示讓你輸入生成該 key 所需要的密碼,輸入回車即可。如果設置 key 密碼,則編譯不通過。

生成的 key 存在於 Android 根目錄下,把 key 移動到/build/target/product/security下並替換之前的 key,同時需要使用 OpenSSL 的工具來驗證一下生成的 key 是否正常。以 releaseKey 為例,執行以下命令: openssl x509 -noout -subject -issuer -in releaseKey.x509.pem

生成 verity_key

  1. 編譯 verity:在 android 根目錄下編譯 verity。make generate_verity_key (mmm system/extras/verity/)
  2. 生成 veritykey 簽名:development/tools/make_key veritykey '/C=CN/ST=ChengDu/L=ChengDu /O=123/OU=13/CN=123/emailAddress=test@123.com'
  3. 執行以下命令生成.pk8 .pem 文件:out/host/linux-x86/bin/generate_verity_key -convert veritykey.x509.pem verity_key

簽名的使用和配置

簽名的使用分為兩種情況:

  1. 不區分 user 和 debug 版本,僅替換當前設備編譯是所使用的 key。
  2. 分區 user 和 debug 版本,編譯不同版本的時候使用不同的 key。

不區分 user 和 debug 版本

  1. 將 android 根目錄下生成的各種.pk8 和.pem 文件 copy 到build/target/product/security/目錄下,覆蓋之前所有的默認 key。將 veritykey.pk8,veritykey.x509.pem,verity_key.pub 重命名.pk8,verity.x509.pem,verity_key
  2. 修改 android 配置:
  • /build/core/config.mk中定義的變量:DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkey

PS:PRODUCT_DEFAULT_DEV_CERTIFICATE:mk 文件中定義的LOCAL_CERTIFICATE變量,如果 mk 文件中定義了LOCAL_CERTIFICATE,編譯則使用所定義的簽名文件,如果沒有定義 LOCAL_CERTIFICATE 變量,則進入 else 流程

  • /build/core/Makefile中定義變量:ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/releasekey) BUILD_VERSION_TAGS += release-keys

**PS:** 這段 code 主要是判斷在 config.mk 中定義的DEFAULT_SYSTEM_DEV_CERTIFICATE變量,並在編譯的時候使用對應的 build_key。在刷機後可以通過getprop build.tags來查看

  • 修改 SELinux:system/sepolicy/private/keys.conf system/sepolicy/prebuilts/api/{apilevel}/private/keys.conf

區分 user 和 debug 版本

以 testkey 作為示例:

  1. device/project/路徑下新建一個用於存放新建 key 文件的文件夾 security。僅用於存在 key 文件。後續步驟中會對路徑做條件判斷。
  2. device/project/product.mk中進行條件判斷:獲取 TARGET_BUILD_VARIANT,如果TARGET_BUILD_VARIANT為userdebug/eng,則使用build/make/target/product/security/testkey;否則使用我們自定義的文件夾中的 key

Android 設備判斷系統簽名 key#

adb root;adb remount
adb shell
cd system
getprop | grep ro.build.tags

#可以看到一行 ro.build.tags=release-keys

生成三方 APP 使用的簽名文件#

在三方 App 應用中,由於不用經過 Android 系統編譯,所以如果沒有簽名文件的情況下用到特殊權限則無法安裝使用。所以可以提供對應的.keystore 文件供其使用

在自己生成的 key 所在的路徑下:

  1. 生成 platform.pem 文件:platform.pk8 生成了.pem文件:openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out platform.priv.pem -nocrypt
  2. 生成 platform.p12 文件: openssl pkcs12 -export -in platform.x509.pem -out platform.p12 -inkey platform.pem -password pass:pwd -name name,其中 name 為 alias name,pwd 為 alias pwd
  3. 生成 platform.keystore:keytool -importkeystore -deststorepass pwd-destkeystore ./platform.keystore -srckeystore ./platform.p12 -srcstoretype PKCS12 -srcstorepass pwd

上面三個步驟可以在該路徑下生成一個platform.keystore文件。該文件可用於 apk 簽名使用。

Bootchart 性能工具使用方式#

Android 系統源碼中有 bootchart 的實現,路徑在system/core/init/bootchart.cpp中,bootchart 通過內嵌在 init 進程中實現,在後台執行測量。不過 bootchart 的測量時段是 init 進程啟動之後,不包含 uboot 和 kernel 的啟動時間

bootchart 在 android 平台的使用步驟#

  1. 使能調試設備的 bootchart 程序,進行設備必要的開機 log:adb shell 'touch /data/bootchart/enabled'
  2. adb reboot調試設備後,ubuntu 電腦連接調試設備,終端 android 根目錄執行命令:android$ ./system/core/init/grab-bootchart.sh
  3. bootchart 的圖標即生成在 android 根目錄

命令切橫豎屏#

#切橫屏:
su
settings put system user_rotation 3
settings put system accelerometer_rotation 0
#切豎屏:
settings put system accelerometer_rotation  1/2/ 3 隨便改

kernel log 命令#

adb shell cat proc/kmsg

修改 selinux 後 make 編譯#

  1. make selinux_policy:這條命令可以編譯所有 selinux ⽂件,50s 左右即可完成⼀次 make
  2. make ⽂件名例如:
make plat_file_contexts -j9;
make plat_sepolicy.cil -j9;
make vendor_sepolicy.cil -j9;
make vendor_property_contexts -j9;

同步 selinux 修改到 device#

adb push out/target/product/product/vendor/etc/selinux/* vendor/etc/selinux/*
adb push out/target/product/product/system/etc/selinux/* system/etc/selinux/*

解析 crash 地址#

symbols/vendor$ addr2line -f -e bin/test_service 000000000000ac40
_ZN12UpdateSocket9handleMsgEPv
vendor/..../test.cpp:87

清除應用數據及查看版本#

清除應用數據:adb shell pm clear com.test.upgrade
查看應用版本號:dumpsys package com.test.upgrade |grep version

編譯不生成 odex 文件#

LOCAL_DEX_PREOPT := false

ANR 日誌提取#

xxx_app_anr 這個⽂件,⼀般記錄的進程堆棧信息較之 traces ⽂件少⼀些。

所以,如果有 traces,那我們就基於該⽂件分析定位 bug。

  • traces ⽂件位於/data/anr/⽬錄下,默認情況下,每發⽣⼀次 anr,都会⽣成 traces.txt ⽂件,但是後發⽣的會將之前的覆蓋掉
  • xxx_app_anr ⽂件位於/data/system/dropbox/⽬錄下,按不同壓縮包存放。由 Dropbox 生成

出現 ANR 可以使⽤adb pull命令將⻋機⾥以上兩個⽬錄提取出來

串口禁止 / 恢復打印內核日誌#

通過調整 printk 的打印級別:

  • 禁止打印:dmesg -n1
  • 恢復打印:dmesg -n8
  • 恢復禁止: echo 0 > /proc/sys/kernel/printk
  • 恢復打印: echo 7 > /proc/sys/kernel/printk

打開觸摸坐標顯示#

  • 打開:settings put system pointer_location 1
  • 關閉:settings put system pointer_location 0

打開某應用#

  • 查看應用包名dumpsys package
  • 打開具體包查看 activity:dumpsys package com.***.***
  • 查看包位置:adb shell pm path com.***.***
  • 打開應用:am start ***/***.actvity
  • 查看當前打開應用的 activity:dumpsys activity top|grep ACTIVITY

獲取當前打開應用包名#

adb shell dumpsys window | grep mCurrentFocus

Selinux#

分類:

  • untrusted_app: 第三方 app,沒有 Android 平台簽名,沒有 system 權限
  • platform_app: 有 android 平台簽名,沒有 system 權限
  • system_app: 有 android 平台簽名和 system 權限
  • priv_app 沒有 platform 簽名的 app (肯定沒有 system 權限), 但 Android.mk 中LOCAL_PRIVILEGED_MODULE := true, 在 priv-app 目錄下的 app 查看
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。