AIDL初识

| 分类 AIDL  Android  | 标签 安卓系统 

一、什么是AIDL(Android 接口定义语言)

官方文档

AIDL(Android 接口定义语言)与您可能使用过的其他 IDL 类似。
您可以利用它定义客户端与服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。
在 Android 上,一个进程通常无法访问另一个进程的内存。
尽管如此,进程需要将其对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象。
编写执行这一编组操作的代码是一项繁琐的工作,因此 Android 会使用 AIDL 来处理。

上面这段话是google文档的描述,目的是为了进程间通信,通过aidl文件可以生成java文件,方便实现ipc。底层还是binder通信,可以理解为多了一层包装,方便书写。

二、AIDL文件语法

AIDL 使用简单语法,使您能通过可带参数和返回值的一个或多个方法来声明接口。
参数和返回值可以是任意类型,甚至可以是其他 AIDL 生成的接口。
您必须使用 Java 编程语言构建 .aidl 文件。
每个 .aidl 文件都必须定义单个接口,并且只需包含接口声明和方法签名。

分类:

  • 第一类是 Java 编程语言中的基本类型,(如 int、long、char、boolean 等等)
  • 第二类包括 String、List、Map 和 CharSequence,
  • 第三类是其他 AIDL 生成的 interface,
  • 第四类是实现了 Parcelable protocol 的自定义类。

之外ANT生成java文件时还支持Bundle,eclips的ADT不支持,不过得为in类型。

in/out区别:

所有非原语参数都需要指示数据走向的方向标记。
可以是 in、out 或 inout(见以下示例)。
原语默认为 in,不能是其他方向。

举个例子:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.linxtu.demo.api.common.aidl;
// Declare any non-default types here with import statements

public interface IDemoApiManager extends android.os.IInterface
{
	/** Local-side IPC implementation stub class. */
	public static abstract class Stub extends android.os.Binder implements com.linxtu.demo.api.common.aidl.IDemoApiManager
	{
		private static final java.lang.String DESCRIPTOR = "com.linxtu.demo.api.common.aidl.IDemoApiManager";
		/** Construct the stub at attach it to the interface. */
		public Stub()
		{
			this.attachInterface(this, DESCRIPTOR);
		}
		/**
		 * Cast an IBinder object into an com.linxtu.demo.api.common.aidl.IDemoApiManager interface,
		 * generating a proxy if needed.
		 */
		public static com.linxtu.demo.api.common.aidl.IDemoApiManager asInterface(android.os.IBinder obj)
		{
			if ((obj==null)) {
				return null;
			}
			android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
			if (((iin!=null)&&(iin instanceof com.linxtu.demo.api.common.aidl.IDemoApiManager))) {
				return ((com.linxtu.demo.api.common.aidl.IDemoApiManager)iin);
			}
			return new com.linxtu.demo.api.common.aidl.IDemoApiManager.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
		{
			switch (code)
			{
				case INTERFACE_TRANSACTION:
				{
					reply.writeString(DESCRIPTOR);
					return true;
				}
				case TRANSACTION_addTest:
				{
					data.enforceInterface(DESCRIPTOR);
					int _arg0;
					_arg0 = data.readInt();
					int _arg1;
					_arg1 = data.readInt();
					int _result = this.addTest(_arg0, _arg1);
					reply.writeNoException();
					reply.writeInt(_result);
					return true;
				}
				case TRANSACTION_getDemoApiRegister:
				{
					data.enforceInterface(DESCRIPTOR);
					com.linxtu.demo.api.common.aidl.IDemoRegisterAIDL _result = this.getDemoApiRegister();
					reply.writeNoException();
					reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
					return true;
				}
			}
			return super.onTransact(code, data, reply, flags);
		}

		private static class Proxy implements com.linxtu.demo.api.common.aidl.IDemoApiManager
		{
			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;
			}
			/**
			     * Demonstrates some basic types that you can use as parameters
			     * and return values in AIDL.
			     */

			@Override public int addTest(int anIntA, int anIntB) 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);
					_data.writeInt(anIntA);
					_data.writeInt(anIntB);
					mRemote.transact(Stub.TRANSACTION_addTest, _data, _reply, 0);
					_reply.readException();
					_result = _reply.readInt();
				}
				finally {
					_reply.recycle();
					_data.recycle();
				}
				return _result;
			}

			@Override public com.linxtu.demo.api.common.aidl.IDemoRegisterAIDL getDemoApiRegister() throws android.os.RemoteException
			{
				android.os.Parcel _data = android.os.Parcel.obtain();
				android.os.Parcel _reply = android.os.Parcel.obtain();
				com.linxtu.demo.api.common.aidl.IDemoRegisterAIDL _result;
				try {
					_data.writeInterfaceToken(DESCRIPTOR);
					mRemote.transact(Stub.TRANSACTION_getDemoApiRegister, _data, _reply, 0);
					_reply.readException();
					_result = com.linxtu.demo.api.common.aidl.IDemoRegisterAIDL.Stub.asInterface(_reply.readStrongBinder());
				}
				finally {
					_reply.recycle();
					_data.recycle();
				}
				return _result;
			}
		}
		static final int TRANSACTION_addTest = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
		static final int TRANSACTION_getDemoApiRegister = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

	}
	/**
	     * Demonstrates some basic types that you can use as parameters
	     * and return values in AIDL.
	     */
	public int addTest(int anIntA, int anIntB) throws android.os.RemoteException;
	public com.linxtu.demo.api.common.aidl.IDemoRegisterAIDL getDemoApiRegister() throws android.os.RemoteException;
}

