android IPC 进程间通信 Binder AIDL

作者: 品味与回味 | 来源:发表于2017-11-20 15:34 被阅读99次

    只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL”,其他情况下你都可以选择其他方法,如使用Messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的。而Messager是单线程处理。 这就明白了 为什么要有aidl

    线程
    进程
    关系
    线程 是CPU 调度最小单位
    进程指的是一个执行单元,如程序或者一个应用

    首先开启多进程 就相当于多开了一个应用
    先来想想带来的不良影响
    1 静态成员和单例模式完全失效
    2 线程同步机制完全失效
    3 sharepreference的可靠性下降
    4 Application会多次被创建

    下面来一些基础介绍
    1 Serializable接口
    这是java提供的一个序列化接口
    如何进行序列化和反序列化呢


    image.png

    android的序列化方式
    Parcelable
    他也是一个接口 只要是实现这个接口 一个类的对象就可以实现序列化并可以通过Intent和Binder传递


    image.png image.png image.png

    Binder 是android中的一个类 他实现了Ibinder接口 从IPC 角度来说 binder 是android中的一种跨进程通信方式

    想要了解 binder 在来了解一个知识点


    image.png

    内核层:Linux 内核和各类硬件设备的驱动,这里需要注意的是,Binder IPC 驱动也是在这一层实现,比较特殊
    硬件抽象层:封装「内核层」硬件驱动,提供可供「系统服务层」调用的统一硬件接口
    系统服务层:提供核心服务,并且提供可供「应用程序框架层」调用的接口
    Binder IPC 层:作为「系统服务层」与「应用程序框架层」的 IPC 桥梁,互相传递接口调用的数据,实现跨进层的通讯
    应用程序框架层:这一层可以理解为 Android SDK,提供四大组件,View 绘制体系等平时开发中用到的基础部件

    一个IPC通讯我们可以简单理解成客户端-服务器模式,客户端请求服务,服务端接收到客户端请求后处理相应,或可能带回结果返回给客户端。binder机制在android系统的进程间通讯模型总结如下:
    (1)客户端通过某种方式得到服务器端的代理对象。从客户端角度看来代理对象和他的本地对象没有什么差别。它可以像其他本地对象一样调用其方法,访问其变量。
    (2)客户端通过调用代理对象的方法向服务器端发送请求信息。
    (3)代理对象通过binder设备节点(/dev/binder),把用户请求信息发送到Linux内核空间(实际上是内存共享),由Binder驱动获取并发送到服务进程。
    (4)服务进程处理用户请求,并通过Linux内核的Binder驱动返回处理结果给客户端的代理对象。
    (5)客户端收到服务端的返回结果。
    整个过程大致如上所述,可以想象一下bingder机制的引入,给进程间的通讯带来什么好处?没错,就是“线程迁移”,就像是一个线程带着参数,进入另一个进程执行,然后带着结果返回,和调用自己的函数一样的效果。

    上面都是一些概念
    看的我也是 晕头转向

    image.png image.png image.png

    看到这里大家有没有晕头转向的感觉 这到底是干嘛的?

    image.png

    完全不懂啊

    ipc binder aidl 这是干啥的 我们开发到底用的到吗? 完全不清楚啊

    下面我们来 讨论几点
    当我们做一款 音频软件的时候!当播放某一个音乐的时候。我们在干别的时候(这款软件的其他功能)会不会影响到播放呢? 答案是不会的。所以这个播放软件的功能要放在一个新的进程中。 这样就不会有相互的影响。但是这个和我们上面说的有什么关系吗? 哇卡卡。 注意到了吗 这个就是两个不同的进程通信。 剩下的我们来慢慢分析。


    image.png

    我们写的app。有的时候会和系统的某些功能区交互。比如获取手机号。uuid。等。 app是一个新的app ,我们就需要用ipc 进程间通信。 盗图一张

    image.png

    每一个系统功能都有一个与之对象manager。

    下面看binder 又盗图一张


    image.png

    Binder IPC 属于 C/S 结构,Client 部分是用户代码,用户代码最终会调用 Binder Driver 的 transact 接口,Binder Driver 会调用 Server,这里的 Server 与 service 不同,可以理解为 Service 中 onBind 返回的 Binder 对象,请注意区分下。

    Client:用户需要实现的代码,如 AIDL 自动生成的接口类
    Binder Driver:在内核层实现的 Driver
    Server:这个 Server 就是 Service 中 onBind 返回的 IBinder 对象
    最后一句话怎么理解? 就是我们自己写服务的时候那个方法的返回值

    http://www.jianshu.com/p/bdef9e3178c9 这是调用地址。 有很多概念 很棒

    顺势我在粘过来几个

    IReporter.aidl

    package com.android.binder;

    interface IReporter {

    int report(String values, int type);
    

    }
    Server

    AidlService.java

    public class AidlService extends Service {

    public static final class Reporter extends IReporter.Stub {
    
        @Override
        public int report(String values, int type) throws RemoteException {
            return type;
        }
    }
    
    private Reporter mReporter;
    
    public AidlService() {
        mReporter = new Reporter();
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return mReporter;
    }
    

    }
    这里与手动实现的方式不同的是,一个继承了 Binder,一个继承了 AIDL 自动生成的 Stub 对象,它是什么呢?我们可以看下它的定义
    ...

    IReporter.java

    public interface IReporter extends android.os.IInterface
    {

    public static abstract class Stub extends android.os.Binder implements com.android.binder.IReporter {
        ...
    
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            switch (code)
            {
                case INTERFACE_TRANSACTION:
                {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_report:
                {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.report(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
    }
    

    ...

    }
    其实和我们上文的写法是一样的,自动生成的 IReporter 类自动给我们处理了一些参数的组包和解包而已,在 case 语句中调用了 this.report 即可调用到自己的业务逻辑部分了。

    Client

    MainActivity.java

    private IReporter mReporterAidl;

    private class AidlConnection implements ServiceConnection {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mReporterAidl = IReporter.Stub.asInterface(service);
    }
    
    @Override
    public void onServiceDisconnected(ComponentName name) {
        mReporterAidl = null;
    }
    

    }

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {

    ...
    
    Intent intent = new Intent(this, AidlService.class);
    bindService(intent, new AidlConnection(), BIND_AUTO_CREATE);
    

    }

    这里与手动实现方式也有区别,即调用了 Stub 对象的 asInterface,具体做了什么呢?

    public static com.android.binder.IReporter asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.android.binder.IReporter))) {
    return ((com.android.binder.IReporter)iin);
    }
    return new com.android.binder.IReporter.Stub.Proxy(obj);
    }
    先查找本地接口是否存在,判断是否是本地调用,如果是则直接返回 IReporter 的对象,否则返回 Stub.Proxy 对象,这个 Proxy 对象是做什么的呢?

    private static class Proxy implements com.android.binder.IReporter
    {
    private android.os.IBinder mRemote;
    Proxy(android.os.IBinder remote)
    {
    mRemote = remote;
    }
    @Override public android.os.IBinder asBinder()
    {
    return mRemote;
    }
    public java.lang.String getInterfaceDescriptor()
    {
    return DESCRIPTOR;
    }
    @Override public int report(java.lang.String values, int type) throws android.os.RemoteException
    {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    int _result;
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    _data.writeString(values);
    _data.writeInt(type);
    mRemote.transact(Stub.TRANSACTION_report, _data, _reply, 0);
    _reply.readException();
    _result = _reply.readInt();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    return _result;
    }
    }
    ...
    基本上已经很明了了,就是一个代理对象,对调用接口参数做组包而已,然后调用了 mRemote.transact 接口,和上文手动实现的方式是一致的。

    相关文章

      网友评论

        本文标题:android IPC 进程间通信 Binder AIDL

        本文链接:https://www.haomeiwen.com/subject/haqzmxtx.html