从Android的aidl调用说起(一)

原创 2014年05月13日 23:24:34

aidl是提供给Android进程通信的工具。一个进程要跟另外一个进程通信正式因为有了aidl变得简单。

首先,我们看一下利用aidl进程调用的例子:

server:

1、aidl定义接口

package com.lbeing.service;

interface INetwork{
	String send(String url);
}
2、实现接口

public class NetworkServiceImpl extends INetwork.Stub {

private static final String TAG = "NetworkServiceImpl";
@Override
public String send(String url) {
new Thread(new Runnable() {
@Override
public void run() {
throw new NullPointerException();
}
},"NetworkServiceImpl").start();
String ret="RequestTime:"+System.currentTimeMillis()+"url:"+url;
return ret;
}
}

3、通过service实现远程服务

public class NetworkService extends Service {

	@Override
	public IBinder onBind(Intent intent) {
		return stub;
	}
	INetwork.Stub stub = new NetworkServiceImpl();

}
4、manifest文件中声明服务

这样Service端建好了。

Client端

1、拷入刚才建立的aidl文件

2、bindService

Intent intent = new Intent("android.intent.action.AIDLService");
bindService(intent, conn, Context.BIND_AUTO_CREATE);

其中conn对象中实现onServiceConnected方法

private ServiceConnection conn = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {

		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			network = INetwork.Stub.asInterface(service);

		}
	};
3、调用接口

network.send("http://www.baidu.com");

这样远程调用成功。但是AIDL是个什么东西,做了什么事情呢?我们看一下gen下生成的Inetwork.java文件

public interface INetwork extends android.os.IInterface {
	/** Local-side IPC implementation stub class. */
	public static abstract class Stub extends android.os.Binder implements
			com.lbeing.service.INetwork {
		private static final java.lang.String DESCRIPTOR = "com.lbeing.service.INetwork";
		private static final String TAG = "Stub";

		/** Construct the stub at attach it to the interface. */
		public Stub() {
			this.attachInterface(this, DESCRIPTOR);
			long pid =Process.myPid();
//			Log.d(TAG, "[Stub]"+pid);
		}

		/**
		 * Cast an IBinder object into an com.lbeing.service.INetwork interface,
		 * generating a proxy if needed.
		 */
		public static com.lbeing.service.INetwork asInterface(
				android.os.IBinder obj) {
			long pid =Process.myPid();
//			Log.d(TAG, "[asInterface]:"+pid);
			if ((obj == null)) {
				return null;
			}
			android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
			if (((iin != null) && (iin instanceof com.lbeing.service.INetwork))) {
				return ((com.lbeing.service.INetwork) iin);
			}
			return new com.lbeing.service.INetwork.Stub.Proxy(obj);
		}

		@Override
		public android.os.IBinder asBinder() {
			long pid =Process.myPid();
//			Log.d(TAG, "[asBinder]:"+pid);
			return this;
		}

		@Override
		public boolean onTransact(int code, android.os.Parcel data,
				android.os.Parcel reply, int flags)
				throws android.os.RemoteException {
			long pid =Process.myPid();
//			Log.d(TAG, "[onTransact]:"+pid);
			switch (code) {
			case INTERFACE_TRANSACTION: {
				reply.writeString(DESCRIPTOR);
				return true;
			}
			case TRANSACTION_send: {
				data.enforceInterface(DESCRIPTOR);
				java.lang.String _arg0;
				_arg0 = data.readString();
				java.lang.String _result = this.send(_arg0);
				reply.writeNoException();
				reply.writeString(_result);
				return true;
			}
			}
			return super.onTransact(code, data, reply, flags);
		}

		private static class Proxy implements com.lbeing.service.INetwork {
			private android.os.IBinder mRemote;
			private String TAG ="Proxy";
			long pid =Process.myPid();
			Proxy(android.os.IBinder remote) {
				mRemote = remote;
//				Log.i(TAG, "[Proxy]:"+pid);
			}

			@Override
			public android.os.IBinder asBinder() {
//				Log.i(TAG, "[asBinder]:"+pid);
				return mRemote;
			}

			public java.lang.String getInterfaceDescriptor() {
//				Log.i(TAG, "[getInterfaceDescriptor]");
				return DESCRIPTOR;
			}

			@Override
			public java.lang.String send(java.lang.String url)
					throws android.os.RemoteException {
//				Log.i(TAG, "[send]:"+pid);
				android.os.Parcel _data = android.os.Parcel.obtain();
				android.os.Parcel _reply = android.os.Parcel.obtain();
				java.lang.String _result;
				try {
					_data.writeInterfaceToken(DESCRIPTOR);
					_data.writeString(url);
					mRemote.transact(Stub.TRANSACTION_send, _data, _reply, 0);
					_reply.readException();
					_result = _reply.readString();
				} finally {
					_reply.recycle();
					_data.recycle();
				}
				return _result;
			}
		}

		static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
	}

	public java.lang.String send(java.lang.String url)
			throws android.os.RemoteException;
}
这一个生成的文件中一共有三个类,INetwork、Stub、Proxy这三个作用是什么呢?

类图关系如下:


通过Inetwork.aidl生成了INetwork.java.该接口类定义了Stub的内部虚类,Stub类中定义了一个Proxy内部类。看着是比较头疼。所以在上图中把他们分开了。

