binder系统(一) 源码分析以及编写测试用例

android handler是什么?

binder 源码分析

binder 主要的功能是跨进程的通信
韦东山老师图
IPC:
对于binder通信,有三个对象

A  B 通信,A 需要知道 B是否存在。 通过谁? 
源:A
目的B: A通过查询, serviceManager 返回一个handler
数据: buf

RPC:
调用哪一个函数?
传给他什么参数? ipc的buff传入
返回值? ipc的buff返回

binder 上层通信思路

韦东山老师手画灵魂图
\frameworks\native\cmds\servicemanager

【client】
	{
		1. open binder 驱动
		2. 获取服务
			{
				向 serviceManager 查询服务
				获得一个 handler 
			}
		3. 向 handle 发送数据
	}
【server】
	{
		1. open binder驱动
		2. 注册服务
				a. 向 serviceManager 发送服务的名字
		3. while(1)
			{休眠
				读驱动
				解析数据
				调用对应函数
			}
	}
【serviceManager】
	{
		1. open binder驱动
		2. 告诉驱动, 它是 serviceManager
		3. while(1)
			{休眠
				读驱动数据,
				解析数据
				调用  a. 注册服务(在链表中记录名字)   
				      b.1 获取服务(链表中查询)
				      b.2 返回 "server" 进程的handle
			}
	}

* 进程间通信,都是通过binder实现。 所以第一步都是打开
* 通过 底层的 binder 来交换信息(buff)

源码验证

\frameworks\native\cmds\servicemanager\service_manager.c
service_manager

main开始分析
a. binder_open
b. binder_become_context_manager
c. binder_loop(bs, svcmgr_handler); // { while  } // --<  svcmgr_handler 传递给binder.c 回调用
	c.1 ioctl(bs->fd, BINDER_WRITE_READ, &bwr)
	c.2 binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
		解析
		处理  : svcmgr_handler   具体参看源码 txn->code
				SVC_MGR_GET_SERVICE/SVC_MGR_CHECK_SERVICE : 获取服务
				SVC_MGR_ADD_SERVICE : 注册服务
		回复

\frameworks\native\cmds\servicemanager\bctest.c
bctest

服务注册过程
	a. binder_open
	b. binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)
						msg -> 含有服务的名字
							  reply -> 返回的数据
									target -> #define BINDER_SERVICE_MANAGER  0U  // 目标是 serviceManager
							 			     code -> SVC_MGR_ADD_SERVICE -> 函数代码
获取服务的过程
	a. binder_open
	b. binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)
						msg -> 含有服务的名字
							  reply -> 返回的数据
									target -> #define BINDER_SERVICE_MANAGER  0U  // 目标是 serviceManager
							 			     code -> SVC_MGR_CHECK_SERVICE -> 函数代码

binder_call 函数分析


函数原型:
call : 调用
应该是一个远程调用

	向谁发送数据?		target
	调用哪个函数?		code
	提供的参数是什么?	msg
	返回值是什么?		reply
	int binder_call(struct binder_state *bs,
                struct binder_io *msg, struct binder_io *reply,
                uint32_t target, uint32_t code)

不知道可不可以读取binder内存来写个病毒

怎么用binder_call?

① 构造数据 : 放在buf[…], 用 binder_io 来描述

struct binder_io
{
    char *data;            /* pointer to read/write from */
    binder_size_t *offs;   /* array of offsets */
    size_t data_avail;     /* bytes available in data buffer */
    size_t offs_avail;     /* entries available in offsets array */

    char *data0;           /* start of data buffer */
    binder_size_t *offs0;  /* start of offsets buffer */
    uint32_t flags;
    uint32_t unused;
};

👆 binder_io => binder_write_read 👇
② 调用 ioctl 来发送数据

res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

struct binder_write_read bwr;
struct binder_write_read {
	binder_size_t		write_size;	/* bytes to write */
	binder_size_t		write_consumed;	/* bytes consumed by driver */
	binder_uintptr_t	write_buffer;
	binder_size_t		read_size;	/* bytes to read */
	binder_size_t		read_consumed;	/* bytes consumed by driver */
	binder_uintptr_t	read_buffer;
};

③ ioctl 也会收数据, 收到一个 binder_write_read
转换为 binder_io 再传回去.

分析 bctest.c 使用binder_call

bctest.c

