专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
开发者全社区  ·  年薪300万大厂程序员被女友晒工资单被裁,百 ... ·  昨天  
开发者全社区  ·  北京86年大叔自救式征婚相亲 ·  昨天  
开发者全社区  ·  北京的普普通通有钱人 ·  昨天  
开发者全社区  ·  技术总监拿了45万年终奖突然离职,我们以为是 ... ·  2 天前  
开发者全社区  ·  色魔博士抓捕现场 ·  3 天前  
51好读  ›  专栏  ›  安卓开发精选

Binder 子系统之调试分析(二)

安卓开发精选  · 公众号  · android  · 2016-10-19 08:15

正文

(点击 上方公众号 ,可快速关注)


来源:Gityuan.com

链接:http://gityuan.com/2016/08/28/binder-debug-2/


一. 概述


上一篇文章 已经介绍了binder子系统调试的一些手段,这篇文章再来挑选系统几个核心服务进程来进行分析.


1.1 创建debugfs


首先debugfs文件系统默认挂载在节点/sys/kernel/debug,binder驱动初始化的过程会在该节点下先创建/binder目录,然后在该目录下创建下面文件和目录:


  • proc/

  • stats

  • state

  • transactions

  • transaction_log

  • failed_transaction_log


比如:


//创建目录 /sys/kernel/debug/binder

binder_debugfs_dir_entry_root = debugfs_create_dir ( "binder" , NULL );

//创建目录 /sys/kernel/debug/binder/proc

binder_debugfs_dir_entry_proc = debugfs_create_dir ( "proc" , binder_debugfs_dir_entry_root );

//创建文件/sys/kernel/debug/binder/state

debugfs_create_file ( "state" , S_IRUGO , binder_debugfs_dir_entry_root , NULL , & binder_state_fops );


另外,/d其实是指向/sys/kernel/debug的链接,也可以通过节点/d/binder来访问.


1.2 内核编译选项


如果系统关闭了debugfs,则通过编辑kernel/arch/arm/configs/×××_defconfig


//开启debugfs

CONFIG_DEBUG_FS = y

//有时,可能还需要配置fs的白名单列表,例如:

CONFIG_DEBUG_FS_WHITE_LIST = ":/tracing:/binder:/wakeup_sources:"


二. stats


2.1 binder_stats


struct binder_stats {

int br [ _IOC_NR ( BR_FAILED_REPLY ) + 1 ]; //统计各个binder响应码的个数

int bc [ _IOC_NR ( BC_DEAD_BINDER_DONE ) + 1 ]; //统计各个binder请求码的个数

int obj_created [ BINDER_STAT_COUNT ]; //统计各种obj的创建个数

int obj_deleted [ BINDER_STAT_COUNT ]; //统计各种obj的删除个数

};


其中obj的个数由一个枚举变量binder_stat_types定义。


统计创建与删除的对象


binder_stat_types中定义的量:


类型 含义
BINDER_STAT_PROC binder进程
BINDER_STAT_THREAD binder线程
BINDER_STAT_NODE binder节点
BINDER_STAT_REF binder引用节
BINDER_STAT_DEATH binder死亡
BINDER_STAT_TRANSACTION binder事务
BINDER_STAT_TRANSACTION_COMPLETE binder已完成事务


每个类型相应的调用方法:


类型 创建调用 删除调用
BINDER_STAT_PROC binder_open binder_deferred_release
BINDER_STAT_THREAD binder_get_thread binder_free_thread
BINDER_STAT_NODE binder_new_node binder_thread_read/ binder_node_release/ binder_dec_node
BINDER_STAT_REF binder_get_ref_for_node binder_delete_ref
BINDER_STAT_DEATH binder_thread_write binder_thread_read/ binder_release_work/ binder_delete_ref
BINDER_STAT_TRANSACTION binder_transaction binder_thread_read/ binder_transaction/ binder_release_work/ binder_pop_transaction
BINDER_STAT_TRANSACTION_COMPLETE binder_transaction binder_thread_read/ binder_transaction/ binder_release_work


2.2 stats分析


cat / d / binder / stats


执行上述语句,所对应的函数binder_stats_show,所输出结果分两部分:


  1. 整体统计信息

  • 所有BC_XXX命令的次数;

  • 所有BR_XXX命令的次数;

  • 输出binder_stat_types各个类型的active和total;

2.遍历所有进程的统计信息:

  • 当前进程相关的统计信息;

  • 所有BC_XXX命令的次数;

  • 所有BR_XXX命令的次数;


其中active是指当前系统存活的个数,total是指系统从开机到现在总共创建过的个数。下面举例来说明输出结果的含义:


