Android -- Binder 机制,AIDL

Binder

名词:

IPC:进程间通信
UID:User ID,每一个程序仅有一个ID
PID:Process ID,进程ID
PPID:当前进程父进程ID
Server:提供服务:由于服务端的方法在服务端的Binder线程池中运行
Clint:获取服务
ServiceManager:帮助系统维护更多的Service列表

扩展

IPC:管道pipe,有名管道FIFO,MessageQueue,共享存储,Socket,Binder
https://blog.csdn.net/weixin_42197191/article/details/82867154?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

什么时候用到多进程(跨进程调用)

WebView,加载图片,推送,app调用外部服务(电话服务,闹钟服务)

为什么用多进程

app运行内存由系统分配给虚拟机,基本上都是32M,48M, 64M。
所以加载图片,网络放到别的进程,
其他进程崩溃不会影响到主进程
进程之间内存不共享,不能直接通信

android为什么用binder

基于linux底层实现的,只复制一次,

  1. Binder机制的核心是在客户端Client创建一个代理,在服务端Server创建一个存根,通过代理和存根之间的调用来完成进程间的数据交换
  2. Binder是Android系统中的一种IPC进程间通信结构。
  3. Binder的整个设计是C/S结构客户端进程通过获取服务端进程的代理,并通过向这个代理接口方法中读写数据来完成进程间的数据通信

4个方面的原因
1.安全:每个进程都会被Android系统分配UID(User ID 系统自动发放)和PID(进程ID),不像传统的在数据里加入UID,这就让那些恶意进程无法直接和其他进程通信,进程间通信的安全性得到提升。
2.高效:像Socket之类的IPC每次数据拷贝都需要2次,而Binder只要1次,在手机这种资源紧张的情况下很重要。
3.稳定性:Server端与Client端相对独立稳定性较好而共享内存实现方式复杂, 需要充分考虑到访问临界资源的并发同步问题,否则可能会出现死锁等问题

  1. 面试要回答进程间的通信,C/S架构,安全,UID/PID,代理接口方法,在serviceManager中注册了,只copy一次
    在这里插入图片描述

binder通信概述:
1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;
2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
4.代理接口将该Parcel发送给内核中的binder driver.
5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。
在这里插入图片描述
Service Manager
任何service在被使用之前,均要向SM(Service Manager)注册,同时客户端需要访问某个service时,应该首先向SM查询是否存在该服务。如果SM存在这个service,那么会将该service的handle返回给client,handle是每个service的唯一标识符。
在这里插入图片描述

Messager.send 发送消息,服务端可以通过handler的handleMessage处理消息
send(msg)前通过msg.replyTo = mMessenger将自己的信使设置到消息中,这样服务端接收到消息时同时也得到了客户端的信使对象了,然后服务端可以通过
//得到客户端的信使对象,并向它发送消息
cMessenger = msg.replyTo;
cMessenger.send(message);

AIDL

  1. 基础
    通过Binder通信需要按照binder的规矩去通信,代码实现起来比较复杂,AIDL已经帮我们实现了这个代码。实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信。实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信。
    基本数据类型(short 除外)、String、charSequehce、List(元素得序列化)、Map(元素得序列化)、parcelable。
    aidl方法传入自定义类对象,in、out、inout必须写(aidl默认支持的类型不用写,默认且只能是in),否则报错。

BroadcastReceiver 占用的系统资源比较多
Messenger 进行跨进程通信时请求队列是同步进行的,无法并发执行
2. 怎么实现

  • 先建立一个AIDL接口(只写方法,不能声明静态成员),自动生成java接口文件
  • 建立服务类,service子类,
  • 实现由aidl生成的java接口
  • 在AndroidManifest中配置AIDL服务,标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值。

概念:
远程服务:运行在其他应用里面的服务
本地服务:运行在自己应用里面的服务
进程间通信 IPC
AIDL即 本地访问远程服务

客户端和服务器都需要有相同的aidl文件,
在gradle文件中配置,识别出java包以外的java文件
有其他自定义的属性要在建立aidl并把相关的java文件放在aidl下
自定义的属性客户端要实现Parcelable接口
客户端开启服务端服务,

  private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.vvvv.aidl");
intent.setPackage("com.iiiv.aidlserver");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
 }

客户端使用ServiceConnection 接口 ,实现onServiceConnection和onServiceDisconnection方法,具体如下

 public void onServiceConnected(ComponentName name, IBinder service) {
        Log.e(getLocalClassName(), "service connected");
        //IBinder对象转化为aidl接口对象,IBinder就是服务器端onBinder时回传的Binder
        //通过.Stub.asInterface(传来的IBander)
        messageCenter = MessageCenter.Stub.asInterface(service);
        mBound = true;

        if (messageCenter != null) {
            try {
            //调用aidl接口的方法,给
                mInfoList = messageCenter.getInfo();
                Log.e(getLocalClassName(), mInfoList.toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

服务器端:
实现aidl接口.Stub,重写方法

     private final MessageCenter.Stub messageCenter = new MessageCenter.Stub(){
       @Override
    public List<Info> getInfo() throws RemoteException {
        synchronized (this){
            if(messages != null ){
                return messages;
            }
            return new ArrayList<>();
        }
    }

    @Override
    public void addInfo(Info info) throws RemoteException {
        synchronized (this){
            if(messages == null){
                messages = new ArrayList<>();
            }
            if(info == null){
                info = new Info();
            }
            if(!messages.contains(info)){
                messages.add(info);
            }
            Log.e("wuzhen", "客户传来了数据" + messages.toString());
        }
    }
};
//这里返回值给客户端,返回值是上面的名字
public IBinder onBind(Intent intent) {
    return messageCenter;
}

aidl文件
//所有的返回值前都不需要加任何东西,不管是什么数据类型
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定

AIDL 的编写主要为以下三部分:

  1. 创建 AIDL
    创建要操作的实体类,实现 Parcelable 接口,以便序列化/反序列化
    新建 aidl 文件夹,在其中创建接口 aidl 文件以及实体类的映射 aidl 文件
    Make project ,生成 Binder 的 Java 文件
  2. 服务端
    创建 Service,在其中创建上面生成的 Binder 对象实例,实现接口定义的方法
    在 onBind() 中返回
  3. 客户端
    实现 ServiceConnection 接口,在其中拿到 AIDL 类
    bindService()
    调用 AIDL 类中定义好的操作请求

• Android提供了一个 AIDL (Android接口定义语言)工具来处理序列化和通信。这种情况下Service需要以aidl文件的方式提供服务接口,AIDL工具将生成一个相应的java接口,并且在生成的服务接口中包含一个功能调用的stub服务桩类。Service的实现类需要去继承这个 stub服务桩类。Service的onBind方法会返回实现类的对象,之后就可以使用它来进行通信了。

1.创建AIDL文件,接口方法
2.对象序列化
3.服务端写好,直接复制到客户端,AIDL文件,对象文件复制过来,包名不能变

①Client–》②bindservice–》③service返回IBinder–》④Client拿到IBinder对象可以像同进程一样调用

方法流程

④Client拿到IBinder对象可以像同进程一样调用:AIDL自动生成java文件,能够拿到,
aidl.java文件:
数据:Client --> Service用Proxy 发送 进站口
Service --> Client 用Stub 接受 出站口
客户端调用方法–》mRemote.transact()–》Binder
Binder–》onTransact–》this.相同的方法–》实现类去具体实现方法
在这里插入图片描述

binderServer怎么返回的IBinder

mbase.bindService 也就是 ContexImpl.bindService–bindServiceCommon

MS–AMS
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值