关键的函数asInterface返回Proxy类里面有aidl文件的方法,并且调用transact方法。

关键的函数onTransact根据transact传参处理。

三、服务端怎么写

  • 重写 IDemoApiManager.Stub 的方法
  • 重写 onBind() 方法,返回写好的 IDemoApiManager.Stub
    public abstract class DemoApiManagerService extends Service{
    
      IDemoApiManager.Stub mBinder = new IDemoApiManager.Stub(){
          @Override
          public int addTest(int anIntA, int anIntB) throws RemoteException {
              return anIntA+anIntB;
          }
    
          @Override
          public IDemoRegisterAIDL getDemoApiRegister() throws RemoteException {
              //
              if(demoRegisterService == null){
                  demoRegisterService = new DemoRegisterService();
              }
              return demoRegisterService;
          }
      };
    
      @Nullable
      @Override
      public IBinder onBind(Intent intent) {
          return mBinder;
      }
    }
    

四、客户端怎么写

  • 建立连接,然后在 ServiceConnection 里面通过asInterface获取 IDemoApiManager 对象
  • 接着通过它来调用服务端的方法
    private static IDemoApiManager demoapi;
    private static Intent startIntent = new Intent(SERVICE_ACTION_NAME);
    @Override
    public void onCreate() {
      super.onCreate();
      mContext = this;
      startIntent.setPackage(SERVICE_PACKAGE_NAME);
      if(demoapi == null) {
          this.startService(startIntent);
          this.bindService(startIntent, mConn, Context.BIND_AUTO_CREATE);
      }
    }
    private static ServiceConnection mConn = new ServiceConnection() {
      public void onServiceDisconnected(ComponentName name) {
          demoapi = null;
          Log.d(TAG, "onServiceDisconnected");
      }
      public void onServiceConnected(ComponentName name, IBinder service) {
          demoapi = com.linxtu.demo.api.common.aidl.IDemoApiManager.Stub.asInterface(service);
          Log.d(TAG, "onServiceConnected");
      }
    };
    

另外还有一种情况是通过获取系统服务,如下

IBinder b = ServiceManager.getService(Context.XXX);
if(b != null) {
	IDemoApiManager demoapi = com.linxtu.demo.api.common.aidl.IDemoApiManager.Stub.asInterface(b);
}

五、小结

通过上面的代码,可以帮助我们看代码时更容易理解。看代码根据三,四小节去查找。具体实现是需要阅读由aidl生成的java文件,也就是二中那一长串代码。有机会再整理。


上一篇     下一篇