Android IPC进程间通信(从应用层源码分)《一》

来源:互联网 发布:阿里云如何注销 编辑:程序博客网 时间:2024/06/15 17:22

在Android系统中,里面涉及到大量的进程间通信(IPC),现在我想自己写一篇关于我对IPC的理解,理解有不对的地方还希望大家给指点出来,IPC我打算分两篇来写,第一篇主要介绍怎么自己写一个进程间通信及AIDL,第二篇就从应用层源码分析,进程间是怎么绑定Binder进行进程间通信的。
首先我们要知道Binder这个概念,到底什么事Binder,其实说简单点,它就是进程与进程间进行通信的一个桥梁。
在通常的情况下,我们写一个AIDL,首先会定义一个AIDL接口,我们就叫他CalculateInterface.aidl类,里面定义了

package com.example.aidl.calculate;interface CalculateInterface {     double doCalculate(double a, double b); }

然后他就会在工程目录的gen下面产生一个同样类的名词.Java文件,点进去如下:

package com.example.aidl.calculate;public interface CalculateInterface extends android.os.IInterface {    /** Local-side IPC implementation stub class. */    public static abstract class Stub extends android.os.Binder implements            com.example.aidl.calculate.CalculateInterface {        private static final java.lang.String DESCRIPTOR = "com.example.aidl.calculate.CalculateInterface";        /** Construct the stub at attach it to the interface. */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an         * com.example.aidl.calculate.CalculateInterface interface, generating a         * proxy if needed.         */        public static com.example.aidl.calculate.CalculateInterface asInterface(                android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.example.aidl.calculate.CalculateInterface))) {                return ((com.example.aidl.calculate.CalculateInterface) iin);            }            return new com.example.aidl.calculate.CalculateInterface.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_doCalculate: {                data.enforceInterface(DESCRIPTOR);                double _arg0;                _arg0 = data.readDouble();                double _arg1;                _arg1 = data.readDouble();                double _result = this.doCalculate(_arg0, _arg1);                reply.writeNoException();                reply.writeDouble(_result);                return true;            }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements                com.example.aidl.calculate.CalculateInterface {            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 double doCalculate(double a, double b)                    throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                double _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeDouble(a);                    _data.writeDouble(b);                    mRemote.transact(Stub.TRANSACTION_doCalculate, _data,                            _reply, 0);                    _reply.readException();                    _result = _reply.readDouble();                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        static final int TRANSACTION_doCalculate = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }    public double doCalculate(double a, double b)            throws android.os.RemoteException;}

每一个AIDL生成的java文件,都必须有一个纯根(Stud)和一个代理类Proxy,在进程通讯中,Proxy主要负责发送数据,Stub主要负责接收数据,打一个比方,我们客户端发送数据的时候,是通过客户端的Proxy发送数据给服务端,然后服务端在Stub中就会回调onTransact方法,将数据读取出来,调用相应的方法,这样就完成了两个进程的通讯。
接下来我们自己写一个AIDL,不需要写AIDL文件和生成的代码,这样可以更好的看清楚两个进程是怎么发送数据和接受数据的。
我们首先新建一个接口,我取名叫IBookManager,继承IInterface这个接口,和写AIDL这个接口有点像,这里面也是写

