AIDL中的Binder机制

AIDL中的Binder机制

来到应用层,使用binder的方法一般就是利用系统提供的AIDL来实现。AIDL的作用就是再编译的时候自动生成一个java文件实现binder的功能。

AIDL实现

这里就写一个最简单的AILD文件。

import com.arthas.aidldemo.Person;
interface IPersonManager {
    List<Person> getPersonList();
    boolean addPerson(inout Person person);
}

//另一个文件中声明一下Person
parcelable Person;

当build之后就会生成一个IPersonManager.java文件,然后创建一个Servive作为服务端。

package com.arthas.aidldemo

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


class MyService : Service() {
    var persons = ArrayList<Person>()

    @Nullable
    override fun onBind(intent: Intent): IBinder? {
        return object : IPersonManager.Stub() {
            @Throws(RemoteException::class)
            override fun addPerson(person: Person) {
                persons.add(person)
            }

            @Throws(RemoteException::class)
            override fun getPersonList(): List<Person> {
                return persons
            }
        }
    }

}

在onBind方法中返回一个IPersonManager.Stub对象,接下来创建一个客户端。

class MainActivity : AppCompatActivity(), View.OnClickListener {
     var bindService: Button? = null
     var addPerson: Button? = null

    var persons: ArrayList<Person>? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initView()
    }

    private fun initView() {
        bindService = findViewById<View>(R.id.bindService) as Button
        addPerson = findViewById<View>(R.id.addPerson) as Button
        bindService!!.setOnClickListener(this)
        addPerson!!.setOnClickListener(this)

    }

    @SuppressLint("NonConstantResourceId")
    override fun onClick(view: View) {
        when (view.id) {
            R.id.bindService -> {
                Log.d("TAG", "onClick: ")
               val intent = Intent(this,MyService::class.java)
                intent.action = MyService::class.java.name
                bindService(intent, conn, BIND_AUTO_CREATE)
            }
            R.id.addPerson -> try {
                iPersonManager!!.addPerson(Person(24, "yqf"))
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
            else -> {}
        }
    }

    private var iPersonManager: IPersonManager? = null
    var conn: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
            Log.d("TAG", "onServiceConnected: ")
            iPersonManager = IPersonManager.Stub.asInterface(iBinder)
        }

        override fun onServiceDisconnected(componentName: ComponentName) {
            iPersonManager = null
        }
    }
}

客户端中创建了一个ServiceConnection对象,调用bindService,在回调中拿到一个IBinder对象,然后调用IPersonManager.Stub.asInterface方法拿到了iPersonManager对象,这时候就可以通过这个对象来调用服务了。下面看下原理

AIDL实现原理

重点就看下自动生成的这个IPersonManager文件。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.arthas.aidldemo;
public interface IPersonManager extends android.os.IInterface
{
  /** Default implementation for IPersonManager. */
  public static class Default implements com.arthas.aidldemo.IPersonManager
  {
    @Override public java.util.List<com.arthas.aidldemo.Person> getPersonList() throws android.os.RemoteException
    {
      return null;
    }
    @Override public void addPerson(com.arthas.aidldemo.Person person) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }


先看第一段IPersonManager继承了android.os.IInterface,声明了一个Default类,里面的所有方法都是空实现就是一个默认实现。下面看在应用中出现的Stub类。

第一部分

  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.arthas.aidldemo.IPersonManager
  {//继承了Binder类,能够通过framework的框架实现Binder通信
    private static final java.lang.String DESCRIPTOR = "com.arthas.aidldemo.IPersonManager";
    static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);//创建两个int值代表两个方法
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);//binder类中的方法用来设置当前Binder的DESCRIPTOR
    }
    /**
     * Cast an IBinder object into an com.arthas.aidldemo.IPersonManager interface,
     * generating a proxy if needed.
     */
    public static com.arthas.aidldemo.IPersonManager asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//查询是否是本地对象,如果是本地对象直接返回,如果是代理对象会返回null
      if (((iin!=null)&&(iin instanceof com.arthas.aidldemo.IPersonManager))) {
        return ((com.arthas.aidldemo.IPersonManager)iin);
      }
      return new com.arthas.aidldemo.IPersonManager.Stub.Proxy(obj);//根据传入的IBinder对象创建proxy对象
    }
    @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
    {//根据参数判断调用的是哪个方法,每个方法对应的就是上面定义的那两个值。
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_getPersonList:
        {
          data.enforceInterface(descriptor);
          java.util.List<com.arthas.aidldemo.Person> _result = this.getPersonList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
        case TRANSACTION_addPerson:
        {
          data.enforceInterface(descriptor);
          com.arthas.aidldemo.Person _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.arthas.aidldemo.Person.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addPerson(_arg0);
          reply.writeNoException();
          if ((_arg0!=null)) {
            reply.writeInt(1);
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
  

远程调用在客户端保存的就是一个Proxy对象,下面就看下Proxy的实现。

  private static class Proxy implements com.arthas.aidldemo.IPersonManager
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;//将remote保存在本地
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      //在Proxy中实现了定义的两个方法。
      @Override public java.util.List<com.arthas.aidldemo.Person> getPersonList() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.arthas.aidldemo.Person> _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);//一个标准的IPC调用
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getPersonList();
          }
          _reply.readException();
          _result = _reply.createTypedArrayList(com.arthas.aidldemo.Person.CREATOR);
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void addPerson(com.arthas.aidldemo.Person person) 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 ((person!=null)) {
            _data.writeInt(1);
            person.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addPerson(person);
            return;
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            person.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.arthas.aidldemo.IPersonManager sDefaultImpl;
    }

    public static boolean setDefaultImpl(com.arthas.aidldemo.IPersonManager impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.arthas.aidldemo.IPersonManager getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public java.util.List<com.arthas.aidldemo.Person> getPersonList() throws android.os.RemoteException;
  public void addPerson(com.arthas.aidldemo.Person person) throws android.os.RemoteException;
}

这里可以总结一下AIDL文件帮我们实现的部分包含了什么。

  1. service端在onBind中创建了一个Stub对象,由于Stub继承了Binder,Binder的创建就完成了。
  2. client端在ServiceConnection中将返回的IBinder对象封装成了Proxy对象,后面调用都是通过mRemote.transact来实现。

有了上一篇中framework的基础这里看起来就很清晰了,ServiceConnection中返回的就是一个BinderProxy,在客户端调用方法就是通过BinderProxy实现了一次IPC调用,在服务端一个IPC调用过来的时候就会调用onTransact方法,接下来就调用到了在Service组件中实现的方法了。到这里从驱动到应用的Binder都分析结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值