2.2.1 整体统计信息


binder stats :

BC_TRANSACTION : 235258

BC_REPLY : 163048

BC_FREE_BUFFER : 397853

BC_INCREFS : 22573

BC_ACQUIRE : 22735

BC_RELEASE : 15840

BC_DECREFS : 15810

BC_INCREFS_DONE : 9517

BC_ACQUIRE_DONE : 9518

BC_REGISTER_LOOPER : 421

BC_ENTER_LOOPER : 284

BC_REQUEST_DEATH_NOTIFICATION : 4696

BC_CLEAR_DEATH_NOTIFICATION : 3707

BC_DEAD_BINDER_DONE : 400

BR_TRANSACTION : 235245

BR_REPLY : 163045

BR_DEAD_REPLY : 3

BR_TRANSACTION_COMPLETE : 398300

BR_INCREFS : 9517

BR_ACQUIRE : 9518

BR_RELEASE : 5448

BR_DECREFS : 5447

BR_SPAWN_LOOPER : 462

BR_DEAD_BINDER : 400

BR_CLEAR_DEATH_NOTIFICATION_DONE : 3707

BR_FAILED_REPLY : 3

proc : active 78 total 382

thread : active 530 total 3196

node : active 1753 total 8134

ref : active 2604 total 13422

death : active 530 total 3991

transaction : active 0 total 195903

transaction_complete : active 0 total 195903


可知:


  1. 当前系统binder_proc个数为78,binder_thread个数为530,binder_node为1753等信息;

  2. 从开机到现在共创建过382个binder_proc,3196个binder_thread等;

  3. transaction active等于零,目前没有活动的transaction事务


规律: BC_TRANSACTION + BC_REPLY = BR_TRANSACTION_COMPLETE + BR_DEAD_REPLY + BR_FAILED_REPLY


2.2.2 进程统计信息


proc 14328

threads : 3 //binder_thread个数

//requested_threads(请求线程数) + requested_threads_started(已启动线程数) / max_threads(最大线程数)

requested threads : 0 + 1 / 15

ready threads 2 // ready_threads(准备就绪的线程数)

free async space 520192 //可用的异步空间约为520k

nodes : 3 //binder_node个数

refs : 9 s 9 w 9 //引用次数,强引用次数,弱引用次数次数

buffers : 0 //allocated_buffers(已分配的buffer个数)

pending transactions : 0 //proc的todo队列事务个数

//该进程中BC_XXX 和BR_XXX命令执行次数

BC_TRANSACTION : 21

BC_FREE_BUFFER : 24

BC_INCREFS : 9

BC_ACQUIRE : 9

BC_INCREFS_DONE : 3

BC_ACQUIRE_DONE : 3

BC_REGISTER_LOOPER : 1

BC_ENTER_LOOPER : 1

BC_REQUEST_DEATH_NOTIFICATION : 1

BR_TRANSACTION : 4

BR_REPLY : 20

BR_TRANSACTION_COMPLETE : 21

BR_INCREFS : 3

BR_ACQUIRE : 3

BR_SPAWN_LOOPER : 1


可知进程14328:


  • 共有3个binder_thread,最大线程个数上限为15.

  • 共有3个binder_node, 9个binder_ref。

  • 已分配binder_buffer为零,异步可用空间约为520k;

  • proc->todo队列为空;


Debug Tips:


  • 当binder内存紧张时,可查看free async space和buffers:字段;

  • 当系统空闲时,一般来说ready_threads = requested_threads_started +BC_ENTER_LOOPER; 当系统繁忙时ready_threads可能为0.

  • 例如system_server进程的ready_threads线程个数越少,系统可能处于越繁忙的状态;

  • 绝大多数的进程max_threads = 15,而surfaceflinger最大线程个数为4,servicemanager最大线程个数为0(只有主线程);


例如,想查看当前系统所有进程的异步可用内存情况,可执行:


adb shell cat / d / binder / stats | egrep "proc |free async space"


2.3 其他


2.3.1 transactions


命令:


cat / d / binder / transactions


输出结果:


binder transactions :

proc 20256

buffer 348035 : ffffff800a280050 size 212 : 0 delivered

...


解释:


  • pid=20256进程,buffer的data_size=212,offsets_size=0,delivered代表已分发的内存块

  • 该命令遍历输出所有进程的情况,可以看出每个进程buffer的分发情况。


2.3.2 transaction_log


命令:


cat / d / binder / transaction_log


输出结果:


357140 : async from 8963 : 9594 to







请到「今天看啥」查看全文