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:\n"); fprintf(stderr, "%s hello\n", argv[0]); fprintf(stderr, "%s hello <name>\n", argv[0]); return -1; } bs = binder_open(128*1024); if (!bs) { fprintf(stderr, "failed to open binder driver\n"); return -1; } g_bs = bs; /* get service */ handle = svcmgr_lookup(bs, svcmgr, "hello"); if (!handle) { fprintf(stderr, "failed to get hello service\n"); 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\n", 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\n", cnt++); } int sayhello_to(char *name) { static int cnt = 0; fprintf(stderr, "say hello 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); 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] = '\0'; /* 处理 */ i = sayhello_to(name); /* 把结果放入reply */ bio_put_uint32(reply, i); break; default: fprintf(stderr, "unknown code %d\n", 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\n"); return -1; } /* add service */ ret = svcmgr_publish(bs, svcmgr, "hello", (void *)123); if (ret) { fprintf(stderr, "failed to publish hello service\n"); return -1; } ret = svcmgr_publish(bs, svcmgr, "goodbye", (void *)124); if (ret) { fprintf(stderr, "failed to publish goodbye service\n"); } #if 0 while (1) { /* read data */ /* parse data, and process */ /* reply */ } #endif binder_loop(bs, hello_service_handler); return 0; }

Android系统--Binder系统具体框架分析(一)的更多相关文章

  1. Android系统--Binder系统具体框架分析(二)Binder驱动情景分析

    Android系统--Binder系统具体框架分析(二)Binder驱动情景分析 1. Binder驱动情景分析 1.1 进程间通信三要素 源 目的:handle表示"服务",即向 ...

  2. Android系统--Binder系统具体框架分析(一)补充

    Android系统--Binder系统具体框架分析(一)补充 补充:对Binder驱动分析一的代码补充,添加saygoobye和saygoodbye_to服务 test_server.h #ifnde ...

  3. 深入浅出 - Android系统移植与平台开发(十一) - Sensor HAL框架分析之一

    作者:唐老师,华清远见嵌入式学院讲师. 1. Sensor的概念 Sensor即传感器,在当前智能手机上大量存在:G-Sensor.LightsSensor. ProximitySensor.Temp ...

  4. 深入浅出 - Android系统移植与平台开发(八)- HAL Stub框架分析

    作者:唐老师,华清远见嵌入式学院讲师. 1. HAL Stub框架分析 HAL stub的框架比较简单,三个结构体.两个常量.一个函数,简称321架构,它的定义在:@hardware/libhardw ...

  5. Android Binder 系统学习笔记(一)Binder系统的基本使用方法

    1.什么是RPC(远程过程调用) Binder系统的目的是实现远程过程调用(RPC),即进程A去调用进程B的某个函数,它是在进程间通信(IPC)的基础上实现的.RPC的一个应用场景如下: A进程想去打 ...

  6. 9.2 Binder系统_驱动情景分析_服务注册过程

    1. 几个重要结构体的引入给test_server添加一个goodbye服务, 由此引入以下概念: 进程间通信其实质也是需要三要素:源.目的.数据,源是自己,目的用handle表示:通讯的过程是源向实 ...

  7. Android系统--输入系统(五)输入系统框架

    Android系统--输入系统(五)输入系统框架 1. Android设备使用场景: 假设一个Android平板,APP功能.系统功能(开机关机.调节音量).外接设备功能(键盘.触摸屏.USB外接键盘 ...

  8. Android 核心分析 之六 IPC框架分析 Binder,Service,Service manager

    IPC框架分析 Binder,Service,Service manager 我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念.从Linux的概念空 ...

  9. Android系统--输入系统(七)Reader_Dispatcher线程启动分析

    Android系统--输入系统(七)Reader_Dispatcher线程启动分析 1. Reader/Dispatcher的引入 对于输入系统来说,将会创建两个线程: Reader线程(读取事件) ...

随机推荐

  1. git commit --amend用法

    提交信息很长时间内会一直保留在你的代码库(code base)中,所以你肯定希望通过这个信息正确地了解代码修改情况. 下面这个命令可以让你编辑最近一次的提交信息,但是你必须确保没有对当前的代码库(wo ...

  2. JS异步笔记

    Promise 最早接触异步是在.net中,当时还是比较流行使用基于控件的BackgroundWorker,其自身通过子线程的方式来异步处理一些情况,并且封装了一些功能与主线程通信.后来,开始使用Th ...

  3. android EditText 限定中文个数与英文个数的解决方式

    EditText 限定中文8个英文16个的解决方法. 在EditText上控件提供的属性中有限定最大最小长度的方法. 可是,对于输入时,限定中文8个英文16个时,怎么办?相当于一个中文的长度是两个英文 ...

  4. 【OC学习-13】什么是组合,它和继承是什么关系?

    继承有两缺点:(1)当层级越来越多时,假如每一个层级都有实例变量,那么最下层的子类继承的实例变量会超级多,沉重.(2)当消息传递自子类往上时.层级越多,效率越低下. 所以就有了组合.说实话区分继承和组 ...

  5. MySQL的下载及安装

    前言:不仅要知其然,还要知所以然 MySQL数据库作为关系型数据库中的佼佼者,因其体积小,速度快,成本低,不仅受到了市场的极大追捧,也受到了广大程序员的青睐.接下来,就给大家说一下,MySQL的下载和 ...

  6. react手记(componentWillMount,componentDidMount等)

    生命周期componentWillMount 组件出现前 就是dom还没有渲染到html文档里面componentDidMount 组件渲染完成 已经出现在dom文档里可以再各个周期实现特定的操作 生 ...

  7. Tomcat虚拟目录

    x先来看一段server.xml文件里的配置: <Host appBase="" autoDeploy="true" debug="0" ...

  8. linux以下C 利用openssl的AES库加密,解密

    OpenSSL提供了AES加解密算法的API const char *AES_options(void); AES算法状态,是所有支持或者是部分支持. 返回值:"aes(full)" ...

  9. PHP 如何成长 (收藏自:http://www.cnblogs.com/try-better-tomorrow/p/6964036.html)

    原文题目为<php程序员学C/C++>,不过我觉得说是提升自己比较合适. 身边有几个做PHP开发的朋友,因为面试,也接触到不少的PHP工程师,他们常疑虑自己将来在技术上的成长与发展,我常给 ...

  10. Android-NDK编译

    (2013-12-19  21:48:21 其实一切还是先看看官网的好,乱百度浪费时间.... http://developer.android.com/tools/sdk/ndk/index.htm ...