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文件帮我们实现的部分包含了什么。
- service端在onBind中创建了一个Stub对象,由于Stub继承了Binder,Binder的创建就完成了。
- client端在ServiceConnection中将返回的IBinder对象封装成了Proxy对象,后面调用都是通过mRemote.transact来实现。
有了上一篇中framework的基础这里看起来就很清晰了,ServiceConnection中返回的就是一个BinderProxy,在客户端调用方法就是通过BinderProxy实现了一次IPC调用,在服务端一个IPC调用过来的时候就会调用onTransact方法,接下来就调用到了在Service组件中实现的方法了。到这里从驱动到应用的Binder都分析结束了。