他们是怎么调用的呢?首先client端通过proxy对象调用方法。通过binder.transact()调用远程方法,远程方法即Stub的实现类,会触发onTransact()方法。那么他们怎么知道调用了那个方法,参数和结果是怎么传递的呢。要回答这个问题,还是要从生成代码入手。

因为Client和Server端,都是有Adt插件生成,保证了双方生成代码一致性

看proxy的send方法实现。

android.os.Parcel _data = android.os.Parcel.obtain();
				android.os.Parcel _reply = android.os.Parcel.obtain();
				java.lang.String _result;
				try {
					_data.writeInterfaceToken(DESCRIPTOR);
					_data.writeString(url);
					mRemote.transact(Stub.TRANSACTION_send, _data, _reply, 0);
					_reply.readException();
					_result = _reply.readString();
				} finally {
					_reply.recycle();
					_data.recycle();
				}
				return _result;
1、首先把参数序列号

2、调用transact方法

3、读取结果。

远程怎么知道调用那个方法的呢,这个是有transact的第一个参数保证确定,因为Client/Server代码一致,通过约定(ADT)生成代码保证。

调用方法问题解决了,那参数和结果是怎么传递的呢?答案同样是约定。


入参是:向Parcel对象中写入String数据,远程获取数据后,首先从Parcel获取String数据,作为send如参,调用成功后,把返回值写入Parcel中,

这样远程调用就完成了。
说了这么多,是不是aidl了解比较清楚了呢,那你知道Client怎么获取到proxy对象的吗?

可能有人会说,不就是通过bindService中获取的嘛,那么bindService又做了什么事情呢?下次再接着说





binder与aidl机制区别

binder是一个远程对象的基础类,核心部分是远程调用机制,这部分是由IBinder定义的。它是对IBinder类的实现,其中IBinder类提供这样一个类的标准的本地化实现方式。 大多数开发者不会去...
  • a2758963
  • a2758963
  • 2015-02-07 18:35:34
  • 2033

android开发中通过aidl实现远程方法调用

在安卓开发过程中我们可能见过这样的问题,就是在一个应用中调用另一个应用中的服务,并调用该服务中的方法。我们可能对调用服务并不陌生,可是要执行服务中的方法,却不能直接调用。因为两个服务和调用它的程序属于...
  • qq_28859405
  • qq_28859405
  • 2016-09-20 09:28:27
  • 1799

android-------采用AIDL调用远程服务

AIDL的作用 AIDL(Android Interface Definition Language)它是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interp...
  • dangnianmingyue_gg
  • dangnianmingyue_gg
  • 2015-09-03 22:25:54
  • 1281

android studio使用Aidl跨进程调用服务

以前就知道其大概代码流程,但是一直没有敲代码去实现,今天将其实现了,android studio下编写也遇到了一些小细节的问题,特此记录一下。 既然是模拟Aidl通讯,那么当然要编写两个应用了,一个...
  • lishaobo211985
  • lishaobo211985
  • 2016-10-20 22:02:09
  • 1381

Android深入源码分析理解Aidl整体调用流程(雷惊风)

2017年开始上班的第一天,老不想工作了,假期感觉还没开始就已经结束了,唉,时间就是这样,新的一年开始了,虽然很不想干正事,没办法,必须干起来,因为后边的路还很长,距离六十岁还很远。刚上班也没什么事,...
  • liuyonglei1314
  • liuyonglei1314
  • 2017-02-03 20:37:26
  • 1489

Android远程服务AIDL的使用以及配合接口回调使用

远程服务的接口回调Android 开发中的一些场景需要用到进程间通信,一般使用AIDL(Android Interface Definition Language)。使用AIDL绑定一个远程服务,远程...
  • woshiwoshiyu
  • woshiwoshiyu
  • 2017-01-09 01:02:15
  • 2390

Android单个app的aidl跨进程调用

先介绍背景:最近在做一个app,app里有一个组件,由于该组件需要操作sqlite数据库,因此组件其实是依赖于context的,而且组件初始化比较耗时(有一些文件要解压读取),所以我们希望这个组件在一...
  • adam_ling
  • adam_ling
  • 2016-09-11 22:32:28
  • 1223

Androidの使用AIDL调用系统打电话接口

Androidの使用AIDL调用系统打电话接口 1. 最近看了系统源码,需要使用打电话接口,顺便看了该AIDL       路径为:framework/base/core/telephony/com/...
  • xiabing082
  • xiabing082
  • 2015-03-16 15:14:12
  • 1147

AndroidStudio 引用 aidl 文件的两种方法

AndroidStudio 引入 aidl 文件,一般来说,有两种方法第一种方法直接在 src/main 目录下新建 aidl 文件夹,并将我们的 aidl 文件放到该目录下。因为 AndroidSt...
  • gdutxiaoxu
  • gdutxiaoxu
  • 2017-10-26 20:15:24
  • 808

Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用

在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法,但是我们能发现Messenger是以串行的方式来处理客户端发来的...
  • itachi85
  • itachi85
  • 2016-01-09 16:51:02
  • 8998
收藏助手
不良信息举报
您举报文章:从Android的aidl调用说起(一)
举报原因:
原因补充:

(最多只允许输入30个字)