// 使用传输数据
uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
{
    uint32_t handle;
    unsigned iodata[512/4];
    struct binder_io msg, reply;  // 构造

    bio_init(&msg, iodata, sizeof(iodata), 4);  // init 
    bio_put_uint32(&msg, 0);  // strict mode header // 👈 
    bio_put_string16_x(&msg, SVC_MGR_NAME); // 👈
    bio_put_string16_x(&msg, name);// 👆 有 put 就有 get

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
        return 0;
}

int binder_call(struct binder_state *bs,
                struct binder_io *msg, struct binder_io *reply,
                uint32_t target, uint32_t code)
{
    int res;
    struct binder_write_read bwr;
    struct {
        uint32_t cmd;
        struct binder_transaction_data txn;
    } __attribute__((packed)) writebuf;
    unsigned readbuf[32];

    if (msg->flags & BIO_F_OVERFLOW) {
        fprintf(stderr,"binder: txn buffer overflow\n");
        goto fail;
    }

    writebuf.cmd = BC_TRANSACTION;
    writebuf.txn.target.handle = target;
    writebuf.txn.code = code;
    writebuf.txn.flags = 0;
    writebuf.txn.data_size = msg->data - msg->data0;
    writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);
    writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;
    writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;

    bwr.write_size = sizeof(writebuf);
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) &writebuf;

    hexdump(msg->data0, msg->data - msg->data0);
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
}


根据 binder_io, target, code 三者构造
韦东山老师的图

直接构造一个binder_io, 然后直接调用 binder_call 就可以了!

自己的代码 怎么写?

1. client
	a. binder_open
	b. 获得服务: handle
	c. 构造参数: binder_io  (未转换的.)
	d. 调用 binder_call(handle, code, binder_io)
	e. 分析返回 binder_io , 取出返回值   👇
2. server 							  👇
	a. binder_open					  👇
	b. 注册服务						  👇
	c. ioctl 读取数据			  		  👇
	d. 解析数据				 		  👇
		binder_write_read->txn{ handle, code, 参数 }
			binder_write_read.readbuf->binder_transationdata{ code, 参数(构造成binder_io) }
	e. 根据code, 决定调用哪个函数, 从binder_io取出数据
	f. 再把返回值转换为 binder_io ,发送client

👇 还是韦老师的图香在这里插入图片描述

编写代码cpp :

client 端 直接调用 binder_call 发送给 server 端。
client 端看来不是很复杂,这就是rpc。

编译

查找编译方法:

/home/zp/android-8.0.0_r15/frameworks/native/cmds/servicemanager
> mmm ./ showcommands
showcommands: 为了看他的编译命令是怎样的,保存下来之后修改

比如找出来 service_manager.c

PWD=/proc/self/cwd prebuilts/clang/host/linux-x86/clang-3859424/bin/clang -c
-Iframeworks/native/cmds/servicemanager -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -fno-exceptions -Wno-multichar -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -Wa,–noexecstack -Werror=format-security -D_FORTIFY_SOURCE=2 -fno-short-enums -no-canonical-prefixes -DNDEBUG -g -Wstrict-aliasing=2 -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -DNDEBUG -UDEBUG -fdebug-prefix-map=/proc/self/cwd= -D__compiler_offsetof=__builtin_offsetof -Werror=int-conversion -Wno-reserved-id-macro -Wno-format-pedantic -Wno-unused-command-line-argument -fcolor-diagnostics -Wno-expansion-to-defined -fdebug-prefix-map=$PWD/= -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Werror=date-time -nostdlibinc -msoft-float -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
-Iexternal/selinux/libselinux/include
-Iexternal/pcre/include
-Isystem/core/libpackagelistparser/include
-Isystem/core/liblog/include
-Isystem/core/libcutils/include
-Iexternal/libcxx/include
-Iexternal/libcxxabi/include
-Isystem/core/include
-Isystem/media/audio/include
-Ihardware/libhardware/include
-Ihardware/libhardware_legacy/include
-Ihardware/ril/include
-Ilibnativehelper/include
-Iframeworks/native/include
-Iframeworks/native/opengl/include
-isystem frameworks/av/include
-isystem bionic/libc/arch-arm/include
-isystem bionic/libc/include
-isystem bionic/libc/kernel/uapi
-isystem bionic/libc/kernel/uapi/asm-arm
-isystem bionic/libc/kernel/android/uapi
-Ilibnativehelper/include/nativehelper -Wall -Wextra -Werror -DVENDORSERVICEMANAGER=1 -DBINDER_IPC_32BIT=1 -target arm-linux-androideabi -Bprebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/arm-linux-androideabi/bin -DANDROID_STRICT -fpie -D_USING_LIBCXX -std=gnu99 -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast -Werror=address-of-temporary -Werror=return-type -MD -MF out/soong/.intermediates/frameworks/native/cmds/servicemanager/vndservicemanager/android_arm_armv7-a_core/obj/frameworks/native/cmds/servicemanager/service_manager.o.d -o out/soong/.intermediates/frameworks/native/cmds/servicemanager/vndservicemanager/android_arm_armv7-a_core/obj/frameworks/native/cmds/servicemanager/service_manager.o frameworks/native/cmds/servicemanager/service_manager.c

