前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >AIDL初步理解

AIDL初步理解

原创
作者头像
笔头
修改2022-10-31 10:57:10
3100
修改2022-10-31 10:57:10
举报
文章被收录于专栏:Android记忆Android记忆

一、AIDL使用

1.基本使用

服务端创建

服务端代码结构
服务端代码结构

AIDL文件

代码语言:javascript
复制
interface IDemoInterface {
    void demo();
    int getDemo();
    void setDemo(int i);
}

代码语言:javascript
复制
public class DemoServer extends IDemoInterface.Stub{

    private int value=0;
    @Override
    public void demo() throws RemoteException {
        Log.e("DemoServer","demo");
    }

    @Override
    public int getDemo() throws RemoteException {
        return value;
    }

    @Override
    public void setDemo(int i) throws RemoteException {
        value=i;
        Log.e("DemoServer","setDemo"+i);
    }

}

代码语言:javascript
复制
public class DemoService extends Service {
    private DemoServer demoServer;
    public DemoService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        demoServer=new DemoServer();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return demoServer;
    }
}

以上是服务端代码,基本功能就是写入值、取出值。

客户端代码

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {

    private TextView startService,demo,setDemo,getDemo;

    IDemoInterface idemo;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService=findViewById(R.id.startService);
        demo=findViewById(R.id.demo);
        setDemo=findViewById(R.id.setDemo);
        getDemo=findViewById(R.id.getDemo);

        startService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.roxmotor.aidlservice.DemoService");
                intent.setPackage("com.roxmotor.aidlservice");
                boolean result = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
                Log.d("MainActivity",result+"");
            }
        });
        demo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    idemo.demo();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        setDemo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.d("MainActivity","设置了200");
                    idemo.setDemo(200);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        getDemo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    int value=idemo.getDemo();
                    Log.e("MainActivity","获取值:"+value);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //成功连接
            Log.d("MainActivity","pushManager ***************成功连接***************");
            idemo=IDemoInterface.Stub.asInterface(service);

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //断开连接调用
            Log.d("MainActivity","pushManager ***************连接已经断开***************");
        }
    };
}

执行结果

上面基本使用方式就不详细说了,这里就不详细说adil如何使用了,我们直接来看aidl是如何帮助我们跨进程处理数据的。

二、AIDL内部源码

