zoukankan      html  css  js  c++  java
  • 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;
    
    }
    
    
  • 相关阅读:
    洛谷 P1430 序列取数
    洛谷 P2042 维护数列
    洛谷 P3391 【模板】文艺平衡树(Splay)
    Permutation UVA
    treap板子(洛谷 P3369 【模板】普通平衡树(Treap/SBT))
    Jumping Jack CodeForces
    Increasing Sequence CodeForces
    Cunning Gena CodeForces
    Hie with the Pie POJ
    ACboy needs your help HDU
  • 原文地址:https://www.cnblogs.com/lkq1220/p/6414112.html
Copyright © 2011-2022 走看看