👆 -I 的都是包含的目录

编写 makefile

APPS = service_manager test_client test_server 

all : ${APPS}

# $@ 目标         $^ 所有的依赖
service_manager : service_manager.o binder.o
	arm-linux-gcc -o $@ $^

test_client : test_client.o binder.o
	arm-linux-gcc -o $@ $^
test_server : test_server.o binder.o
	arm-linux-gcc -o $@ $^

# 所有的.o文件依赖于所有的.c文件
# $< 表示第一个依赖
%.o : %.c
	arm-linux-gcc -c -o $@ $< 

一个一个错的解决

文件找不到 1
.service_manager.c:9:47: fatal error: private/android_filesystem_config.h: No such file or directory
这时候就看上面 showcommands 打印出来的 -isystem 所带的参数

zp@ubuntu:~/android-8.0.0_r15$ find ./ -name “android_filesystem_config.h”
./system/core/libcutils/include/private/android_filesystem_config.h
./system/core/include/private/android_filesystem_config.h // 找到了在这里 👈
./build/make/tools/fs_config/default/android_filesystem_config.h
./device/google/marlin/marlin/android_filesystem_config.h
./device/google/marlin/sailfish/android_filesystem_config.h

-Isystem/core/include // 👆 上面showcommands 打印出来的,果然有

解决:
将这个config文件拷贝到自身的目录。 keep
修改makefile文件,最后一句加入

- arm-linux-gcc -c -o $@ $< 
+ arm-linux-gcc -i include -c -o $@ $< 

./bionic/libc/kernel/uapi/linux/android/binder.h
同上


一点点的 make 找错误

