Android AIDL-跨进程

简介: Android在设计理念上强调组件化,组件之间的依赖性很小。我们往往发一个Intent请求就可以启动另一个应用的Activity,或者一个你不知道在哪个进程的Service,或者可以注册一个广播,只要有这个事件发生你都可以收到,又或者你可以查询一个ContentProvider获得你想要的数据,这其实都需要跨进程通信的支持。

Android在设计理念上强调组件化,组件之间的依赖性很小。我们往往发一个Intent请求就可以启动另一个应用的Activity,或者一个你不知道在哪个进程的Service,或者可以注册一个广播,只要有这个事件发生你都可以收到,又或者你可以查询一个ContentProvider获得你想要的数据,这其实都需要跨进程通信的支持。只是Android将其封装的如此简单,应用开发者甚至完全不用关注它是不是和我在一个进程里。

我们有没有想过安全性问题,如此简单就可以跨进程的访问,安全性问题怎么保证。本来每个进程都是一个孤岛,而通过ipc,这个孤岛却可以和世界通信了。这里简单介绍下android中的安全机制。

android是如何实现ipc的呢?答案是binder。Binder并不是android最早开始使用,它发源于Be和Palm之前的OpenBinder,由Dianne Hackborn领导开发。Hackborn现在就在google,是android framework的工程师,我们可以从https://lkml.org/lkml/2009/6/25/3看一下,Hackborn如何描述binder。一句话总结:

In the Android platform, the binder is used for nearly everything that
happens across processes in the core platform. 

 android将binder几乎封装的不可见,我们看下层次结构是怎么样的。

最底层的是android的ashmen(Anonymous shared memoryy)机制,它负责辅助实现内存的分配,以及跨进程所需要的内存共享。

AIDL(android interface definition language)对Binder的使用进行了封装,可以让开发者方便的进行方法的远程调用,后面会详细介绍。

Intent是最高一层的抽象,方便开发者进行常用的跨进程调用。我们在使用Anroid的的四大组件的时候都会用的Intent。

 

AIDL是android为了方便开发者进行远程方法调用,定义的一种语言。使用aidl完成一个远程方法调用只需要三个步骤:

1.用aidl定义需要被调用方法接口。

2.实现这些方法。

3.调用这些方法。

下面我们以Service为例子来说明如何使用aidl。

Service是Android中的服务组件, 经常用来执行一些运行在后台的耗时操作. 使用一个Service需要继承Service类, 并根据需要重写生命周期方法. Service的生命周期如下:

 

从图中可以看出, Service可以有两种启动方式:

1. 以startService(Intent intent)的方式启动. 此时启动的Service与调用者之间没有关联, 即使调用者已经退出, Service仍然可以继续运行, 而且调用者和Service之间无法进行数据交换和通信. 如果需要停止Service的运行, 只能调用Context类的stopService(intent)方法, 或者由Service本身调用其stopSelf()等方法.

2. 以bindService(Intent service, ServiceConnection conn, int flags)的方式启动.

此时调用者与Service绑定在一起, 如果调用者退出, 则Service也随之退出, 而且调用者和Service之间可以进行数据交换或通信.

根据调用者和Service是否在一个应用程序内, 可以将调用者和Service之间的通信分为进程内通信和进程间通信.

 a. 进程内通信. bindService(Intent service, ServiceConnection conn, int flags)方法的第二个参数为ServiceConnection对象, 最后一个参数通常可以是Service.BIND_AUTO_CREATE. ServiceConnection是一个接口, 该接口包含2个方法:

|-- onServiceConnected(ComponentName name, IBinder service): 该方法在调用者和Service成功绑定之后由系统回调.

方法中的第一个参数ComponentName是所绑定的Service的组件名称, 而IBinder对象就是Service中onBinder()方法的返回值. 要实现调用者和Service之间的通信, 只需要调用IBinder对象中定义的方法即可.

下面我给出一个示例,工程结构如下:

 

在eclipse中定义一个aidl结尾的文件,我们一般将这个放在一个单独的包中。

package com.aidl;
interface TestAIDL {   
    String registerTestCall();   
    void invokCallBack();
}  

eclipse自动会生成一个,一个java文件,这个文件中可以看到Stud实现了上面的接口,并继承了Binder,如下:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: E:\\AndroidWS\\AIDLService\\src\\com\\aidl\\TestAIDL.aidl
 */
