Android AIDL-跨进程

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;
    }

}

时间: 2024-12-03 08:18:11

Android AIDL-跨进程的相关文章

Android AIDL 进行进程间通讯(IPC)

编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3.AIDL默认支持的类型包括java基本类型 (int.long.boolean等) 和 (String.List.Map.CharSequence),使用这些类型时不需要import声明.对于List和Map中的元素类型必须是AIDL支持的类型,如果使用自定义类型作为参数或者返回值,自定义类型必须实

Android Messenger 跨进程通信

如果你需要在不同进程间通信,你可以在Service中使用Messenger来实现进程中通信. 如果使用这种方式,Service中需要定义一个Handler对象(负责对客户端发送过来的Message进行响应). Messenger可以共享给client一个IBinder对象,client通过这个IBinder对象向Service发送Message,而前面提到的Handler对象是这一切的基础. 注:使用这种方式进行通信是不支持多线程的. 那就让我们来看看使用这种方式进行通信吧! 注:Service

Android Binder跨进程通信原理分析

出发前预备子弹 我们知道进程之间,虚拟地址不同,是不能直接通信的,这是一种保护机制.打开任务管理器,查看一下N多的进程,试想一下如果这些进程直接通信会带来什么后果? 而用户空间可以通过System calls(系统回调)与内核空间通信的,如果在内核空间中有一个模块,能够完成数据的转发,那么是不是两个进程就可以通信了呢?如下图: 上面提到一些用户空间.内核空间的概念,用户空间也能大概猜到是什么东西,而内核空间,就知道它是很底层的东西好了.而模块呢,可以简单的理解为实现一个功能的程序或一个硬件电路等

AIDL跨进程通信

注:慕课网详细教程:http://www.imooc.com/learn/606 一.线程通信应用场景 AIDL   IPC  多个应用程序  多线程 Binder   IPC  多个应用程序  没有多线程 Messenger   IPC  没有多线程 什么是IPC:http://www.jianshu.com/p/c0a5bdbba3c2 二.案例 三.工程结构 创建一个工程,即服务端 工程中创建一个Module,即客户端 四.服务端 一.创建AIDL文件夹 二.创建AIDL接口文件 // T

【整理】使用AIDL跨进程传递复杂对象的实践例子

首先定义对象类,并实现Parcelable接口,实现接口内的几个方法,看代码,Person.java package com.example.u3.aidltest; import android.os.Parcel; import android.os.Parcelable; /** * Created by U3 on 2015/3/11. */ public class Person implements Parcelable { private String name; public S

Android四大组件——Service后台服务、前台服务、IntentService、跨进程服务、无障碍服务、系统服务

Service后台服务.前台服务.IntentService.跨进程服务.无障碍服务.系统服务 本篇文章包括以下内容: 前言 Service的简介 后台服务 不可交互的后台服务 可交互的后台服务 混合性交互的后台服务 前台服务 IntentService AIDL跨进程服务 AccessibilityService无障碍服务 系统服务 部分源码下载 前言 作为四大组件之一的Service类,是面试和笔试的必备关卡,我把我所学到的东西总结了一遍,相信你看了之后你会对Service娓娓道来,在以后遇

(转载)你真的理解Android AIDL中的in,out,inout么?

前言 这其实是一个很小的知识点,大部分人在使用AIDL的过程中也基本没有因为这个出现过错误,正因为它小,所以在大部分的网上关于AIDL的文章中,它都被忽视了--或者并没有,但所占篇幅甚小,且基本上都是官方文档的译文,译者读者其实都不知其然.这几天在研究AIDL,偏偏我又是个执拗的性子,遇着不清不楚的东西就是想把它捋清楚,就下了些功夫研究了下AIDL中的定向tag,研究了下它的 in , out , inout . 整理而成此博文. 1.概述 首先要说的是定向tag是AIDL语法的一部分,而 in

android AIDL 语言用法

跨进程通信可以用AIDL语言 这里讲述下如何使用AIDL语言进行跨进程通信 文章参考 <设计模式>一书 demo结构参考 主要的文件类有:IBankAidl.aidl java文件:AidlBankBinder,BackActivity(应该是BankActivity写错了),BankService(继承自Service,服务类) IBankAidl.aidl文件 这里AIdl的使用对包位置有要求,所以我就把包名放出来了 package finishdemo.arcturis.binderan

android 远程Service以及AIDL的跨进程通信

在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问题了. 转换成远程Service非常简单,只需要在注册Service的时候将他的android:process的属性制定成 :remote就可以了. 重新运行项目,你会发现,不会出现ANR了. 为什么将MyService转换成远程Service后就不会导致程序ANR了呢?这是由于,使用了远程Serv

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

在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法,但是我们能发现Messenger是以串行的方式来处理客户端发来的信息,如果有大量的消息发到服务端,服务端仍然一个一个的处理再响应客户端显然是不合适的.另外,Messenger用来进程间进行数据传递但是却不能满足跨进程的方法调用,接下来我们来使用AIDL来实现跨进程方法调用,此前我们都是用Eclipse来实现的,这次我们看看在Android Studio中使用AI