Android跨进程通信(四):AIDL源码解析

文章目录

Android跨进程通信(一):AIDL使用教程1
Android跨进程通信(二):AIDL使用教程2
Android跨进程通信(三):Messenger使用教程
Android跨进程通信(四):AIDL源码解析
Android跨进程通信(五):Messenger源码解析

本篇文章是AIDL的源码解析,不了解AIDL的朋友可以看看使用教程,熟悉了基本的使用后再来阅读本文章。阅读本文章的时候,把服务端和客户端的工程都打开结合着它们来一同分析。

接口代码总览

在我们编写AIDL并成功编译后,工程里便会自动生成一个Java接口文件。首先来总览这个文件,红色框的方法就是AIDL文件里声明的方法。文件里还有一个Stub静态内部抽象类,它implements了此Java接口(蓝色框),也就是说它或它的子类要把AIDL声明的方法给实现了。
在这里插入图片描述
来看看Stub类。

红色框说明Stub类继承自Binder类,我们在写Service的时候,如果希望它能被绑定,就需要在onBind方法上返回Stub的实现类。也就是说Binder是进程通信的一个重要类。

黄色框的字符串用于标识此Binder,因为它是完整类名,所以可以保证不会和别的Binder混淆。

蓝色框的asInterface方法,返回了Proxy(代理)类。我们在写客户端的ServiceConnection的实现类时调用了它,也就是说客户端得到了这个代理。Proxy实现了AIDL声明的方法,在客户端上调用这些方法便实现了跨进程。

绿色框的asBinder方法,它把Stub返回了,也就是返回Binder。它在Proxy中调用。

灰色框的onTransact方法也在Proxy中调用,具体做了什么我们之后分析。
在这里插入图片描述
到这就先停下来总结一下。AIDL生成一个Java接口类,这个接口有两个重要的类。

第一个是Stub类,它继承了Binder,在服务端实现AIDL声明的方法,例如下面这个例子。

public class SensorService extends Service {
    private SensorBinder mBinder;

    private class SensorBinder extends ISensorAidlInterface.Stub{
        @Override
        //实现AIDL声明的方法
        public double getTemperature() throws RemoteException {...}

        @Override
        //实现AIDL声明的方法
        public String getSensorName() throws RemoteException {...}

        @Override
        //实现AIDL声明的方法
        public void setSensor(SensorConfig sensorConfig) throws RemoteException {...}
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return mBinder;
    }
    ...
}

第二个是Proxy(代理)类,它被客户端获取。它代理了AIDL声明的方法,使客户端能调用服务端的方法,例如下面这个例子。

public class MainActivity extends AppCompatActivity {
    ...
    private SensorServiceConnection mServiceConnection;
    //根据AIDL生成的java接口
    private ISensorAidlInterface mSensorAidlInterface;

    private class SensorServiceConnection implements ServiceConnection{
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        	//得到来自服务端的Proxy
            mSensorAidlInterface = ISensorAidlInterface.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    }
    ...
    mGetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    //通过Proxy调用服务端的方法
                    double temperature = mSensorAidlInterface.getTemperature();
                    mTempText.setText(temperature + "℃");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    ...
}

通过上面的分析,我们大概知道了AIDL生成的java接口的全局。接下来我们具体分析Proxy类,看看它是如何让客户端调用服务端方法的。

具体功能分析

展开Proxy类,其中红色框是AIDL声明的方法,客户端可以通过Proxy来调用它们。
在这里插入图片描述
打开其中一个方法来看看。看到代码1处的transact方法。它指的是请求调用服务端的getTemperature方法,方法参数是_data,返回结果是_reply。因为是跨进程,所以_data和_reply都实现了序列化。

从代码1到代码2,我们并没有看到线程切换,说明这是一个同步请求。AIDL是同步的。

@Override public double getTemperature() 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);
       	  //1
          boolean _status = mRemote.transact(Stub.TRANSACTION_getTemperature, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getTemperature();
          }
          _reply.readException();
          _result = _reply.readDouble();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        //2
        return _result;
      }

客户端发出了getTemperature的请求,接下来就是等待服务端响应了。上面提到Stub类有一个方法叫onTransact,来看看它。

看到代码1处,result就是Stub的getTemperature方法的返回值。还记得上面说过Stub的子类是由服务端来实现的。意思是说,这个地方就真正地调用了服务端的方法了。

@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 TRANSACTION_getTemperature:
        {
          data.enforceInterface(descriptor);
          //1
          double _result = this.getTemperature();
          reply.writeNoException();
          reply.writeDouble(_result);
          return true;
        }
        ...
      }
    }

再来看看下面的图片。可以看到客户端和服务端并不是直接通信的,而是经过了内核空间。这期间数据复制了1次。
在这里插入图片描述
Android系统为每个App分配了一定的虚拟内存,如下图的客户端和服务端。由于App有各自的虚拟内存,所以不能直接通信,数据需要经过内核空间。

App的虚拟内存映射到真实的物理内存上,例如客户端App虚拟内存映射到了物理内存A,服务端App虚拟内存映射到物理内存B。

客户端把数据A发送到内核空间,内核空间把它复制到共享物理内存上(红色框),正是因为共享,所以服务端直接使用即可,不需要再复制了。
在这里插入图片描述

最后

本篇文章通过源码分析了AIDL的原理。Messenger是AIDL的封装,下一篇我们来看看Messenger的源码是如何做到的。

参考文章

《AIDL使用以及原理分析》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值