binder应用层的学习——ADIL的使用与原理

使用aidl

首先看下应用使用aidl时的代码:
①在服务端和客户端创建aidl文件

服务端

// IMyAidlInterface.aidl
package aidl.com.example.test;
interface IMyAidlInterface {
    void hi(String s);
    String bye(int s);
    void hello(int s);
}

客户端

// IMyAidlInterface.aidl
package aidl.com.example.test;
interface IMyAidlInterface {
    void hi(String s);
    String bye(int s);
    void hello(int s);
}

两端的代码保持一致,包括包名和声明的方法(包含参数)一致,切aidl文件的存放位置,需要客户端和服务端存放在的相同的包名下。
如图
在这里插入图片描述
②make-project
在这里插入图片描述

点< make project >按钮使as根据aidl文件创建出所需要的与framework调渡的java文件

③ 服务端 实现在aidl中声明的方法
在这里插入图片描述
⑥客户端绑定服务,获取服务binder代理实例

 private void bindService() {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.aidlserver", "MyService"));
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (iMyAidlInterface != null){
                //服务断开
                iMyAidlInterface.asBinder().unlinkToDeath(this, 0);
                iMyAidlInterface = null;
            }
            //服务重连
            bindService();
        }
    };

    private IMyAidlInterface iMyAidlInterface;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        //获得服务binder实例
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                //服务生命监听
                service.linkToDeath(deathRecipient,0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            try {
                iMyAidlInterface.hi("");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

< make project> AS自动生成的代码
首先预览下自动生成的代码的类关系图
在这里插入图片描述
在这里插入图片描述

服务端实现服务方法

在AS 新建好aidl文件后,服务端实现IMyAidlInterface.Stub()方法,进而实现第一步在aidl声明的方法。
那么从IMyAidlInterface.Stub()开始入手:

  public static abstract class Stub extends android.os.Binder implements aidl.com.example.test.IMyAidlInterface
  {
    private static final java.lang.String DESCRIPTOR = "aidl.com.example.test.IMyAidlInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
    //调用attachInterface将 此stub 实例与DESCRIPTOR进行关联
      this.attachInterface(this, DESCRIPTOR);
    }
    ...

在binder.java中attachInterface()将stub 实例与DESCRIPTOR进行关联,便于后续服务被绑定时,调用queryLocalInterface(),查询进程有没有已关联的binder实例

    public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }

由于Stub类为抽象类,所以当实例化IMyAidlInterface.Stub时,需要实现相应的接口方法,如图
在这里插入图片描述
asBinder方法已在Stub类中实现,所以在我们自己实例化Stub类时不用必须实现asBinder()

public static abstract class Stub extends android.os.Binder implements aidl.com.example.test.IMyAidlInterface
  {
		...
		@Override
		 public android.os.IBinder asBinder()
	    {
	      return this;
	    }
		...	
}

客户端绑定服务(获取服务)

前提引入:客户端在服务绑定时,传入ServiceConnection对象,绑定服务后该对象的onServiceConnected会回调IBinder实例,如下代码:

 private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        //得到系统返回的iBinder对象后,传入IMyAidlInterface.Stub.asInterface()
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                //服务生命监听
                service.linkToDeath(deathRecipient,0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            try {
            //调用服务的方法
                iMyAidlInterface.hi("");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

接下来看看IMyAidlInterface.Stub.asInterface(service);里做了什么处理

 public static abstract class Stub extends android.os.Binder implements aidl.com.example.test.IMyAidlInterface
  {
  ...
  		public static aidl.com.example.test.IMyAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        	return null;
      }
      //查询该binder对象是否有绑定过DESCRIPTOR
       android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      //该binder对象有绑定过DESCRIPTOR, 则直接把该对象的类型转换为IMyAidlInterface后,即可返回该对象
      if (((iin!=null)&&(iin instanceof aidl.com.example.test.IMyAidlInterface))) {
        r	eturn ((aidl.com.example.test.IMyAidlInterface)iin);
      }
       //若该binder对象没有绑定过DESCRIPTOR,这新建一个内部类Proxy返回出去
      return new aidl.com.example.test.IMyAidlInterface.Stub.Proxy(obj);
    }
  ...
	}

接下来看看IMyAidlInterface.Stub.Proxy()构造方法:

 private static class Proxy implements aidl.com.example.test.IMyAidlInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      
      @Override public android.os.IBinder asBinder()
      {
      //返回mRemote实例
        return mRemote;
      }
      ...
 }

小结

由上述代码中可得到:当客户端与服务端是同个进程时,asInterface()返回的binder实例是 IMyAidlInterface.Stub的实例,而当客户端与服务端不是同个进程时,asInterface()返回的binder实例是新建一个IMyAidlInterface.Stub.Proxy实例

1、当客户端与服务端是同个进程时,asInterface()返回的binder实例是 IMyAidlInterface.Stub的实例,所以此时调用服务的方法时,并没有发生跨进程的传递事件:

2、当客户端与服务端不是同个进程时,asInterface()返回的binder实例是新建一个IMyAidlInterface.Stub.Proxy实例,所以此时调用服务的方法时,发生了跨进程的传递事件,这里需要看客户端的proxy类如何发送请求到服务端(应用层):
aidl的接口对应的方法编号:
在这里插入图片描述

IMyAidlInterface.java (IMyAidlInterface.Proxy.hi(String))

@Override public void hi(java.lang.String s) throws android.os.RemoteException
      {
        //获取包装类_data用于传入请求信息到服务端
        android.os.Parcel _data = android.os.Parcel.obtain();
        //获取包装类_reply用于接收服务端返回的信息
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          //描述请求服务端的信息(包名类名信息)
          _data.writeInterfaceToken(DESCRIPTOR);
          //传递服务方法的参数
          _data.writeString(s);
          //Stub.TRANSACTION_hi为调用的方法,为int类型,
          //AS根据aidl的方法自动为这些方法进行编号,约定好某个数字对应调用服务端的某个方法
          //后续依此传入_data, _reply
          //如果方法正常执行,则返回true
          boolean _status = mRemote.transact(Stub.TRANSACTION_hi, _data, _reply, 0);
          //服务端方法执行异常,且客户端有默认实现该aidl的接口方法,则执行客户端的方法
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().hi(s);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }

调用mRemote.transact()后,经过framework-native-kernel-native-framework,后调度到服务端进程的Binder.onTransact()
服务端进程的Binder.onTransact()接下来继续看看:
IMyAidlInterface.java (IMyAidlInterface.Stub.onTransact())

...
 @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                //根据code跳转到对应的分支,这个方法编号是as编译自动生成
                case TRANSACTION_hi: {
                    data.enforceInterface(descriptor);
                    java.lang.String _arg0;
                    //获取方法的参数
                    _arg0 = data.readString();
                    //调度服务端stub实例中实现的hi(String)
                    this.hi(_arg0);
                    reply.writeNoException();
                    //方法执行成功true返回
                    return true;
                }
...

总结

如上述绑定服务和使用服务的过程,可类比为以下图:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值