关于Android中的BInder机制的笔记

1.binder是什么

binder英文意思理解为胶水,它是实现IPC通讯的一种方式,是Android 系统中实现进程中通讯的主要方式。我们都知道Android 系统都是基于Linux架构的,为什么不能使用Linux中的进程通讯方式呢?我们都知道,Android系统和Linux系统不同的是,Android系统有很多应用需要管理,每一个应用都跑在属于自己的进程中,首先要考虑安全问题,如果使用像Linux系统中的内存共享,管道之类的实现进程中通讯的方式,那么每个应用以及系统之间的服务的安全得不到保证。而Socket这种方式实现的效率太低,只适合网络通讯。那么为了解决Android 系统的这种特有的需求,Android 系统架构师肯定会想,我可不可以做一个可以保证进程间通讯安全,又能像socket这样方便的东西呢?Binder机制就这么诞生了,在Android 系统中,Binder有一个特有的驱动程序,虽然它没有硬件设备,但它和其它硬件模块一样不可缺少,它类似于整个系统的路由器,它为系统中的每个服务都绑定了一个固定的Ip,如果你想要实现进程中通讯,比如你想要调取摄像头的服务,那么你只要指定摄像头的服务,然后将信息通过binder发给ManagerService,ManagerService帮你找到摄像头的服务,然后帮你的进程和摄像头服务的进程建立连接。当然,在你调用服务的时候,Android系统会审核这个进程是否有调用摄像头权限,这些审核机制应该在调用服务之前就已经完成,Binder只负责实现通讯。如此可以看出来,Binder就像胶水一样,把每个应用都通过它粘连起来。

2.如何实现Binder通讯,

Android 在使用Binder进行通讯的时候,定义了一套规则,俗称AIDL,全称Android Interface definition language,即Android接口定义语言,看名称就明白,如果你要使用这个东西,那么你必须按照它的规则来实现。下面是一个实现的例子。简单实现了一个图书管理的客户端和服务端的通讯,在一个服务进程中管理书籍,而在另外一个进程中去获得这些书籍的信息。定义一个Book类,固定实现Pacerlable接口,我们都知道Pacerlable是Andriod实现序列化的一个接口,在AIDL中,有特定的几种类型可以传输,比如Int,String,Float之类的,除此之外,如果你想要传一个别的对象,那么必须要实现Pacerlable方法。如下面的代码

package com.example.weizhang.myaidltest;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Administrator on 2017/12/3 0003.
 */

public class Book implements Parcelable {
    private String name;
    private int price;

    public Book(String name, int price) {
        this.name = name;
        this.price = price;
    }
    public Book() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeInt(this.price);
    }

    protected Book(Parcel in) {
        this.name = in.readString();
        this.price = in.readInt();
    }

    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel source) {
            return new Book(source);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };
}
实现完这个以后,接下来要在项目中建立一个aidl的文件夹,文件夹位置和java同级。在AS中可以点击app,然后选择aidl,项目会自动生成一个aidl文件夹

,然后在这个文件夹中建立以下两个文件。一个是Book类的申明,一个是实际的接口,其实第一个申明是为了第二个接口调用做的申明。

// IBookManerger.aidl
package com.example.weizhang.myaidltest;

// Declare any non-default types here with import statements

parcelable Book;

// IBookManerger.aidl
package com.example.weizhang.myaidltest;
import com.example.weizhang.myaidltest.Book;
interface IBookManerger {

  //所有的返回值前都不需要加任何东西,不管是什么数据类型
     List<Book> getBooks();

     //传参时除了Java基本类型以及String,CharSequence之外的类型
     //都需要在前面加上定向tag,具体加什么量需而定
     void addBook(in Book book);

}

点击Rebuild,系统中的脚本会为我们在gen目录下的生成一个java文件,名称即为我们在aidl中命名的文件

