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 查看
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。