Android IPC机制——Binder详解

IPC是指Android中的进程间通信,即在不同进程之间传递消息数据,Android中可实现进程通信的方法有很多,比如Intent、ContentProvider、Messenger、Binder、Socket或是利用文件,这些方式各有千秋,都有最适合使用的场景,这次要介绍的是一种安全高效的面向对象式的IPC实现——Binder。

当使用bindService()绑定一个服务时,service会在其onBind()方法中返回一个Binder对象,然后在client的ServiceConnection中获取这个Binder,即可跨进程使用service的方法,接下来我们就来看一看Binder的实现原理。

在Android中,实现Binder很简单,不需要我们去写,只需要写一个aidl文件,在其中写一个接口,声明需要的方法,其他的工作通过编译之后系统会为我们完成,最后生成java文件。Android为我们提供了这这种简单的Binder使用方式,虽然简化了开发,但也一定程度的限制了我们对其工作原理的深入理解,下面就以系统生成的Binder类来讲解一下Binder构造。

本文会分四个个部分来分析Binder:

1.Binder的组成结构
2.Binder的使用方法
3.Binder对象的传递流程
4.Binder对client请求的处理过程


Aidl生成Binder类

首先,创建一个aidl文件,如下:

package com.ipctest.aidl;

interface IUser {
   boolean login(String userName,String userPwd);
   void logout(String userName);
}

然后编译工程,在AndroidStudio的目录结构下,生成的.java文件在build–generated–source–aidl–debug目录下,我得到的文件经过格式整理如下:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: 
 */
package com.ipctest.aidl;
// Declare any non-default types here with import statements

public interface IUser extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.ipctest.aidl.IUser{

        private static final java.lang.String DESCRIPTOR = "com.ipctest.aidl.IUser";

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