代码语言:javascript
复制
public interface IDemoInterface extends android.os.IInterface
{
  /** Default implementation for IDemoInterface. */
  public static class Default implements com.roxmotor.aidlservice.IDemoInterface
  {
    @Override public void demo() throws android.os.RemoteException
    {
    }
    @Override public int getDemo() throws android.os.RemoteException
    {
      return 0;
    }
    @Override public void setDemo(int i) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.roxmotor.aidlservice.IDemoInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.roxmotor.aidlservice.IDemoInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.roxmotor.aidlservice.IDemoInterface interface,
     * generating a proxy if needed.
     */
    public static com.roxmotor.aidlservice.IDemoInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.roxmotor.aidlservice.IDemoInterface))) {
        return ((com.roxmotor.aidlservice.IDemoInterface)iin);
      }
      return new com.roxmotor.aidlservice.IDemoInterface.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
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_demo:
        {
          data.enforceInterface(descriptor);
          this.demo();
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_getDemo:
        {
          data.enforceInterface(descriptor);
          int _result = this.getDemo();
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
        }
        case TRANSACTION_setDemo:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          this.setDemo(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.roxmotor.aidlservice.IDemoInterface
    {
      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 void demo() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_demo, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().demo();
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public int getDemo() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getDemo, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getDemo();
          }
          _reply.readException();
          _result = _reply.readInt();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void setDemo(int i) 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.writeInt(i);
          boolean _status = mRemote.transact(Stub.TRANSACTION_setDemo, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setDemo(i);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.roxmotor.aidlservice.IDemoInterface sDefaultImpl;
    }
    static final int TRANSACTION_demo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getDemo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_setDemo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    public static boolean setDefaultImpl(com.roxmotor.aidlservice.IDemoInterface 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.roxmotor.aidlservice.IDemoInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public void demo() throws android.os.RemoteException;
  public int getDemo() throws android.os.RemoteException;
  public void setDemo(int i) throws android.os.RemoteException;
}

结构如下

代码初看比较长,我们一个个来看。

1.Default

我们先看下Default这个类,他只是实现了com.roxmotor.aidlservice.IDemoInterface这个接口,而且都是空实现,同时并没有继承Binder,asBinder返回是null,我个人一般不用Default。

2.Stub

2.1 Stub()

Stub构造函数,当我们bindService时,在onBind返回一个IBind类型接口,因为所有的IBinder aidl 远程调用都要继承自IDemoInterface.Stub,所以必然会调用到

代码语言:javascript
复制
public Stub()
{
  this.attachInterface(this, DESCRIPTOR);
}

Stub 的空构造函数。而Stub 本身又是Binder 的子类。调用了Binder 的attachInterface 方法。

代码语言:javascript
复制
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}

分别保存了当前类的实例对象(This,也就是当前的binder)和当前类接口描述符(DESCRIPTOR),后面会通过DESCRIPTOR查找对应的binder

代码语言:javascript
复制
private static final java.lang.String DESCRIPTOR = "com.roxmotor.aidlservice.IDemoInterface";

2.2 asInterface

代码语言:javascript
复制
public static com.roxmotor.aidlservice.IDemoInterface asInterface(android.os.IBinder obj)
{
  if ((obj==null)) {
    return null;
  }
  android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  if (((iin!=null)&&(iin instanceof com.roxmotor.aidlservice.IDemoInterface))) {
    return ((com.roxmotor.aidlservice.IDemoInterface)iin);
  }
  return new com.roxmotor.aidlservice.IDemoInterface.Stub.Proxy(obj);
}

我们知道这里的obj是bindService拿到的远程Binder,即BinderProxy(这里为什么是BinderProxy,后面文章会说到。)

那我们看下BinderProxy的queryLocalInterface(DESCRIPTOR)

代码语言:javascript
复制
public IInterface queryLocalInterface(String descriptor) {
    return null;
}

这里返回null,asInterface方法直接返回com.roxmotor.aidlservice.IDemoInterface.Stub.Proxy(obj)。如果obj不是远程的BinderProxy,那就是本进程Binder,其方法如下

代码语言:javascript
复制
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
    if (mDescriptor != null && mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

这里的mOwner,就是本地的一个Stub

这里的asInterface,就是判断是拿本地binder还是拿远程binder即BinderProxy

3.Proxy

代码语言:javascript
复制
private static class Proxy implements com.roxmotor.aidlservice.IDemoInterface
{
  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 void demo() throws android.os.RemoteException
  {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
      _data.writeInterfaceToken(DESCRIPTOR);
      boolean _status = mRemote.transact(Stub.TRANSACTION_demo, _data, _reply, 0);
      if (!_status && getDefaultImpl() != null) {
        getDefaultImpl().demo();
        return;
      }
      _reply.readException();
    }
    finally {
      _reply.recycle();
      _data.recycle();
    }
  }
  @Override public int getDemo() throws android.os.RemoteException
  {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    int _result;
    try {
      _data.writeInterfaceToken(DESCRIPTOR);
      boolean _status = mRemote.transact(Stub.TRANSACTION_getDemo, _data, _reply, 0);
      if (!_status && getDefaultImpl() != null) {
        return getDefaultImpl().getDemo();
      }
      _reply.readException();
      _result = _reply.readInt();
    }
    finally {
      _reply.recycle();
      _data.recycle();
    }
    return _result;
  }
  @Override public void setDemo(int i) 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.writeInt(i);
      boolean _status = mRemote.transact(Stub.TRANSACTION_setDemo, _data, _reply, 0);
      if (!_status && getDefaultImpl() != null) {
        getDefaultImpl().setDemo(i);
        return;
      }
      _reply.readException();
    }
    finally {
      _reply.recycle();
      _data.recycle();
    }
  }
  public static com.roxmotor.aidlservice.IDemoInterface sDefaultImpl;
}