我们来看一下这个类,在看这个类之前,先想一下这个类应该要实现什么功能,首先,要想实现进程中通讯,我们要把自己的一些信息先注册给serviceManerger,然后客户端才能调用到这个接口,而之前已经说过了,Android中实现进程中通讯,使用的是BInder,那么为了实现注册,我们必须要使用Binder。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\AndroidDemo\\app\\src\\main\\aidl\\com\\example\\weizhang\\myaidltest\\IBookManerger.aidl
 */
package com.example.weizhang.myaidltest;

public interface IBookManerger extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.weizhang.myaidltest.IBookManerger {
        private static final java.lang.String DESCRIPTOR = "com.example.weizhang.myaidltest.IBookManerger";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.weizhang.myaidltest.IBookManerger interface,
         * generating a proxy if needed.
         */
        public static com.example.weizhang.myaidltest.IBookManerger asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.weizhang.myaidltest.IBookManerger))) {
                return ((com.example.weizhang.myaidltest.IBookManerger) iin);
            }
            return new com.example.weizhang.myaidltest.IBookManerger.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @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_getBooks: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.example.weizhang.myaidltest.Book> _result = this.getBooks();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    com.example.weizhang.myaidltest.Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.example.weizhang.myaidltest.Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.weizhang.myaidltest.IBookManerger {
            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 java.util.List<com.example.weizhang.myaidltest.Book> getBooks() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.example.weizhang.myaidltest.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.weizhang.myaidltest.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定

            @Override
            public void addBook(com.example.weizhang.myaidltest.Book book) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
//所有的返回值前都不需要加任何东西,不管是什么数据类型

    public java.util.List<com.example.weizhang.myaidltest.Book> getBooks() throws android.os.RemoteException;
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定

    public void addBook(com.example.weizhang.myaidltest.Book book) throws android.os.RemoteException;
}

可以看到,manerger里面有个子类stub,stub中又有一个私有的子类proxy。要想理解这个结构,我们必须要明白设计模式中的一个模式,代理模式。stub和Proxy都实现了同一个接口,proxy是stub的代理。我们可以看到,Proxy持有了一个Binder对象,即
private android.os.IBinder mRemote;
这个对象包含了各种信息,通过将这个Binder发送给ServiceManerger就实现了服务的注册。我们来看一下Service中是如何将Binder发送出去的。

package com.example.weizhang.myaidltest;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

/**
 * 服务端的AIDLService.java
 * <p/>
 */
public class AIDLService extends Service {

    public final String TAG = this.getClass().getSimpleName();

    //包含Book对象的list
    private List<Book> mBooks = new ArrayList<>();

    //AIDL文件生成的IBookManerger
    private final IBookManerger.Stub mIBookManerger = new IBookManerger.Stub() {
        @Override
        public List<Book> getBooks() throws RemoteException {
            synchronized (this) {
                Log.e(TAG, "invoking getBooks() method , now the list is : " + mBooks.toString());
                if (mBooks != null) {
                    return mBooks;
                }
                return new ArrayList<>();
            }
        }



        @Override
        public void addBook(Book book) throws RemoteException {
            synchronized (this) {
                if (mBooks == null) {
                    mBooks = new ArrayList<>();
                }
                if (book == null) {
                    Log.e(TAG, "Book is null in In");
                    book = new Book();
                }
                //尝试修改book的参数,主要是为了观察其到客户端的反馈
                book.setPrice(2333);
                if (!mBooks.contains(book)) {
                    mBooks.add(book);
                }
                //打印mBooks列表,观察客户端传过来的值
                Log.e(TAG, "invoking addBooks() method , now the list is : " + mBooks.toString());
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Book book = new Book();
        book.setName("Android开发艺术探索");
        book.setPrice(28);
        mBooks.add(book);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString()));
        return mIBookManerger;
    }
}

可以看到,其实就是创建一个继承stub的对象,然后在Onbind方法中,将这个对象抛出去,那么在客户端就可以拿到这个binder,然后调用这个接口的函数了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值