Android系统--Binder系统具体框架分析(一)

Binder系统具体框架分析(一)

一、Binder系统核心框架

1. IPC:Inter-Process Communication, 进程间通信

  • A进程将数据原原本本发送B进程,主要负责进程间数据传输

    • 源地址

    • 目的地址

      • 进程B向ServiceManager注册服务

      • 进程A向ServiceManager查询服务,得到一个handle,handle指向B进程,即目的地址

    • 数据包

2. RPC:Remote Procedure Call, 远程过程调用,主要用于调用服务中函数

  • A进程想操作硬件(LED为例),ledopen/ledctrl,实质A->B,B来操作硬件

    • 封装构造数据

    • 发送数据包给B进程

    • B进程收到之后发送数据

    • 调用本地ledopen/ledctrl函数

      • Server的函数编号

      • 通过IPC的buf传输

3. 具体Binder驱动调用关系

3.1 首先需要向ServiceManager注册一个服务,故先运行的为ServiceManager
  • open Binder驱动--binder_open();

  • 告诉驱动程序,自身是ServiceManager--binder_become_context_manager();

  • while(1)--binder_loop(bs, svcmgr_handler);

    • 读取驱动信息,获取数据--res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

    • 解析处理数据--binder_parse

    • 调用两个函数(1. 注册服务; 2. 获取服务,返回handle)

      // 解析
      
      // 处理  : svcmgr_handler
      
                   SVC_MGR_GET_SERVICE/SVC_MGR_CHECK_SERVICE : 获取服务
      
                   SVC_MGR_ADD_SERVICE : 注册服务          
      
      // 回复          
      
3.2 Server如何调用函数并执行
  • open Binder驱动程序--binder_open();

  • 注册服务(向ServiceManager发送服务名字)--binder_call(bs, &msg, &reply, 0, SVC_MGR_ADD_SERVICE);

        // bs:驱动信息
    
        // &msg:含有服务的名字
    
        // &reply:它会含有servicemanager回复的数据 
    
        // 0:表示servicemanager
    
        // SVC_MGR_ADD_SERVICE:code,表示要调用servicemanager中的"addservice函数"
    
  • while(1)

    • 读取驱动信息,获取数据

    • 解析数据

    • 调用对应函数

3.3 Client如何进行数据传输
  • open Binder驱动程序--binder_open();

  • 获取服务(向ServiceManager查询服务,获得一个handle)-- binder_call(bs, &msg, &reply, 0, SVC_MGR_CHECK_SERVICE)

        // bs:驱动信息
    
        // &msg:含有服务的名字
    
        // &reply:它会含有servicemanager回复的数据, 表示提供服务的进程 
    
        // 0,表示servicemanager
    
        // SVC_MGR_CHECK_SERVICE:code,表示要调用servicemanager中的"getservice函数"
    
  • 向handle发送数据

3.4 binder_call具体分析:实现远程调用RPC
3.4.1 函数作用:
  • 向谁发送数据

  • 调用哪个函数

  • 提供什么参数

  • 返回值

binder_call函数

int binder_call(struct binder_state *bs, struct binder_io *msg, struct binder_io *reply, uint32_t target, uint32_t code)

3.4.2 如何使用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;

    };

    

    unsigned iodata[512/4];     

    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);     

    bio_put_uint32(&msg, 0);                    // strict mode header     

    bio_put_string16_x(&msg, SVC_MGR_NAME);     

    bio_put_string16_x(&msg, name);     

    bio_put_obj(&msg, ptr);

  • binder_io,target,code->binder_write_read

    struct {

        uint32_t cmd;

        struct binder_transaction_data txn;

    } __attribute__((packed)) writebuf;

    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;

  • 调用ioctl发送数据--ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

    • struct binder_write_read bwr;

struct binder_write_read {

 binder_size_t write_size;

 binder_size_t write_consumed;

 binder_uintptr_t write_buffer;

/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */

 binder_size_t read_size;

 binder_size_t read_consumed;

 binder_uintptr_t read_buffer;

};

使用例子:

    bwr.write_size = sizeof(writebuf);

    bwr.write_consumed = 0;

    bwr.write_buffer = (uintptr_t) &writebuf;

  • ioctl也会接收数据,收到binder_write_read,转化binder_io
如何使用binder_call函数:构建binder_io结构体->使用binder_call(内部将实现转化等操作)

二、如何编写Binder系统APP

(1) Client 实现

  • binder_open

  • 获得服务:handle

  • 构造参数:binder_io

  • 调用binder_call(参数:handle,code,...)

  • 分析返回的binder_io,取出返回值


/* Copyright 2008 The Android Open Source Project

*/

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <linux/types.h>

#include<stdbool.h>

#include <string.h>

#include <private/android_filesystem_config.h>

#include "binder.h"

#include "test_server.h"

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);

    bio_put_uint32(&msg, 0);  // strict mode header

    bio_put_string16_x(&msg, SVC_MGR_NAME);

    bio_put_string16_x(&msg, name);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))

        return 0;

    handle = bio_get_ref(&reply);

    if (handle)

        binder_acquire(bs, handle);

    binder_done(bs, &msg, &reply);

    return handle;

}

struct binder_state *g_bs;

uint32_t g_handle;

void sayhello(void)

{

    unsigned iodata[512/4];

    struct binder_io msg, reply;

	/* 构造binder_io */

    bio_init(&msg, iodata, sizeof(iodata), 4);

    bio_put_uint32(&msg, 0);  // strict mode header

	/* 放入参数 */

	/* 调用binder_call */

    if (binder_call(g_bs, &msg, &reply, g_handle, HELLO_SVR_CMD_SAYHELLO))

        return ;

	

	/* 从reply中解析出返回值 */

    binder_done(g_bs, &msg, &reply);

	

}

int sayhello_to(char *name)

{

	unsigned iodata[512/4];

	struct binder_io msg, reply;

	int ret;

	/* 构造binder_io */

	bio_init(&msg, iodata, sizeof(iodata), 4);

	bio_put_uint32(&msg, 0);  // strict mode header

	/* 放入参数 */

    bio_put_string16_x(&msg, name);

	/* 调用binder_call */

	if (binder_call(g_bs, &msg, &reply, g_handle, HELLO_SVR_CMD_SAYHELLO_TO))

		return 0;

	

	/* 从reply中解析出返回值 */

	ret = bio_get_uint32(&reply);

	binder_done(g_bs, &msg, &reply);

	return ret;

	

}

/* ./test_client hello

 * ./test_client hello <name>

 */

int main(int argc, char **argv)

{

    int fd;

    struct binder_state *bs;

    uint32_t svcmgr = BINDER_SERVICE_MANAGER;

    uint32_t handle;

	int ret;

	if (argc < 2){

        fprintf(stderr, "Usage:
");

        fprintf(stderr, "%s hello
", argv[0]);

        fprintf(stderr, "%s hello <name>
", argv[0]);

        return -1;

	}

    bs = binder_open(128*1024);

    if (!bs) {

        fprintf(stderr, "failed to open binder driver
");

        return -1;

    }

	g_bs = bs;

	/* get service */

	handle = svcmgr_lookup(bs, svcmgr, "hello");

	if (!handle) {

        fprintf(stderr, "failed to get hello service
");

        return -1;

	}

	g_handle = handle;

	/* send data to server */

	if (argc == 2) {

		sayhello();

	} else if (argc == 3) {

		ret = sayhello_to(argv[2]);

        fprintf(stderr, "get ret of sayhello_to = %d
", ret);		

	}

	binder_release(bs, handle);

    return 0;

}

(2) Server 实现

  • binder_open

  • 注册服务

  • ioctl()读取数据

  • 解析数据--binder_write_read()

  • 根据code决定调用哪个函数,从binder_io中取出参数

  • 把返回值转化为binder_io后返回


/* Copyright 2008 The Android Open Source Project

 */

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <linux/types.h>

#include<stdbool.h>

#include <string.h>

#include <private/android_filesystem_config.h>

#include "binder.h"

#include "test_server.h"

int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)

{

    int status;

    unsigned iodata[512/4];

    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);

    bio_put_uint32(&msg, 0);  // strict mode header

    bio_put_string16_x(&msg, SVC_MGR_NAME);

    bio_put_string16_x(&msg, name);

    bio_put_obj(&msg, ptr);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))

        return -1;

    status = bio_get_uint32(&reply);

    binder_done(bs, &msg, &reply);

    return status;

}

void sayhello(void)

{

	static int cnt = 0;

	fprintf(stderr, "say hello : %d
", cnt++);

}

int sayhello_to(char *name)

{

	static int cnt = 0;

	fprintf(stderr, "say hello to %s : %d
", name, cnt++);

	return cnt;

}

int hello_service_handler(struct binder_state *bs,

                   struct binder_transaction_data *txn,

                   struct binder_io *msg,

                   struct binder_io *reply)

{

	/* 根据txn->code知道要调用哪一个函数

	 * 如果需要参数, 可以从msg取出

	 * 如果要返回结果, 可以把结果放入reply

	 */

	/* sayhello

	 * sayhello_to

	 */

	

    uint16_t *s;

	char name[512];

    size_t len;

    uint32_t handle;

    uint32_t strict_policy;

	int i;

    // Equivalent to Parcel::enforceInterface(), reading the RPC

    // header with the strict mode policy mask and the interface name.

    // Note that we ignore the strict_policy and don't propagate it

    // further (since we do no outbound RPCs anyway).

    strict_policy = bio_get_uint32(msg);

    switch(txn->code) {

    case HELLO_SVR_CMD_SAYHELLO:

		sayhello();

        return 0;

    case HELLO_SVR_CMD_SAYHELLO_TO:

		/* 从msg里取出字符串 */

		s = bio_get_string16(msg, &len);

		if (s == NULL) {

			return -1;

		}

		for (i = 0; i < len; i++)

			name[i] = s[i];

		name[i] = '';

		/* 处理 */

		i = sayhello_to(name);

		/* 把结果放入reply */

		bio_put_uint32(reply, i);

		

        break;

    default:

        fprintf(stderr, "unknown code %d
", txn->code);

        return -1;

    }

    return 0;

}

int main(int argc, char **argv)

{

    int fd;

    struct binder_state *bs;

    uint32_t svcmgr = BINDER_SERVICE_MANAGER;

    uint32_t handle;

	int ret;

    bs = binder_open(128*1024);

    if (!bs) {

        fprintf(stderr, "failed to open binder driver
");

        return -1;

    }

	/* add service */

	ret = svcmgr_publish(bs, svcmgr, "hello", (void *)123);

    if (ret) {

        fprintf(stderr, "failed to publish hello service
");

        return -1;

    }

	ret = svcmgr_publish(bs, svcmgr, "goodbye", (void *)124);

    if (ret) {

        fprintf(stderr, "failed to publish goodbye service
");

    }

#if 0

	while (1)

	{

		/* read data */

		/* parse data, and process */

		/* reply */

	}

#endif

    binder_loop(bs, hello_service_handler);

    return 0;

}

原文地址:https://www.cnblogs.com/lkq1220/p/6414112.html