package com.aidl;
public interface TestAIDL extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.aidl.TestAIDL
{
private static final java.lang.String DESCRIPTOR = "com.aidl.TestAIDL";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.aidl.TestAIDL interface,
 * generating a proxy if needed.
 */
public static com.aidl.TestAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.aidl.TestAIDL))) {
return ((com.aidl.TestAIDL)iin);
}
return new com.aidl.TestAIDL.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_registerTestCall:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.registerTestCall();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_invokCallBack:
{
data.enforceInterface(DESCRIPTOR);
this.invokCallBack();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.aidl.TestAIDL
{
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 java.lang.String registerTestCall() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_registerTestCall, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void invokCallBack() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_registerTestCall = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_invokCallBack = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.lang.String registerTestCall() throws android.os.RemoteException;
public void invokCallBack() throws android.os.RemoteException;
}

 

编写实现类,只需要继承TestAIDL.Stub

 

package com.aidl;

import android.util.Log;

public class TestBinder extends TestAIDL.Stub {

    public String registerTestCall() {
        
        Log.i("1", "注册");
        return "您好";
    }

    public void invokCallBack() {
        Log.i("2", "回调");
    }

}

编写服务类,在服务类中需要创建TestBinder的对象。

 

package com.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class TestService  extends Service{

    private TestBinder mBiner= new TestBinder();
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return mBiner;
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        // TODO Auto-generated method stub
        return super.onUnbind(intent);
    }

}

 

 

客户端实现

在ServiceConnection中获取上面创建的binder对象,然后在客户端使用binder中的方法。

 

package com.example.aidlclient;

import com.aidl.TestAIDL;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class ActivityClient extends Activity {
    
    Button btnBind ;
    Button btnExcut ;
    Button btnUnbind ;
    private TestAIDL mBinder;
    EditText editText;
    final String Tag="com.aidl.TestAIDL";
    
    
    ServiceConnection conn= new ServiceConnection()
    {

        @Override
        public void onServiceConnected(ComponentName arg0, IBinder binder) {
            // TODO Auto-generated method stub
            mBinder=TestAIDL.Stub.asInterface(binder);
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            // TODO Auto-generated method stub
            
        }
        
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);
        btnBind=(Button)findViewById(R.id.button2);
        btnExcut=(Button)findViewById(R.id.button3);
        btnUnbind=(Button)findViewById(R.id.button1);
        
        editText=(EditText)findViewById(R.id.editText1);
        btnExcut.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                
                Log.d("","执行前");
                // TODO Auto-generated method stub
                if(mBinder!=null)
                {
                    try {
                    String s=    mBinder.registerTestCall();
                    editText.setText(s);
                        Log.d("","执行后");
                    } catch (RemoteException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        });
        
        btnUnbind.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                unbindService(conn);
            }
        });
        
        btnBind.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                
                Intent intentService = new Intent();
                intentService.setAction(Tag);
                
                bindService(intentService, conn, Context.BIND_AUTO_CREATE);
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_client, menu);
        return true;
    }

}

 

 

相关文章
|
移动开发 编解码 监控
mmkv跨进程,Android开发经验的有效总结,系列篇
mmkv跨进程,Android开发经验的有效总结,系列篇
|
2月前
|
Java Android开发
[Android AIDL] --- AIDL工程搭建
[Android AIDL] --- AIDL工程搭建
18 0
|
2月前
|
Java 开发工具 Android开发
[Android AIDL] --- AIDL原理简析
[Android AIDL] --- AIDL原理简析
33 0
|
9月前
|
缓存 Android开发
|
11月前
|
Java Android开发
Android IPC系列(一):AIDL使用详解
AIDL可以实现进程间的通信,由于每个进程都是运行在独立的空间,不同的进程想要交互需要借助一些特殊的方式,AIDL就是其中的一种,AIDL是一种模板,因为实际交互过程中,并不是AIDL起的作用,具体会在之后源码分析解释,AIDL的作用是为了避免重复编写代码而出现的一个模板
|
Android开发
Android IPC 之 AIDL 原理
Android IPC 之 AIDL 原理
Android IPC 之 AIDL 原理
|
安全 数据处理 Android开发
Android一次完美的跨进程服务共享实践
Android一次完美的跨进程服务共享实践
150 0
Android一次完美的跨进程服务共享实践