美文网首页
[Android]Binder跨进程通信理解

[Android]Binder跨进程通信理解

作者: 黑森林中的小木屋 | 来源:发表于2018-09-26 10:14 被阅读0次

    建议在看本文之前,先阅读文章Binder学习指南

    注:本文是在阅读上面文章后自己理解整理。以下内容皆为本人理解,不保证全部正确,请酌情参考

    本文是不借助AIDL,自己手写的的跨进程通信模型
    先上代码:

    import android.os.*;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.util.Log;
    
    public class Library extends Binder implements IBookManager {
        public static  String des = "a453826252.github.intercom.util.binder.Library";
        public Library(){
            this.attachInterface(this,des);//将自己注册到SM中
        }
    
        //执行在binder实体中
        @Override
        protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
    
            try {
                Thread.sleep(500);//验证client端在执行过程中会被吊起
            }catch (Exception e){
    
            }
            Book book = Book.CREATOR.createFromParcel(data); //接收client端传入的参数
           String msg = addBook(book);//调用本地方法
           reply.writeString(msg); //写入返回值
           reply.writeNoException();
    
           return true;
        }
    
    
    
        public static class StubBinder{
            public static IBookManager asInterface(IBinder iBinder){
                if(iBinder == null){
                    return null;
                }
                IInterface iInterface = iBinder.queryLocalInterface(des);//根据des在SM中查找服务是否在client进程
                if(iInterface != null && iInterface instanceof Library){
                    return  (Library)iInterface;
                }
                //服务不在client进程中,IBinder对象为远端对象
                return new StubBinderProxy(iBinder);
    
            }
    
            public static class StubBinderProxy implements IBookManager{
                IBinder mRemote;
                public StubBinderProxy(IBinder iBinder){
                    mRemote = iBinder; //代码能到这,说明肯定IBinder是远端对象
                }
                //运行在client端进程中,包装参数用的方法(可以理解为仓库的入口)
                @Override
                public String addBook(Book book) {
    
                    Parcel data = Parcel.obtain();
                    book.writeToParcel(data,0);
                    Parcel reply = Parcel.obtain();
                    //data.writeInterfaceToken(des);
                    try {
                        long currentTime = System.currentTimeMillis();
                        mRemote.transact(0,data,reply,0);//通过Binder驱动调用server进程中的Binder实体(远端对象)
                        Log.i("binderBook","take:"+(System.currentTimeMillis()-currentTime)+"mm");
                       return reply.readString(); //读取返回值
                    } catch (Exception e) {
                        e.printStackTrace();
                        return "sorry,i don't know";
                    }finally {
                        reply.recycle();
                        data.recycle();
                    }
                }
    
                @Override
                public IBinder asBinder() {
                    return mRemote;
                }
            }
        }
    
        @Override
        public IBinder asBinder() {
            return this;
        }
        
      //在server端进程中,真正提供功能的方法(可以理解为仓库)
        @Override
        public String addBook(Book book) {
            Log.i("binderBook",book.title+"|"+book.author);
            Log.i("binderBook","addBookID:"+android.os.Process.myPid( ));
            return "i have received";
        }
    }
    
    import android.os.IInterface;
    
    public interface IBookManager extends IInterface{
        String addBook(Book book);
    }
    

    IBookManager为一个接口,继承自IInterface,声明服务端可以对外提供什么功能,本例中,只向外提供一个addBook的功能(方法)

    调用流程

    1、在构造函数中向SM(ServerManager)注册,便于client端查找
    2、client端拿到对象后需要调用asInterface()方法确定该对象为实体对象还是代理对象
    3、执行对象提供的addBook()方法,获取返回值

    上面第二步的代码为:
    ServiceConnection connection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    IBookManager bookManager  = Library.StubBinder.asInterface(service);//确定对象为实体对象还是代理对象
                    String msg = bookManager.addBook(new Book("title","auth"));//执行方法获取返回值
                    Log.i("binderBook",String.valueOf(msg));
                }
    
                @Override
                public void onServiceDisconnected(ComponentName name) {
    
                }
            };
    

    services代码(不是Server代码)

    public class RemoteService extends Service {
    
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            return new Library();
        }
    }
    
    第二、三步中,具体的调用流程是:

    1、调用asInterface(),根据标识符(des)查询Binder实体(服务对象)是否在本进程中,如果是,直接返回Binder实体,如果不是,则新建一个Binder代理对象。因为Binder代理对象也实现了IBookManager接口,因此,代理对象中也有一个addBook()方法,但是这个方法中只是将参数包装、序列化之后调用远端Binder实体的onTransact()方法。当调用mRemote.transact(0,data,reply,0)时,就已经在远端进程执行了,此时,client进程被挂起,直到远端执行完毕

    2、onTransact()方法根据code参数确定要调用哪个方法(因为我就一个方法,就没有判断),然后从data中获取参数,调用方法,将结果写入reply中,返回。

    3、回到client进程继续执行代码

    Log.i("binderBook","take:"+(System.currentTimeMillis()-currentTime)+"mm");
     return reply.readString(); //读取返回值
    

    4、调用结束,结果为:


    image.png

    相关文章

      网友评论

          本文标题:[Android]Binder跨进程通信理解

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