Android Binder&Aidl理解和补充

Android 四大组件:activity显示,service后台服务,broadcast通信, contentProvider 数据共享.
相关系列文章:
Activity总结和补充:https://www.jianshu.com/p/bd31881c28fc
Android Binder&Aidl理解和补充:https://www.jianshu.com/p/eb791ae04e2f
Service史上最全面解析》理解和补充: https://www.jianshu.com/p/444af9739135
Handler总结和补充:https://w独立进程ww.jianshu.com/p/a041c41af27d

目录

image

前言

下面这篇是读过的最好的关于binder和aidl的blog。
Android:远程服务Service(含AIDL & IPC讲解) https://www.jianshu.com/p/34326751b2c6
图文详解 Android Binder跨进程通信的原理:https://www.jianshu.com/p/4ee3fd07da14.
重点是aidl的使用blog,binder仅仅为了更好的理解aidl.
下文是对上面blog的一些补充.

1 什么是binder

1.1 定义和作用
Binder是一套实现进程通信的系统,它自己通过一层一层的调用实现,参见文末附录。binder是client-server结构,给应用层client,server两个进程提供了注册,发送和接收的接口.
binder系统内部通过优化的共享内存机制,实现了发送和接收,对应用层透明。实际应用中,通常使用基于binder实现的aidl进行进程通信,所以binder接口通常对用户也是透明.
1.2 Binder跨进程原理
对于进程之间来说,用户空间的数据不可共享,内核空间的数据可共享.所以跨进程通信原理,是在内核空间进行数据交换.
内核内存是所有进程共享的,不区分进程,所以不存在某个进程自己的内核内存.
内核内存由内核页表管理,内核页表保存在内核的mm_struct中.所有进程的内核页表是一样的,进程页表是不一样的.

2 Binder 模块

Binder采用cs结构.


0?wx_fmt=png

0?wx_fmt=png
角色 作用 备注
Service manager 独立进程.主要功能有两个一个是提供服务注册功能(addservice),一个是提供服务检索功能(getservice) 类似dns.
binder 通过它就可以在两个进程之间路由转发数据了 类似dns之上的路由器.server的service向service manager 注册获得binder, 所以binder属于server
Server&Client

3 使用binder实现通信

这节代码是为了将binder机制将清楚,实际应用层通常并不直接使用binder接口函数.而是使用基于binder实现的aidl,即第5节的内容。
binder原理参见https://www.jianshu.com/p/4ee3fd07da14,本节是binder的实现.
上面blog的代码分析有些复杂,需要先看下面的例子之后,再看上面blog的代码分析.

image

实现binder一共需要2步.
3.1 server 创建binder&在onTransact中实现service 函数

public class GameService extends Service {
    private Binder mBinder = new Binder() {
    };
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
private Binder mBinder = new Binder() {
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    if (code ==1 ) {
      String _arg0;
      _arg0 = data.readString();
      int _result = getGamePrice(_arg0);
      reply.writeInt(_result);
    }
    ......//other case
}
public int getGamePrice(String name) {
      int price = -1;
      if ("逃生2".equals(name)) {
          price = 88;
       } else if ("饥荒".equals(name)) {
          price = 24;
      }
          return price;
    }
};

在Androidmanifest.xml 中添加service,Service manager管理Androidmanifest.xml 中的service。

        <service
            android:name="com.smartwork.bindertest.GameService"
            android:process=":remote">
            <intent-filter>
                <action android:name="android.intent.action.bind.gameservice" />
            </intent-filter>
        </service>

3.2 client bindService & 调用server service 函数

  1. bindService: 客户端想和服务端通信,通过Service Manager查找到服务端的Binder,通过callback函数返回.
    String action = "android.intent.action.bind.gameservice";
    Intent intent = new Intent(action);
    bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    private IBinder mRemote = null;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mRemote = service;
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mRemote = null;
        }
    };
  1. client 调用server 函数,或者说通过transact向server发送数据
    客户端通过调用transact()方法,将要请求的内容发送到服务段,通过code(1)区分不同server 函数。
    private int getPrice(String name) throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int _result;
        try {
            mRemote.transact(1, _data, _reply, 0);
            _result = _reply.readInt();
        }  finally {......        
        }
        return _result;
    }

小结:server: 新建service,在service中创建binder,在service中实现业务逻辑函数;将service 添加到Androidmanifest.xml.Service manager start service.
client: bindService 查询Service manager获取binder;通过transact发送,server通过onTransact接收.

4 binder与共享内存的区别

image

linux的进程通信机制有管道,消息队列,共享内存,套接字。binder是andrid特有的进程通信机制.它是对共享内存做的改进.

  1. 效率:消息队列、Socket和管道,需要两次内核拷贝.Binder需要一次。使用copy_from_user将data写到内核.
    copy_from_user是用户态内存拷贝到内核态内存.mmap不需要拷贝,用户态进程可以直接读写内核内存.
    两个进程都使用mmap就是共享内存。一个使用copy_from_user,一个使用mmap就是binder,这样区分开了client和server.
  2. 稳定性:上面说到共享内存的性能优于Binder,那为什么不采用共享内存呢?因为共享内存需要处理并发同步问题,容易出现死锁和资源竞争,稳定性较差。Binder基于C/S架构 ,Server端与Client端相对独立,稳定性较好。
    共享内存是需要同步的,binder是cs结构不需要考虑共享内存的同步问题,client write之后read阻塞等待结果.
  3. 安全性:传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Binder机制为每个进程分配了UID/PID,且在Binder通信时会根据UID/PID进行有效性检测.