arm-linux-gnueabihf-gcc -o service_manager service_manager.o binder.o
service_manager.o: In function check_mac_perms': service_manager.c:(.text+0xf8): undefined reference togetpidcon’
service_manager.c:(.text+0x12c): undefined reference to selinux_check_access' service_manager.c:(.text+0x142): undefined reference tofreecon’
service_manager.o: In function check_mac_perms_from_lookup': service_manager.c:(.text+0x20c): undefined reference toselabel_lookup’
service_manager.c:(.text+0x248): undefined reference to freecon' service_manager.o: In functionsvcmgr_handler’:
service_manager.c:(.text+0x69a): undefined reference to selinux_status_updated' service_manager.c:(.text+0x6a4): undefined reference toselinux_android_service_context_handle’
service_manager.c:(.text+0x6be): undefined reference to selabel_close' service_manager.o: In functionmain’:
service_manager.c:(.text+0x8d6): undefined reference to is_selinux_enabled' service_manager.c:(.text+0x8e6): undefined reference toselinux_android_service_context_handle’
service_manager.c:(.text+0x93a): undefined reference to `getcon’
collect2: error: ld returned 1 exit status
Makefile:11: recipe for target ‘service_manager’ failed
make: *** [service_manager] Error 1

👆 不需要selinux的,我们就干脆删掉。

最终的目录结构

zp@ubuntu:~/binder_test$ tree
.
|-- Android.bp
|-- Android.mk
|-- Makefile
|-- bctest.c
|-- binder.c
|-- binder.h
|-- binder.md
|-- binder.o
|-- include
|   |-- android_filesystem_capability.h
|   |-- linux
|   |   `-- binder.h
|   `-- private
|       `-- android_filesystem_config.h
|-- service_manager
|-- service_manager.c
|-- service_manager.o
|-- servicemanager.rc
|-- test_client
|-- test_client.c
|-- test_client.o
|-- test_server
|-- test_server.c
|-- test_server.h
|-- test_server.o
`-- vndservicemanager.rc

make 成功
第一次make git地址

因为是android8.0编译, 所以和韦东山老师的makefile不一样:


APPS = service_manager test_client test_server 

all : ${APPS}

#	 $@ 目标   		<service_manager>      
# $^ 所有的依赖    	<service_manager.o binder.o>
service_manager : service_manager.o binder.o
	arm-linux-gnueabihf-g++ -fpermissive -static -o $@ $^ 

test_client : test_client.o binder.o
	arm-linux-gnueabihf-g++ -fpermissive -static -o $@ $^
test_server : test_server.o binder.o
	arm-linux-gnueabihf-g++ -fpermissive -static -o $@ $^

# 所有的.o文件依赖于所有的.c文件
# $< 表示第一个依赖
%.o : %.c
	arm-linux-gnueabihf-g++ -fpermissive -static -Iinclude -c -o $@ $< 

clean:
	rm $(APPS) -f; rm -rf *.o

# -fpermissive resolve "__unused"
# -static 

output:

255|sailfish:/data/local/tmp # ./test_server                                   
say hello : 0
 say hello : 1
 say hello : 2
 say hello : 3
 say hello : 4
 say hello to weidongshan : 0
 say hello to weidongshan : 1
 say hello to weidongshan : 2
 say hello to weidongshan : 3
 say hello to weidongshan : 4
 say hello to weidongshan : 5
------------------------------------------------------------
 sailfish:/ # /data/local/tmp/test_client                                       
Usage: 
/data/local/tmp/test_client hello
/data/local/tmp/test_client hello <name>
255|sailfish:/ # /data/local/tmp/test_client  hello                            
sailfish:/ # /data/local/tmp/test_client  hello                                
sailfish:/ # /data/local/tmp/test_client  hello                                
sailfish:/ # /data/local/tmp/test_client  hello                                
sailfish:/ # /data/local/tmp/test_client  hello                                
sailfish:/ # /data/local/tmp/test_client  hello weidongshan                    
Usage: 
/data/local/tmp/test_client hello
/data/local/tmp/test_client hello <name>
data/local/tmp/test_client  hello weidongshan                                 <
get ret to sayhello_to = 1
data/local/tmp/test_client  hello weidongshan                                 <
get ret to sayhello_to = 2
data/local/tmp/test_client  hello weidongshan                                 <
get ret to sayhello_to = 3
data/local/tmp/test_client  hello weidongshan                                 <
get ret to sayhello_to = 4
data/local/tmp/test_client  hello weidongshan                                 <
get ret to sayhello_to = 5
data/local/tmp/test_client  hello weidongshan                                 <
get ret to sayhello_to = 6
sailfish:/ # 

binder 调用的顺序图 (大致)

韦东山老师太强了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Binder是Android操作系统中的一个IPC(进程间通信)机制,用于实现进程之间的通信和数据传输。Binder源码主要位于frameworks/native目录下。 在Binder源码中,最核心的部分是Binder驱动和Binder服务。Binder驱动是位于内核空间的组件,负责处理进程间的数据传输和交互。Binder服务是位于用户空间的组件,负责提供接口和功能来进行进程间通信。 在Binder源码中,主要涉及到以下几个重要的文件和目录: 1. drivers目录:包含了Binder驱动的代码,其中最重要的文件是binder.c,它实现了Binder驱动的核心逻辑。 2. include目录:包含了Binder的头文件,其中最重要的文件是binder.h,它定义了Binder的接口和数据结构。 3. libbinder目录:包含了Binder服务的代码,其中最重要的文件是IBinder.cpp和BpBinder.cpp,它们分别实现了Binder服务的接口和代理类。 4. services目录:包含了一些系统级别的Binder服务,例如Package Manager Service和Activity Manager Service。 如果你想深入了解Android Binder源码,可以参考以下资源: 1. Android 源码:你可以从Android官网或者GitHub上获取Android源码,并在frameworks/native目录下查看Binder相关的代码。 2. Android系统架构指南:Android官网提供了关于Android系统架构的详细文档,其中有关IPC和Binder的章节对于理解Binder的实现原理和源码结构很有帮助。 3. 《深入理解Android:卷2》一书中有关于Binder的详细介绍和源码解析,可以作为参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值