您的位置:首页 > 大数据 > 人工智能

Binder框架及AIDL解析

2015-12-26 12:45 489 查看
Binder其实就是,连接服务端和客户端的桥梁,Binder可以提供系统中任何程序都可以访问的全局服务。(这时,我们可能会想到AIDL,因为提到全局的服务,我们一般都会用到AIDL,这和Binder有什么关系呢?其实,AIDL的内部实现,归根结底也是利用Binder的框架,只不过AIDL的代码是系统自动帮我们生成的,所以我们一般借助AIDL以简化不同应用程序间访问的全局服务。)

我们可以把任意的应用程序看做是客户端,全局的服务看作是服务端。

客户端:客户端的请求通过客户端Binder对象,调用tansact方法,传递到服务端。

服务端:服务端同样通过服务端Binder对象,接收客户端传递过来的请求,然后处理请求(调用Binde对象的onTansact方法)。

为了简化,先先借助AIDL实现全局服务。

下面以一个加减运算的服务,简单介绍Binder实现全局服务,首先新建AIDL文件:

package com.example.administrator.myaidl;

// Declare any non-default types here with import statements

interface ICalcAIDL {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(int a , int b);
int min(int a,int b);
}






服务端代码:CalService类

package com.example.administrator.myaidl;

import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

/**
* Created by Administrator on 2015/12/25.
*/
public class CalService extends Service {

private static String Tag="Service";

@Override
public void onCreate() {
super.onCreate();
Log.e(Tag,"OnCreate()");
}
//绑定返回Binder对象mBinder,mBinder是ICalcAIDL.Stub的引用(ICalcAIDL是我上面新建的AIDL文件名,Stub是继承于Binder的)
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}

@Override
public void onDestroy() {

Log.e(Tag,"OnDestroy()");
super.onDestroy();
}

@Override
public boolean onUnbind(Intent intent) {

Log.e(Tag,"onUnBinder()");
return super.onUnbind(intent);
}

@Override
public void onRebind(Intent intent) {
Log.e(Tag,"OnRebind()");
super.onRebind(intent);
}

private final ICalcAIDL.Stub mBinder=new ICalcAIDL.Stub(){

@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

}

@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}

@Override
public int min(int a, int b) throws RemoteException {
return a-b;
}
};
}
在此Service中,使用生成的ICalcAIDL创建了一个mBinder的对象,并在Service的onBind方法中返回.此时系统会自动为我们生成ICalcAIDL.java文件,如下:

/*
* This file is auto-generated.  DO NOT MODIFY.
* Original file: F:\\duan\\Linux\\CSDNDemo\\myaidl\\src\\main\\aidl\\com\\example\\administrator\\myaidl\\ICalcAIDL.aidl
*/
package com.example.administrator.myaidl;
// Declare any non-default types here with import statements

public interface ICalcAIDL extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.administrator.myaidl.ICalcAIDL
{
private static final java.lang.String DESCRIPTOR = "com.example.administrator.myaidl.ICalcAIDL";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.administrator.myaidl.ICalcAIDL interface,
* generating a proxy if needed.
*/
public static com.example.administrator.myaidl.ICalcAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.administrator.myaidl.ICalcAIDL))) {
return ((com.example.administrator.myaidl.ICalcAIDL)iin);
}
return new com.example.administrator.myaidl.ICalcAIDL.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_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_min:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.min(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.administrator.myaidl.ICalcAIDL
{
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 void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public int add(int a, int b) 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(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int min(int a, int b) 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(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_min, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_min = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
public int add(int a, int b) throws android.os.RemoteException;
public int min(int a, int b) throws android.os.RemoteException;
}
后面再解释自动生成的代码。

下面往清单文件里注册服务:

<service android:name=".CalService">

<intent-filter>
<action android:name="com.dfy.myaidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>


这里我们给Service指定了一个name,因为我们一会会在别的应用程序中通过Intent来查找此Service;这个不需要Activity,所以我也就没写Activity,安装完成也看不到安装图标,悄悄在后台运行着。

客户端UI显示:activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="bindService"
android:text="BindService" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="unbindService"
android:text="UnbindService" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="addInvoked"
android:text="12+12" />

<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="minInvoked"
android:text="50-12" />

</LinearLayout>


客户端代码:

package com.example.administrator.myaidl;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

private static final String Tag = "client";
private ICalcAIDL mCalcAidl;
private ServiceConnection mConn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(Tag,"onServiceConnection");
mCalcAidl = ICalcAIDL.Stub.asInterface(iBinder);

}

@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(Tag,"OnServiceDisconnected()");
mCalcAidl=null;

}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void bindService(View view ) {

Intent intent =new Intent();
intent.setAction("com.dfy.myaidl");

super.bindService(intent, mConn, Context.BIND_AUTO_CREATE);

}

public void unbindService(View view) {
super.unbindService(mConn);

}
public void addInvoked(View view) throws RemoteException {
if(mCalcAidl!=null){
int res= mCalcAidl.add(12,12);
Log.e("Tag","addInvoke()的结果:"+res);
Toast.makeText(this,res+"",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this,"服务器被异常杀死,重新连接!",Toast.LENGTH_SHORT).show();

}

}

public void minInvoked(View view) throws RemoteException {
if(mCalcAidl!=null){
int res=mCalcAidl.min(50,12);
Log.e(Tag, "minInvoke()的结果:"+res);
Toast.makeText(this,res+"",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "服务器异常,重新连接!",Toast.LENGTH_LONG).show();
}
}
}