        /**

         * Cast an IBinder object into an com.ipctest.aidl.IUser interface,
         * generating a proxy if needed.
         */
        public static com.ipctest.aidl.IUser asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.ipctest.aidl.IUser))) {
                return ((com.ipctest.aidl.IUser)iin);
            }
            return new com.ipctest.aidl.IUser.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_login:
                {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    boolean _result = this.login(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(((_result)?(1):(0)));
                    return true;
                }
                case TRANSACTION_logout:
                {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.logout(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.ipctest.aidl.IUser{
            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 boolean login(java.lang.String userName, java.lang.String userPwd) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(userName);
                    _data.writeString(userPwd);
                    mRemote.transact(Stub.TRANSACTION_login, _data, _reply, 0);
                    _reply.readException();
                    _result = (0!=_reply.readInt());
                }finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override 
            public void logout(java.lang.String userName) throws android.os.RemoteException{
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(userName);
                    mRemote.transact(Stub.TRANSACTION_logout, _data, _reply, 0);
                    _reply.readException();
                }finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
    static final int TRANSACTION_login = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_logout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public boolean login(java.lang.String userName, java.lang.String userPwd) throws android.os.RemoteException;
    public void logout(java.lang.String userName) throws android.os.RemoteException;
}

Binder类结构

上面就是是系统生成的IUser.java,可能看起来会有些头疼,但结构其实非常简单,上面作为源码参考,下面我将其方法内容省略,将结构分离出来,这个接口继承于IInterface,在其中中实现了一个内部类Stub,Stub又有一个内部类Proxy,代码如下:

package com.ipctest.aidl;
//AIDL文件中定义的IUser接口
public interface IUser extends android.os.IInterface
{
    //IUser中的内部类,继承于Binder类并实现了IUser接口,在service中传递的就是这个类
    public static abstract class Stub extends android.os.Binder implements com.ipctest.aidl.IUser{
        //接口的唯一标识,一般由包名+类名组成
        private static final java.lang.String DESCRIPTOR = "com.ipctest.aidl.IUser";

        public Stub(){
            //在构造方法中将自身接口标识存储起来
            this.attachInterface(this, DESCRIPTOR);
        }

        public static com.ipctest.aidl.IUser asInterface(android.os.IBinder obj)
        {
            //获取binder对象
            //在这里会调用obj.queryLocalInterface(DESCRIPTOR)来获取binder,在service返回Binder时会判断client请求进行处理
            //如果请求来自当前线程,queryLocalInterface()会返直接返回构造方法中attachInterface()的binder对象,也就是binder本身
            //如果来自其他进程,queryLocalInterface方法直接返回null
            //这时就需要创建一个Proxy对象(Stub的内部代理类)供client使用
        }

        @Override 
        public android.os.IBinder asBinder()
        {
            //获取当前Binder
            return this;
        }

        @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{
            //在跨进程请求时被调用,请求先被Proxy对象处理,Proxy将方法参数序列化之后
            //和方法编号以及方法参数和用于存储返回值的序列化对象(如果有返回值)一同交给此方法
            //然后在这里将参数还原,并调用相应的方法进行处理,最后将返回值序列化后返回给Proxy。
        }

        //Stub的内部类,当请求来自同一进程时,不会使用,当请求来自另一个进程时,会将client得到的binder包装成它的实例
        private static class Proxy implements com.ipctest.aidl.IUser{
            private android.os.IBinder mRemote;
            //持有一个IBinder,通常就是stub本身
            Proxy(android.os.IBinder remote){
                mRemote = remote;
            }

            //获取当前的Proxy对象
            @Override 
            public android.os.IBinder asBinder(){
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor(){
                return DESCRIPTOR;
            }

            @Override 
            public boolean login(java.lang.String userName, java.lang.String userPwd) throws android.os.RemoteException{
                //login方法请求封装
            }

            @Override 
            public void logout(java.lang.String userName) throws android.os.RemoteException{
                //logout方法请求封装
            }
        }
        //IUser借口中两个方法的code
    static final int TRANSACTION_login = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_logout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    //待实现的方法
    public boolean login(java.lang.String userName, java.lang.String userPwd) throws android.os.RemoteException;
    public void logout(java.lang.String userName) throws android.os.RemoteException;
}

Binder使用方法

上面就是IUser的结构,下面通过一个例子先演示一下Binder的实现方式:

//首先创建Service,还是使用前面的aidl生成的Binder
public class MyService extends Service{
    private final String TAG="BinderTest";
    //创建Binder对象,实现两个方法
    private Binder mBinder= new IUser.Stub() {
        @Override
        public boolean login(String userName, String userPwd) throws RemoteException {
            Log.d(TAG,userName+"   登录成功!");
            return true;
        }

        @Override
        public void logout(String userName) throws RemoteException {
            Log.d(TAG,userName+"   退出成功!");
        }
    };

    //在onBind中返回Binder对象
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
//然后在Activity中启动服务
public class MainActivity extends AppCompatActivity {
    private final String TAG = "MyServiceTest";
    private EditText mUserNameEdt, mUserPwdEdt;
    private Button mLoginBtn, mLogoutBtn;
    IUser mUserBinder;

    //创建ServicerConnection
    ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected");
            mUserBinder = IUser.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "oncreate");
        setContentView(R.layout.activity_main);
        initLayout();
        //绑定服务
        Intent intent = new Intent(MainActivity.this, MyService.class);
        bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
    }

    private void initLayout() {
        mUserNameEdt = (EditText) this.findViewById(R.id.user_name_edt);
        mUserPwdEdt = (EditText) this.findViewById(R.id.user_pwd_edt);
        mLoginBtn = (Button) this.findViewById(R.id.login_btn);
        mLogoutBtn = (Button) this.findViewById(R.id.logout_btn);
        //点击登录按钮访问Service的Binder的login方法
        mLoginBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String userName = mUserNameEdt.getText().toString();
                String userPwd = mUserPwdEdt.getText().toString();
                if (mUserBinder != null) {
                    try {
                        mUserBinder.login(userName, userPwd);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        //点击退出按钮访问Service的Binder的logout方法
        mLogoutBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String userName = mUserNameEdt.getText().toString();
                if (mUserBinder != null) {
                    try {
                        mUserBinder.logout(userName);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

点击按钮结果:

这里写图片描述
可以发现Binder中的方法被执行了,这是同一进程的运行结果,如果将service运行在独立线程中又会如何呢?

    //在Manifest中为MyService设置一个进程
    <service
            android:name=".MyService"
            android:process=":remote" />

运行结果:
这里写图片描述

这里写图片描述

可以看到,在将MyService的进程中login()和logout()被执行了,也就是说点击按钮后成功的跨进程调用了MyService的方法


Binder对象的传递过程

接下来详细解析Binder从Service到client的传递过程

首先看上边的Demo,在MyService中实现了对象

private Binder mBinder= new IUser.Stub() {
        @Override
        public boolean login(String userName, String userPwd) throws RemoteException {
            Log.d(TAG,userName+"   登录成功!");
            return true;
        }

        @Override
        public void logout(String userName) throws RemoteException {
            Log.d(TAG,userName+"   退出成功!");
        }
    };
@Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

IUser.Stub,在文章开头的源码中可以找到,它是一个抽象类,继承与Binder类,这个对象在service与MyService通信使用的Binder,同时它实现了我们定义的Aidl的IUser接口,也就是说这个Binder拥有了我们的自定义方法(在Stub中只是将IUser接口的方法继承了下来,但并没有实现,直到在我们创建这个实例时手动实现了方法),然后通过Binder的onTransact()的code参数将client的请求类型与本地的方法绑定,在将此Binder对象返回给client,单从应用层来看,如此便将方法暴露给了client。(后面注意Stub类是我们自定义的Binder类,后面说的binder对象便是Stub对象)

再看client代码:

ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected");
            mUserBinder = IUser.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

 bindService(intent,mServiceConnection,BIND_AUTO_CREATE);

在client中,创建了一个ServiceConection对象,并在bindService()启动服务时进行绑定,当服务启动ServiceConnection连接成功时:
1、service的onBind()方法被执行,返回我们我们创建的Binder对象(mBinder)
2、clientServiceConection对象的onServiceConnected(ComponentName name, IBinder service)方法被执行,参数service用来接收service返回的Binder,然后在下面这一句代码将得到的Binder转为可识别的对象(asInterface如果是同进程直接返回收到的binder,如果是跨进程会返回一个Binder的内部代理类Proxy的实例),这样client就得到了在Service中创建的Binder,通过aidl的IUser引用即可使用Binder的方法。

mUserBinder = IUser.Stub.asInterface(service);

那么IUser.Stub.asInterface(service),这个方法是到底是如何处理收到的binder对象的呢?来看源码:

public static com.ipctest.aidl.IUser asInterface(android.os.IBinder obj){   
        /*obj为service的binder对象,先做非空判断*/
        if ((obj==null)) {
            return null;
        }
        /*这里验证binder对象中DESCRIPTOR是否合法,是直接返回binder,否返null(详解见下面的源码)*/
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        /*如果不为null,将binder对象转换为我们定义的IUser类型,返回给client的ServiceConnection*/
        if (((iin!=null)&&(iin instanceof com.ipctest.aidl.IUser))) {
            return ((com.ipctest.aidl.IUser)iin);
        }
        /*如果为null代表为跨进程请求,创建一个Proxy代理对象(Stub的内部类,后面详解)*/
        return new com.ipctest.aidl.IUser.Stub.Proxy(obj);
    }

上面可以看到asInterface将binder对象进行了处理,如果请求为当前进程,那么同进程可共享内存,即可直接使用service返回的binder对象,但如果请求是跨进程,则将binder对象包装为一个代理对象,返回给client,到这里Binder的传递流程就通了,但如何区分是当前进程还是跨进程呢?关键就在Stub的queryLocalInterface的方法,我们继续深入,这个方法是Stub的父类Binder中的方法,我们看源码:

//在Stub的asInterface中调用了这个方法,DESCRIPTOR为Stub的接口唯一标识,默认为包名路径
obj.queryLocalInterface(DESCRIPTOR);

//queryLocalInterface源码
public IInterface queryLocalInterface(String descriptor) {
       //在这里先将传入的接口标识和Binder的字段mDescriptor对比是否一样,是返回mOwner字段,否返回null
       //那mDescriptor和mOwner两个字段又代表了什么呢,我们找到其获取值得地方,见下一个方法
       if (mDescriptor.equals(descriptor)) {
           return mOwner;
       }
       return null;
   }

//在看这两个字段的赋值之前,先看看他们的类型,这是这两个字段的声明
//可以看到mOwner是一个IInterface 接口引用,也就是说他可以接受任何类型的对象实例
private IInterface mOwner;
//mDescriptor为一个字符串,然后看赋值
private String mDescriptor; 

//在这里我们发现,attachInterface方法中对mOwner和mDescriptor字段进行了赋值
//既如此,那么我们找到attachInterface方法的调用者即可知道这两个字段的内容,看下一个方法
public void attachInterface(IInterface owner, String descriptor) {
       mOwner = owner;
       mDescriptor = descriptor;
   }

//仔细看了Stub结构的读者应该可以发现,attachInterface方法在Stub的构造方法中就被调用了
public Stub(){
            //这里传入的参数为this为我们传递的stub对象本身
            //DESCRIPTOR为Stub的接口标识,在Stub源码可以看到
            this.attachInterface(this, DESCRIPTOR);
        }

也就是说在binder对象被创建时,使用attachInterface(this, DESCRIPTOR)将其自身和接口标识存入mOwner和mDescriptor字段
在client接收到这个对象后,调用queryLocalInterface(DESCRIPTOR)方法,将Stub类的DESCRIPTOR字段与mDescriptor比较,如果相同表示client请求来自同一进程,返回mOwner字段,否则表示是跨进程请求,返回null,那么就有一个问题:

Service返回的是同一个Binder对象,且这个对象在构造时就已经为mDescriptor字段赋值,那么为什么在同一进程的client在进行mDescriptor.equals(descriptor)比较的时候是为true成立的,而client在另一个进程时这个条件就为false了呢?

这个就涉及到更底层的知识了,从系统的角度来看,client得到的binder对象引用并不是由service直接交付的,而是通过Binder驱动: 当我们的client需要serivice中binder对象的引用而又不在同一进程时,service首先会将本地内存中binder对象的名字通过处于内核的Binder驱动交给ServiceManagerServiceManager将binder的引用存储起来,在client中通过binder的名字来访问ServiceManager中存储的对binder对象的引用,然后Binder驱动会为client也创建一个Binder对象,不同的是这个对象并不是一个Binder实体,而是对service中binder的方法调用请求的封装(调用通过从ServiceManager中得到的binder引用)

那么到这里就可以知道,之所以mDescriptor.equals(descriptor)在跨进程的时候会不成立,是因为在Binder驱动为client创建binder对象时,这个对象只是一个对service中的binder实体各种业务请求的封装,而不是一个真正的binder实体

想要深入理解这个部分,可以看看:http://blog.csdn.net/universus/article/details/6211589

现在来整理一下:
1、首先在binder对象被创建时,在构造方法中调用attachInterface(this, DESCRIPTOR)将其自身和接口标识存入mOwner和mDescriptor字段
2、Service 的onBinder()返回binder对象,Bidner驱动创建mRemote交给client,client得到binder对象
3、client进行请求方式判断(同进程或跨进程),是同一个进程直接返回binder对象,否则返回代理对象
4、client使用service业务
client拿到binder对象的过程就到这


Binder 请求处理过程

先说service和client在同一进程的情况:同进程内存是可以共享的,所以前面解释过当请求来自同一进程时,client得到的binder就是我们创建的mBinder对象,所以我们调用其方法就是常规的方法调用,

而service和client不在同一进程时,就产生了跨进程的问题,我们知道,不同进程的内存是不可共享的,一个新的进程甚至会导致Application和各个静态变量的重复创建,所以我们就无法直接对binder的方法进行调用,这时就需要通过Binder驱动去访问seriver中的binder。

前面说了,client中使用的binder对象是Binder驱动为client创建的一个“对service中binder的方法调用请求的封装”,那这个调用请求是如何实现的呢?前面讲解了当client请求来自跨进程时,会创建一个Stub中的Proxy类的实例,我们在来看看这个Proxy类的源码,在前面的源码中可以看到Proxy类同样实现了IUser接口,先看看构造方法

Proxy(android.os.IBinder remote){
                mRemote = remote;
            }

在Stub的asInterface()方法中有这句代码,就是前面说的当请求为跨进程时创建Proxy的对象

return new sikang_demo.ipctest.IUser.Stub.Proxy(obj);

可以看到这里将obj作为构造参数,记录在了Proxy对象中,也就是说它持有了service的service引用,然后再看源码

@Override 
            public boolean login(java.lang.String userName, java.lang.String userPwd) throws android.os.RemoteException
            {
                /*用于存储方法参数和返回值*/
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    /*写入接口标识、和binder中login()方法需要的参数userName,和userPwd*/
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(userName);
                    _data.writeString(userPwd);
                    /*调用mRemote的transact方法申请serive业务*/
                    mRemote.transact(Stub.TRANSACTION_login, _data, _reply, 0);
                    /*得到返回值*/
                    _reply.readException();
                    _result = (0!=_reply.readInt());
                }finally {
                    _reply.recycle();
                    _data.recycle();
                }
                /*将结果反馈给客户端*/
                return _result;
            }

            @Override 
            public void logout(java.lang.String userName) throws android.os.RemoteException{
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(userName);
                    mRemote.transact(Stub.TRANSACTION_logout, _data, _reply, 0);
                    _reply.readException();
                }finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

这里实现了IUser接口的两个方法,在跨进程的客户端请求binder方法业务时,直接与客户端接触的就是这里的方法,我们看看方法的内容,方法的处理是一样的,这里根据login方法来讲解

首先在方法开始创建了两个Parcel对象,我们知道Parcel是Java中序列化的一种实现,在跨进程通信时,传输的数据必须可序列化,这里这两个Parcel对象 _data_reply分别用于保存方法参数和接收返回值,可以看到在_data中写入了一个binder的接口标识,和login方法需要的两个参数,然后调用了

mRemote.transact(Stub.TRANSACTION_logout, _data, _reply, 0);

mRemote为Proxy被创建时传入的binder引用,先来看看这个方法几个参数的含义:

public final boolean transact(int code, Parcel data, Parcel reply, int flags)

code:请求方法的编号,当这个请求被service的binder收到时,就是通过这个参数来确定客户端请求的是哪个方法。
data:请求方法需要的参数
reply:用于接收方法的返回值
flags:一般用不到这个参数

data和reply很好理解,但这个code是什么呢?先看看Stub类的最下面有这么两句代码

static final int TRANSACTION_login = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_logout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

这就是我们在IUser接口中定义的两个方法的code,由此可知,binder被创建时,会为它从接口继承来的每个方法都创建一个唯一的code,用来为方法编号,当client需要请求方法时,只需要向上面一样,传入一个方法code,及这个方法的参数和返回值保存者,就可以实现对指定方法的调用。
现在知道了client是这么请求的,那service又是如何响应的呢?看Stub中的onTransact类,

@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_login:
                {
                    /**取出方法参数*/
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    /**调用本地方法,传入参数*/
                    boolean _result = this.login(_arg0, _arg1);
                    reply.writeNoException();
                    /**将返回值写入reply对象*/
                    reply.writeInt(((_result)?(1):(0)));
                    return true;
                }
                case TRANSACTION_logout:
                {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.logout(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

onTransact()方法就是service的binder实体对client请求的响应方法,可以看到onTransact()的参数和client中调用的transact()方法参数相同,在client发出请求之后,Binder驱动 将这个请求通过ServiceManager提供的binder引用将请求转到binder的onTransact()方法中,如此service便受到了client的请求,然后在看看service是这么处理这个请求的

还是看login方法,看case TRANSACTION_login 中的处理:
首先取出了client写入到data中的参数,然后调用了login方法,最后将返回值写入了client提供的reply对象中,这时client就可以从reply中读取返回结果了

这就是Binder的请求处理过程,Binder就介绍到这,如果有什么考虑不周,大家可以帮忙提出来

猜你喜欢

转载自blog.csdn.net/Mr_Sk/article/details/50738259