5 Aidl

QA: binder与aidl的关系 ?
aidl的底层是用binder实现的.有binder 跨进程通信,为什么还用aidl呢?因为aidl对binder做了封装,使用方便。
5.1 aidl的原理:只要按照规范写一个.aidl文件,编译之后自动创建一个与aidl同名的.java文件,里面已经帮我们自动写好一堆东东,这些标准化的东西,用模板自动生成即可,让开发者尽量关注功能实现上.
真是实现通信的是aidl编译之后,自动生成的java文件.java文件就是自动写好的binder使用框架.
aidl一定记住一点:aidl编译出来的stub就是binder(实际是binder的子类,proxy是stub的内部类)
5.2 aidl 结构图
代理模式示意图如下,aidl就属于代理模式.

image

aidl示意图如下,aidl就是统一接口,stubproxy 是proxy,stub是subjecImpl. binder没有统一接口.

image

image

5.3 aidl使用
整体过程:aidl定义并编译生成文件,Server service 注册,Server service的binder类实现接口函数(通常用匿名了实现),client bindService,client 调用接口.
注意:aidl接口实现是在service的binder类中实现的,不是service中.较少在service实现,然后使用binder调用service再调用service的业务逻辑函数.
Android:远程服务Service(含AIDL & IPC讲解)https://www.jianshu.com/p/34326751b2c6.这篇blog已经将的很好了
1) 定义aidl
与java接口的定义很类似.比如:

interface MyAidl{    
    int getId();  
    void setId(int id);  
  }  
  1. server实现被调用的Remote Service(提供可实例化的Stub对象)
public class TaskService extends Service {
    ...... 
    private finalITaskService.Stub mTaskServiceBinder =new ITaskService.Stub() { 
       public int getPid() {
           return Process.myPid();
       }
    };

在AndroidManifest.xml文件里将Service声明出来,让系统里其他部分可以调用到.这个就是向service Manager注册binder(binder在service中).

<application
…
    <service android:name=".TaskService">
    <intent-filter>
    <action android:name="org.lianlab.services.ITaskService"/>
    </intent-filter>
    </service>
</application>
  1. client bind Service&调用Remote Service
    bindService的回调mTaskConnection获取stub.proxy. mTaskService.getPid的本质是stub.proxy通过binder 的transact发送,server 通过onTransact接收.
bindService(new Intent(ITaskService.class.getName()),mTaskConnection,
                    Context.BIND_AUTO_CREATE);
mPid = mTaskService.getPid();  

5.4 aidl生成的stub 类(java binder 类)解析

2

aidl结构图1

aidl使用流程示意图:
call ladder:bindService获取iBinder(server onBind()返回)---stub.asinterface由iBinder获取stub.proxy---调用binder中的实现函数(底层bindler机制是,调用核心函数transact()发送,然后onTransact接收).
image

这个blog:https://www.jianshu.com/p/375e3873b1f4的 ”IMyAidlInterface .java类分析“部分,对aidl生成的stub类做了解析,比如:asinterface就是获取stub.proxy。
stub 类生成和作用:stub类是编译aidl自动生成的,既作为服务器端接口也作为Binder驱动给客户端使用

角色 作用 备注
BookManager.Stub server继承stub,实现业务逻辑函数 binder
BookManager.Stub.Proxy 给client提供的binder接口 binderproxy. proxy 是stub的内部类.

binderProxy.BookManager.Stub.Proxy =BookManager.Stub
(代理-桩的设计理念),前者放在client,后者在server客户端最终通过这个类与服务端进行通信 |

image

**小结:
image

service,bindler,aidl什么关系?
server service仅仅用于注册,是server对外接口. service中创建binder,在binder中实现aidl中定义(或者server定义)的业务逻辑函数函数.
真正跨进程send/receive的是binder,实现函数也是在binder中,不是service.
aidl等于定义binder的接口,自动生成binder class。
附录: binder协议实现client使用stub.proxy,客户端接口会获得Binder驱动,调用其transact()发送消息至服务器.
server会接收Binder驱动发送的消息,收到消息后会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码.
这节可有可无,binder实现有一套自己的协议,不需要知道具体内容,不需要重复造轮子。完全是为了满足读者的好奇心。
image

总结: 本文主要是对开篇的binder blog补充了,设计和实现。对aidl blog补充了源码分析。使读者了解binder和aidl更容易和全面一些.
aidl的使用最主要.aidl的本质是自动生成stub即binder类的使用。
binder和service是绑定的,binder对象是server service类的一个成员变量。注册service就是注册binder.
binder原理是优化的共享内存。
binder使用transact,onTransact 发送和接收.
伪代码:
client: stub.proxy是binderProxy
binderProxy.transact(sendmsg,parm1,parm2...);//发送
server:stub:
onTransact //接收
case sendmsg //不同函数
sendmsg(parm1,parm2...);//调用真正server service的实现。
附录:Android跨进程通信IPC之11——AIDL https://www.jianshu.com/p/375e3873b1f4
Android跨进程通信IPC之6——Binder框架:https://www.jianshu.com/p/b4a8be5c6300

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341