ICalcAIDL.Stub.asInterface(iBinder)方法返回的是ICalcAIDL.Stub.Proxy对象。顾名思义就是ICalcAIDL的代理类,也是ICalcAIDL类型的。这里的iBinder对象就是客户端与连接服务器端建立连接时的IBinder,(也就是说是在服务器端初始化的mBinder)

所有代码到此结束!

下面具体结合自动生成的文件与服务端和客户端的联系。

自动生成的ICalcAIDL.java文件,看起来感觉很多,其实只需要关心几个模块即可,首先先看Stub定义:继承Binder,实现ICalcAIDL(我定义的aidl文件)

public static abstract class Stub extends android.os.Binder implements com.example.administrator.myaidl.ICalcAIDL


因此我们服务端CalcService里面实例化Binder对象mBInder通过如下代码:(实现ICalcAIDL.aidl文件里面定义的方法)

private final ICalcAIDL.Stub mBinder=new ICalcAIDL.Stub(){

@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

}

@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}

@Override
public int min(int a, int b) throws RemoteException {
return a-b;
}
};

再看

Stub类的onTansact方法:服务端的Binder实例会根据客户端发来的消息(依靠Binder对象),执行onTransact方法,然后由其参数决定执行服务端的代码。相信大家都看到里面的case判断语句了。

Stub类的asInterface()方法:这个方法关乎客户端代码,再次贴出客户端相关代码:
private ServiceConnection mConn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(Tag,"onServiceConnection");
mCalcAidl = ICalcAIDL.Stub.asInterface(iBinder);

}

@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(Tag,"OnServiceDisconnected()");
mCalcAidl=null;

}
};


public static com.example.administrator.myaidl.ICalcAIDL asInterface(android.os.IBinder obj)
这个方法返回一个Proxy实例,这个Proxy实例传入了我们的Binder对象,并且封装了我们调用服务端的代码,客户端会通过Binder对象的transact()方法调用服务端代码。

直接看Proxy的add方法。

android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);//读取服务端端口,与服务器端enforceInterface(DESCRIPTOR)相对应
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();//客户端接收服务端返回的数据,
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
Proxy的min方法类似,略...

总的过程可以这么理解:AIDL只不过是简化BInder框架的一个机制,(帮我们自动生成了代码)

下面是原生Binder框架实现与AIDL实现的具体细节:

我们需要了解里面的内部细节,1,在服务端:首先需要客户端与服务器建立连接时生成一个IBinder对象(这个IBinder对象是继承自Binder类,)

原生的Binder框架:在这个Binder类的内部需要复写onTransact(),方法内部是根据该方法的参数选择case语句分支,也就是选择不同的方法(需要提供的服务方法对应于AIDL用法里面建立的aidl文件)。

AIDL实现:先定义一个AID文件同样是需要一个IBinder对象,不过这里只需要实线Stub类的各种方法即可(Stub里面的各种方法就是定义的AIDL文件)。

2,在客户端:需要拿到在服务端初始化的IBInder对象,也即是在第一部中得到的IBinder对象,一般是从ServiceConnnectin类的onConnection方法中获取。

原生Binder框架:从ServiceConnnectin类的onConnection方法中获取,拿到IBinder对象,在需要调用服务的地方,向IBinder对象一步一步传入具体参数,并调用IBinder对象的onTransact()方法,向服务其传递参数,并等待服务器返回结果后,接收服务器返回的数据,(其实这里的onTransact方法就是第一部中生成IBInder对象时复写的onTransact方法)。

AIDL实现:在erviceConnnectin类的onConnection方法中通过IBinder对象,获取的是AIDL类型的类(提供服务的类)的代理对象,在需要调用服务的地方,直接调用该代理对象的相应方法就行,不需要向上面那样进行复杂的传递和接收工作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: