Android : 跟我学Binder --- C程序示例

Posted sheldon_blogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android : 跟我学Binder --- C程序示例相关的知识,希望对你有一定的参考价值。


目录:

 

 

一、Binder框架分析

  1、IPC、LPC和RPC的概念:

    IPC:  (Inter Process Communication )跨进程通信,泛指进程之间任何形式的通信行为,它不仅包括各种形式的消息传递,还可以指共享资源,以及同步对象;

    LPC: Local Procedure Call 本地过程调用,用在多任务操作系统中,使得同时运行的任务能互相会话。这些任务共享内存空间使任务同步和互相发送信息;(IPC的封装)

    RPC:(Reomote Procedure Call )远程过程调用,类似于LPC,只是在网上工作。RPC开始是出现在Sun微系统公司和HP公司的运行UNIX操作系统的计算机中;

 

  2、通信架构:

    Client/Server <---> service manager 交互流程:

      server ---------addservice-------> service manager

      client  ---------getservice--------> service manager

 注:ServiceManager首先向binder驱动注册为服务管理者,handle为0;

 

  3、简析示例代码(非完整流程)

①android_5.0.2_32\\frameworks\\native\\cmds\\servicemanager\\service_manager.c  //管理server注册的服务(进程)

    a. binder_open  //打开驱动
    b. binder_become_context_manager //告诉驱动注册为service manager
    c. binder_loop(bs, svcmgr_handler);
       c.1 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  //读数据
       c.2 binder_parse // 解析数据
    
          /*处理数据  : svcmgr_handler*/
                     SVC_MGR_GET_SERVICE/SVC_MGR_CHECK_SERVICE : 获取服务
                     SVC_MGR_ADD_SERVICE : 注册服务
          /*有必要则回复数据*/  
             .......

 

android_5.0.2_32\\frameworks\\native\\cmds\\servicemanager\\bctest.c  //client测试代码

   注册服务的过程:
    a. binder_open  //打开驱动
    b. svcmgr_publish  //构造数据   
    c. binder_call(bs, &msg, &reply, 0, SVC_MGR_ADD_SERVICE)
                       // 含有服务的名字
                             // 它会含有servicemanager回复的数据
                                     // 0表示servicemanager
                                        // code: 表示要调用servicemanager中的"addservice函数"

  获取服务的过程:
    a. binder_open //打开驱动
    
b. svcmgr_lookup //构造数据
    
c. binder_call(bs,
&msg, &reply, 0, SVC_MGR_CHECK_SERVICE)      // 含有服务的名字     // 它会含有servicemanager回复的数据, 表示提供服务的进程     // 0表示servicemanager      // code: 表示要调用servicemanager中的"getservice函数

 

android_5.0.2_32\\frameworks\\native\\cmds\\servicemanager\\binder.c  //封装好的C函数

(1)构造参数:放在一个buffer用binder_io来描述;

   unsigned iodata[512/4]; //用binder_io来管理这个缓冲区
    struct binder_io msg, reply;
...
    bio_init(&msg, iodata, sizeof(iodata), 4); //初始化binder_io对象

  /*可以放入各类型参数,反之通过get方法获取*/
    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_call(struct binder_state *bs,
          struct binder_io *msg/*提供参数*/, 
          struct binder_io *reply/*获得回复*/,
          uint32_t target/*发送对象*/,
          uint32_t code/*调用函数*/)*/

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
        return -1;

 

(2)根据 binder_io、targetcode 构造writebuf:

    struct binder_write_read bwr;
    struct {
        uint32_t cmd;
        struct binder_transaction_data txn;
    } __attribute__((packed)) writebuf;
    unsigned readbuf[32];
....

    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;

  其中binder_write_read 结构体在内核代码中的定义:

struct binder_write_read {
    signed long    write_size;    /* bytes to write */
    signed long    write_consumed;    /* bytes consumed by driver */
    unsigned long    write_buffer;
    signed long    read_size;    /* bytes to read */
    signed long    read_consumed;    /* bytes consumed by driver */
    unsigned long    read_buffer;
};

  其中binder_transaction_data结构体在内核代码中的定义:

struct binder_transaction_data {
    /* The first two are only used for bcTRANSACTION and brTRANSACTION,
     * identifying the target and contents of the transaction.
     */
    union {
        size_t    handle;    /* target descriptor of command transaction */
        void    *ptr;    /* target descriptor of return transaction */
    } target;
    void        *cookie;    /* target object cookie */
    unsigned int    code;        /* transaction command */

    /* General information about the transaction. */
    unsigned int    flags;
    pid_t        sender_pid;
    uid_t        sender_euid;
    size_t        data_size;    /* number of bytes of data */
    size_t        offsets_size;    /* number of bytes of offsets */

    /* If this transaction is inline, the data immediately
     * follows here; otherwise, it ends with a pointer to
     * the data buffer.
     */
    union {
        struct {
            /* transaction data */
            const void    *buffer;
            /* offsets from buffer to flat_binder_object structs */
            const void    *offsets;
        } ptr;
        uint8_t    buf[8];
    } data;
};

 

(3)通过ioctl发送数据:

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

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

        if (res < 0) {
            fprintf(stderr,"binder: ioctl failed (%s)\\n", strerror(errno));
            goto fail;
        }

        res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); //解析返回的数据
        if (res == 0) return 0;
        if (res < 0) goto fail;
    }

 

框架流程总结:

  client端: binder_open ---> 获得服务handle ---> 构造参数binder_io ---> 调用binder_call ---> 解析返回的binder_io;

  server端:binder_open ---> 注册服务 ---> ioctl读取数据(binder_write_read )---> 解析数据(binder_transaction_data ) ---> 获得binder_io并根据code调用对应函数 ---> 把返回值发送给client;

 

 

二、编写程序

  1.参考service_manager.c编写test_server.c添加服务:

/* 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\\n", ++cnt);
}


int sayhello_to(char *name)
{
    static int cnt = 0;
    fprintf(stderr, "say hello to %s : %d\\n", name, ++cnt);
    return cnt;
}

void saygoodbye(void)
{
    static int cnt = 0;
    fprintf(stderr, "say goodbye : %d\\n", ++cnt);
}


int saygoodbye_to(char *name)
{
    static int cnt = 0;
    fprintf(stderr, "say goodbye to %s : %d\\n", 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); // 取出0,后面才是传过来的所需数据


    switch(txn->code) {
    case HELLO_SVR_CMD_SAYHELLO:
        sayhello();
        bio_put_uint32(reply, 0); /* no exception */
        return 0;

    case HELLO_SVR_CMD_SAYHELLO_TO:
        /* 从msg里取出字符串(16位转8位) */
        s = bio_get_string16(msg, &len);  //"IHelloService"
        s = bio_get_string16(msg, &len);  // name
        if (s == NULL) {
            return -1;
        }
        for (i = 0; i < len; i++)
            name[i] = s[i];
        name[i] = \'\\0\';

        /* 处理 */
        i = sayhello_to(name);

        /* 把结果放入reply */
        bio_put_uint32(reply, 0); /* no exception */
        bio_put_uint32(reply, i);
        
        break;

    default:
        fprintf(stderr, "unknown code %d\\n", txn->code);
        return -1;
    }

    return 0;
}



int goodbye_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 GOODBYE_SVR_CMD_SAYGOODBYE:
        saygoodbye();
        bio_put_uint32(reply, 0); /* no exception */
        return 0;

    case GOODBYE_SVR_CMD_SAYGOODBYE_TO:
        /* 从msg里取出字符串(16位转8位) */
        s = bio_get_string16(msg, &len);  //"IGoodbyeService"
        s = bio_get_string16(msg, &len);  // name
        if (s == NULL) {
            return -1;
        }
        for (i = 0; i < len; i++)
            name[i] = s[i];
        name[i] = \'\\0\';

        /* 处理 */
        i = saygoodbye_to(name);

        /* 把结果放入reply */
        bio_put_uint32(reply, 0); /* no exception */
        bio_put_uint32(reply, i);
        
        break;

    default:
        fprintf(stderr, "unknown code %d\\n", txn->code);
        return -1;
    }

    return 0;
}


int test_server_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    int (*handler)(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply);

    handler = (int (*)(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply))txn->target.ptr;
    
    return handler(bs, txn, msg, reply);
}

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\\n");
        return -1;
    }

    /* add service */
    ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler); //第三个参数值需要唯一,obj->binder = (uintptr_t)ptr;
    if (ret) {
        fprintf(stderr, "failed to publish hello service\\n");
        return -1;
    }
    ret = svcmgr_publish(bs, svcmgr, "goodbye", goodbye_service_handler);
    if (ret) {
        fprintf(stderr, "failed to publish goodbye service\\n");
    }

    binder_set_maxthreads(bs, 10);
    
    /* //binder_loop已封装如下步骤:
    while (1)
    {
        /* read data */
        /* parse data, and process */
        /* reply */
    }
    */
    binder_loop(bs, test_server_handler); //通过函数test_server_handler处理消息

    return 0;
}

test_server.h :

#ifndef _TEST_SERVER_H
#define _TEST_SERVER_H

#define HELLO_SVR_CMD_SAYHELLO     1
#define HELLO_SVR_CMD_SAYHELLO_TO  2

#define GOODBYE_SVR_CMD_SAYGOODBYE     1
#define GOODBYE_SVR_CMD_SAYGOODBYE_TO  2

#endif // _TEST_SERVER_H

 

    2.编写test_client.c获得/使用服务:

/* 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_hello_handle;
uint32_t g_goodbye_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 ,传入0
    bio_put_string16_x(&msg, "IHelloService");

    /* 放入参数 */

    /* 调用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_hello_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;
    int exception;

    /* 构造binder_io */
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, "IHelloService");

    /* 放入参数 */
    bio_put_string16_x(&msg, name);

    /* 调用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_hello_handle, HELLO_SVR_CMD_SAYHELLO_TO))
        return 0;
    
    /* 从reply中解析出返回值 */
    exception = bio_get_uint32(&reply);
    if (exception)
        ret = -1;
    else
        ret = bio_get_uint32(&reply);

    binder_done(g_bs, &msg, &reply);

    return ret;
    
}


void saygoodbye(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
    bio_put_string16_x(&msg, "IGoodbyeService");

    /* 放入参数 */

    /* 调用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE))
        return ;
    
    /* 从reply中解析出返回值 */

    binder_done(g_bs, &msg, &reply);
    
}

int saygoodbye_to(char *name)
{
    unsigned iodata[512/4];
    struct binder_io msg, reply;
    int ret;
    int exception;

    /* 构造binder_io */
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, "IGoodbyeService");

    /* 放入参数 */
    bio_put_string16_x(&msg, name);

    /* 调用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE_TO))
        return 0;
    
    /* 从reply中解析出返回值 */
    exception = bio_get_uint32(&reply);
    if (exception)
        ret = -以上是关于Android : 跟我学Binder ---  C程序示例的主要内容,如果未能解决你的问题,请参考以下文章

Android : 跟我学Binder ---- 什么是Binder机制?

Binder 机制分析 Android 内核源码中的 Binder 驱动源码 binder.c ( googlesource 中的 Android 内核源码 | 内核源码下载 )

Android面试Android跨进程通信之Binder

Android Binder实现浅析-Binder驱动

Android binder介绍

Android Binder 跟踪