调用远程binder会走Proxy这里。

我们可以大概看看出,Proxy实现了IDemoInterface的方法,内部实现是通过mRemote去调用的。这个mRemote就是bindService拿到的IBinder service,也就是BinderProxy.

我们拿getDemo方法来看看

_data是传参,_reply是返回值,他们是Parcel类型(进程间通信由于资源不共享,因此无法直接传递对象,只能通过序列化在不同的空间拷贝两份相同的资源

我们可以看出,不管哪个方法,_data都要存储DESCRIPTOR,也就是描述符。现在我们知道为什么客户端adil为什么要和服务端一样了。他们一样的话,DESCRIPTOR也就一样,服务端可以通过这个DESCRIPTOR可以在onTransact里面找到对应的方法。

getDemo没有参数,所以_data里面没有存储给服务端参数。setDemo里面存储了一个参数,调用了_data.writeInt(i)。

接下来执行

代码语言:javascript
复制
mRemote.transact(Stub.TRANSACTION_getDemo, _data, _reply, 0);

这里的mRemote,我们现在知道,他是BinderProxy.调用了transact方法,最终还是执行了Stub中的onTransact

代码语言:javascript
复制
  @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_demo:
        {
          data.enforceInterface(descriptor);
          this.demo();
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_getDemo:
        {
          data.enforceInterface(descriptor);
          int _result = this.getDemo();
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
        }
        case TRANSACTION_setDemo:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          this.setDemo(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }

我们看下TRANSACTION_getDemo,这里我们把this.getDemo方法的结果存储到reply中。这里this.getDemo是那里实现呢?

这里的Stub实现了IDemoInterface接口,但是并没有真正的实现,那在那里实现了?我们回看代码,发现了一个叫DemoServer的类,继承了IDemoInterface.Stub,实现了所有方法。

代码语言:javascript
复制
@Override
public int getDemo() throws RemoteException {
    return value;
}

this.getDemo就是返回value。

我们继续往下看。

执行mRemote.transact方法后,_result = _reply.readInt();会取出_reply值,然后return _result。最终拿到返回值。

整个过程完成。

Proxy调用getDemo,实际上是通过调用mRemote.transact()来触发远端Stub的onTransact()

一般流程:

  1. 创建参数与返回值的Parcel对象,将参数写入Parcel。
  2. 调用mRemote.transact(),返回值会写入到Parcel对象中。
  3. 从Parcel对象中读出返回值并return。

三、总结

1.binderService,获得一个远程binder,即BinderProxy

2.在Proxy,拿到BinderProxy,同时通过Parcel将参数传给BinderProxy,最终触发BinderProxy的transact方法。

3.Binder的transact方法最终会触发到Server上Stub的onTransact方法。

4.Server上Stub的onTransact方法中,会先从Parcel中解析中参数,然后将参数带入真正的方法中执行,然后将结果写入Parcel后传回。

5.Client的Ipc方法中,执行Binder的transact时,是阻塞等待的。一直到Server逻辑执行结束后才会继续执行。

6.当Server返回结果后,Client从Parcel中取出返回值,于是实现了一次IPC调用。

大概流程如下:

四、问题

1.ServiceConnection是如何获取到Binder的而且是BinderProxy?

2.transact方法最终是如何触发Stub中的onTransact的?

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、AIDL使用
  • 二、AIDL内部源码
    • 1.Default
      • 2.Stub
        • 2.1 Stub()
        • 2.2 asInterface
      • 3.Proxy
      • 三、总结
      • 四、问题
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档