public interface IBookManager extends IInterface{    //这是进程通讯的域名    static final String DESCRIPTOR = "com.example.aidl.calculate.IBookManager";    //给接口里面的方法定义一个ID,因为进程通讯里面,服务端是不认识我们所传的方法名,只认识ID,通过ID查找相应的方法。    static final int TRANSACTION_getBook = IBinder.FIRST_CALL_TRANSACTION+1;    //接口方法    public double getBook(double a1,double a2) throws RemoteException;    //BookManagerImpl相当于AIDL中的纯根(Stub)    public class BookManagerImplStub extends Binder implements IBookManager{        //初始化绑定信息        public BookManagerImplStub() {            this.attachInterface(this, DESCRIPTOR);        }        //这个相当于Stub中的代理类        //官方解释:一个内部对象到一个com.example.aidl.calculateIBookManager接口,生成一个        //如果需要代理。        public static IBookManager asInterface(IBinder iBinder){            if(iBinder == null){                return null;            }            //这里是判断是否在同一个进程,如果在就把自身给反回,如果不是就交给Prixy代理类            android.os.IInterface iin = iBinder.queryLocalInterface(DESCRIPTOR);            if((iin != null) && (iin instanceof IBookManager)){                return (IBookManager)iin;            }            return new Proxy(iBinder);        }        @Override        public IBinder asBinder() {            return this;        }        @Override        protected boolean onTransact(int code, Parcel data, Parcel reply,                int flags) throws RemoteException {            switch (code) {                case INTERFACE_TRANSACTION:{                    reply.writeString(DESCRIPTOR);                    return true;                }                //这个就是在服务端接受到的消息ID,通过消息ID查找相应的方法                case TRANSACTION_getBook:{                    data.enforceInterface(DESCRIPTOR);                    //这些取数据底层都是使用NDK,C/C++写的。                    double a1;                    a1 = data.readDouble();                    double a2;                    a2 = data.readDouble();                    //这里是得到值回调getBook方法                    double result = this.getBook(a1, a2);                    reply.writeNoException();                    reply.writeDouble(result);                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        @Override        public double getBook(double a1, double a2) throws RemoteException {            return a1 + a2;        }        //这个类部类中很重要的成员,负责发送数据        public static class Proxy implements IBookManager{            private IBinder iBinder;            public Proxy(IBinder iBinder){                this.iBinder = iBinder;            }            @Override            public IBinder asBinder() {                return iBinder;            }            @Override            public double getBook(double a1, double a2) throws RemoteException {                Parcel data = Parcel.obtain();                Parcel reply = Parcel.obtain();                double result = 0;                try {                    //验证通讯的Token,为了安全                    data.writeInterfaceToken(DESCRIPTOR);                    //写入数据                    data.writeDouble(a1);                    data.writeDouble(a2);                    iBinder.transact(TRANSACTION_getBook, data, reply, 0);                    reply.readException();                    result = reply.readDouble();                } catch (Exception e) {                    reply.recycle();                    data.recycle();                }                return result;            }        }    }}

这代码咋一看,怎么和自动生成的代码一摸一样,确实是一摸一样,这里只是为了让大家看得更清楚一点,代码里面的注释还是写的比较详细,相信大家也能看懂,现在我说下怎么使用吧,把IBookManager这个接口类在客户端和服务端要保证一摸一样。
客户端使用的方法。

public class MainActivity extends Activity {     private Button btnCalculate;     private EditText etNum1;     private EditText etNum2;     private TextView tvResult;     private IBookManager mService;     private ServiceConnection mServiceConnection = new ServiceConnection() {         @Override         public void onServiceDisconnected(ComponentName name) {             mService = null;         }         @Override         public void onServiceConnected(ComponentName name, IBinder service) {             mService = IBookManager.BookManagerImplStub.asInterface(service);             try {                 //在客户端链接服务端成功了,设置一个死亡代理,就是当服务端死亡之后会回调这么方法                service.linkToDeath(recipient, 0);            } catch (RemoteException e) {                e.printStackTrace();            }         }   };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Intent intent = new Intent("com.example.aidldemoserver.BookService");        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);         etNum1 = (EditText) findViewById(R.id.et_num_one);         etNum2 = (EditText) findViewById(R.id.et_num_two);         tvResult = (TextView) findViewById(R.id.tv_result);         btnCalculate = (Button) findViewById(R.id.btn_cal);         btnCalculate.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 logE("开始远程运算");                 try {                     double num1 = Double.parseDouble(etNum1.getText().toString());                     double num2 = Double.parseDouble(etNum2.getText().toString());                     String answer = "计算结果:" + mService.getBook(num1, num2);                     tvResult.setText(answer);                 } catch (RemoteException e) {                 }             }         });    }}

服务端的使用方法:

public class BookService extends Service {     private static final String TAG = "CalculateService";     @Override     public IBinder onBind(Intent arg0) {         return implStub;     }     @Override     public void onCreate() {         super.onCreate();     }     @Override     public boolean onUnbind(Intent intent) {         return super.onUnbind(intent);     }     @Override     public void onDestroy() {         super.onDestroy();     }     public IBookManager.BookManagerImplStub implStub = new IBookManager.BookManagerImplStub(); }

大致的流程就介绍到这里,有说得不对的地方还希望大家给指点出来,我会继续努力的,下篇我将从源码中介绍进程是怎么通信的。
Android IPC进程间通信(从应用层源码分)《二》

0 0