初识Android进程间通信之----Binder机制

【转载请注明出处:http://blog.csdn.net/feiduclear_up/article/details/51405967 CSDN废墟的树】

前言

前面两篇博客分别介绍了Android进程间通信之AIDL的使用,以及使用AIDL传递复杂对象以及Bitmap对象。所谓AIDL:Android Interface Definition Language,是一种Android接口定义语言,用于编写Android进程间通信代码。也就是说AIDL只是一个实现进程间通信的一个工具,真正实现Android进程间通信机制的其实是幕后“主谋”Binder机制。所有有关AIDL实现进程间通信都是依赖于Android的Binder机制,那么这个Binder机制到底是个什么东西呢?在这篇博客中我只能说初始Binder机制,在下实在不敢造次,因为Android的Binder机制实在挺复杂的,要想深入了解Binder机制的实现原理的朋友们请绕道而走,出门左拐去看老罗的博客,我可不敢误人子弟啊。

简介

我们从整个抽象层面来理解Android的进程间通信Binder机制,在进程间通信有三个角色分别为:客户端(Client),Binder驱动,服务端(Service)。客户端通过Binder驱动向服务端发送请求,服务端又将请求的结果通过Binder驱动回送给客户端,这就是一个简单的进程间通信的描述。由此可以看到Binder驱动是两者的中间桥梁,是客户端和服务端的信使。

  • 服务端:定义了一个Binder对象,并且重写其中的onTransact方法来处理来自客户端的请求,该Binder对象会注册到系统中,以便客户端绑定使用。
  • Binder驱动:设备文件驱动,提供相应的接口给客户端和服务端,以便两者通信。
  • 客户端:通过绑定指定的服务来获取服务端的Binder对象,然后调用IBinder接口类中的transact方法进行远程调用。

IBinder是一个接口对象,其定义了一系列方法,其中一个方法transact至关重要,客户端就通过该方法来进行远程通信。而Binder对象继承IBinder接口,并实现了里面的方法。现在我们来看看Binder对象中的transact方法的实现:

/**
     * Default implementation rewinds the parcels and calls onTransact.  On
     * the remote side, transact calls into the binder to do the IPC.
     */
    public final boolean transact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);
        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }

分析:该方法有四个参数,分别是 code,data,reply,flag。

  • code:整形的一个识别码,客户端传入,用于区分服务端执行哪个方法。
  • data:客户端传入的Parcel类型的参数。
  • reply:服务端返回的结果值,也是Parcel类型数据。
  • flag:整形的一个标记,用于标记是否是否有返回值,0表示有返回值,1表示没有。

一般客户端需要调用transact方法来将客户端相应的参数传递给服务端。

我们知道transact方法是Binder类提供给客户端来实现远程调用的一个方法,而该方法中真正做事情的代码却是调用了Binder类中的onTransact方法。而该方法正是服务端用来实现客户端请求的方法,那么我们来看看onTransact方法:

 /**
     * Default implementation is a stub that returns false.  You will want
     * to override this to do the appropriate unmarshalling of transactions.
     *
     * <p>If you want to call this, call transact().
     */
    protected boolean onTransact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException {
        if (code == INTERFACE_TRANSACTION) {
            reply.writeString(getInterfaceDescriptor());
            return true;
        } else if (code == DUMP_TRANSACTION) {
            ParcelFileDescriptor fd = data.readFileDescriptor();
            String[] args = data.readStringArray();
            if (fd != null) {
                try {
                    dump(fd.getFileDescriptor(), args);
                } finally {
                    try {
                        fd.close();
                    } catch (IOException e) {
                        // swallowed, not propagated back to the caller
                    }
                }
            }
            // Write the StrictMode header.
            if (reply != null) {
                reply.writeNoException();
            } else {
                StrictMode.clearGatheredViolations();
            }
            return true;
        }
        return false;
    }

以上是onTransact方法的默认实现,其参数和transact方法一一对应。

一般服务端需要重写该方法来实现客户端的请求。

对AIDL文件的理解

通过上一小节我们知道,基于Binder机制的Android进程间通信的一个简易过程就是:服务端定义个Binder对象,并且重写其中的onTransact方法来实现客户端的请求,然后通过Service将该Binder注册到系统中。客户端通过绑定指定的服务来获得远程的IBinder对象,之后调用其中的transact方法来进行远程调用。

而标准的AIDL编程其实很简单,无须开发者自己主动去调用transact和实现onTransact方法,只需实现相应的一些功能即可。由此也方便了开发者,尽量避免让开发者去关注Binder工作的一个过程,而仅仅在意其功能就好了。不过我们本着学习的心态了解一点进程间通信的原理还是有帮助的。接下来我们简单分析一下一个aidl文件:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: G:\\WorkPlace\\ServiceAidl\\app\\src\\main\\aidl\\com\\xjp\\serviceaidl\\IMyAidlInterface.aidl
 */
package com.xjp.serviceaidl;
// Declare any non-default types here with import statements

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

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.xjp.serviceaidl.IMyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.xjp.serviceaidl.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.xjp.serviceaidl.IMyAidlInterface))) {
                return ((com.xjp.serviceaidl.IMyAidlInterface) iin);
            }
            return new com.xjp.serviceaidl.IMyAidlInterface.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();
                    int _result = this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.xjp.serviceaidl.IMyAidlInterface {
            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 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();
                int _result;
                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();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

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

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public int basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}

分析:

其中抽象类Stub是继承自Binder对象,且继承了开发者自己定义的接口IMyAidlInterface类,且该Stub类中实现了onTransact方法,也就是Stub类帮服务端实现了远程调用方法,所以服务端只需要实现IMyAidlInterface类中的接口方法即可。

其中代理类Proxy也是继承自Binder对象,且继承了开发者自己定义的接口IMyAidlInterface类,并且Proxy类实现了IMyAidlInterface类中的接口方法,在该方法中调用了Binder类的transact方法,也就是Proxy代理类帮客户端调用了transact方法,所以客户端直接调用IMyAidlInterface接口类中的方法。

由此我们知道客户端通过Binder调用IMyAidlInterface接口类中的方法,恰好服务端正好通过Binder来实现了IMyAidlInterface接口类中的方法,从而实现了客户端远程调用了服务端的接口方法来完成一次进程间的通信。

由此也看出上面的AIDL文件其实客户端只是使用了其中的Proxy类代码,服务端只是使用了其中的Stub类代码,但是在客户端和服务端都会生成相同的AIDL文件。那么我们可不可以再客户端把Stub类中代码去掉,然后再服务端把Proxy类代码去掉呢?答案是可以得。由于AIDL编程是idea自动生成的,它区分不了哪个是客户端,哪个是服务端,故而自动生成的AIDL文件即包括了客户端的代码,也包括了服务端的代码,看着有点冗余。既然我们知道了Android进程间通信Binder机制,那么接下来不使用AIDL编程语言来实现进程间通信试试!!!!

不使用AIDL实现进程间通信

其实上面几个小节已经讲解的很清楚了,只要服务端定义一个Binder对象并且实现其中的onTransact方法,客户端获取一个远程服务的IBinder对象并且调用其中的transact方法即可实现不实用AIDL实现进程间的通信。

示例代码

服务端

package com.xjp.serviceaidl;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.Nullable;

/**
 * Created by xjp on 2016/5/14.
 */
public class CustomService extends Service {
    private static final String DESCRIPTOR = "com.xjp.serviceaidl.service";
    private static final int TRANSACTION_add = 0;

    private Binder mIBinder = new Binder(){
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code){
                case TRANSACTION_add://方法标识码
                    data.enforceInterface(DESCRIPTOR);//读取系列化令牌,和客户端的data.writeInterfaceToken对应
                    int arg0 = data.readInt();//读取参数
                    int arg1 = data.readInt();//读取参数
                    int result = this.add(arg0,arg1);//本地方法
                    reply.writeNoException();
                    reply.writeInt(result);//回写结果值
                    return true;
            }
            return super.onTransact(code, data, reply, flags);
        }
        //远程调用的方法
        public int add(int arg0, int arg1){
            return arg0 + arg1;
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mIBinder;
    }
}

分析:服务端只是定义了Binder对象并且重写了onTransact方法,很简单。记得在AndroidManifest.xml配置该服务。

客户端代码

package com.xjp.clientbinder;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final String SERVICE_ACTION = "com.xjp.serviceaidl_service";
    private static final String SERVICE_PKG_NAME = "com.xjp.serviceaidl";
    private static final String DESCRIPTOR = "com.xjp.serviceaidl.service";
    private static final int TRANSACTION_add = 0;
    private IBinder mBinder;

    private TextView txtResult;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (service != null) {
                mBinder = service;
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            serviceConnection = null;
        }
    };

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

        txtResult = (TextView) findViewById(R.id.result);
    }

    public void bindService(View v) {
        Intent intent = new Intent(SERVICE_ACTION);
        intent.setPackage(SERVICE_PKG_NAME);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    public void unbindService(View v) {
        unbindService(serviceConnection);
    }

    public void remoteAdd(View v) throws RemoteException {
        int result = remoteAdd(4, 9);
        txtResult.setText("远程调用结果是:" + result);
    }

    private int remoteAdd(int arg0, int arg1) throws RemoteException {
        if (mBinder == null) {
            Toast.makeText(this, "请先绑定服务!", Toast.LENGTH_SHORT).show();
            return -1;
        }
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        int result;
        try {
            data.writeInterfaceToken(DESCRIPTOR);//往序列化中写一个令牌,和服务端的data.enforceInterface对应,相当于接头暗号。
            data.writeInt(arg0);//往序列化参数中写值
            data.writeInt(arg1);//往序列化参数中写值,值得注意是此处的写顺序必须和服务端的读顺序一致。
            mBinder.transact(TRANSACTION_add, data, reply, 0);//远程调用方法
            reply.readException();
            result = reply.readInt();//读取远程调用的结果值
        } finally {
            data.recycle();
            reply.recycle();
        }
        return result;
    }

}

分析:

  1. 值得注意的是data.writeInterfaceToken()方法的参数和服务端data.enforceInterface()方法的参数值必须保持一致,这相当于客户端和服务端的接头暗号。
  2. 客户端的data.write***()系列方法必须和服务端的data.read***()系列方法顺序保持一致,上一篇博客中有讲到。
  3. 客户端和服务端的方法区分码code的值也必须保持一一对应。

运行结果:

总结

如果你对Android进程间通信Binder是一个小白,请自觉使用AIDL语言来编写进程间通信,那么即保证不出错也简单。如果你觉得利用AIDL编程闲代码有点多余,那么你可以自己实现Binder类相应的方法来实现进程间通信。总之通过这几篇博客,总算对Android进程间通信之AIDL编程和Binder机制有个初步的了解。

时间: 2024-10-06 21:26:31

初识Android进程间通信之----Binder机制的相关文章

Android深入浅出之Binder机制(转)

Android深入浅出之Binder机制 一 说明 Android系统最常见也是初学者最难搞明白的就是Binder了,很多很多的Service就是通过Binder机制来和客户端通讯交互的.所以搞明白Binder的话,在很大程度上就能理解程序运行的流程. 我们这里将以MediaService的例子来分析Binder的使用: l         ServiceManager,这是Android OS的整个服务的管理程序 l         MediaService,这个程序里边注册了提供媒体播放的服

Android深入浅出之Binder机制【转】

Android深入浅出之Binder机制 一 说明 Android系统最常见也是初学者最难搞明白的就是Binder了,很多很多的Service就是通过Binder机制来和客户端通讯交互的.所以搞明白Binder的话,在很大程度上就能理解程序运行的流程. 我们这里将以MediaService的例子来分析Binder的使用: <!--[if !supportLists]-->l         <!--[endif]-->ServiceManager,这是Android OS的整个服务

从源码角度分析Android中的Binder机制的前因后果

前面我也讲述过一篇文章<带你从零学习linux下的socket编程>,主要是从进程通信的角度开篇然后延伸到linux中的socket的开发.本篇文章依然是从进程通信的角度去分析下Android中的进程通信机制. 为什么在Android中使用binder通信机制? 众所周知linux中的进程通信有很多种方式,比如说管道.消息队列.socket机制等.socket我们再熟悉不过了,然而其作为一款通用的接口,通信开销大,数据传输效率低,主要用在跨网络间的进程间通信以及在本地的低速通信.消息队列和管道

Android中的Binder机制的简要理解

转载自:http://www.linuxidc.com/Linux/2012-07/66195.htm http://blog.csdn.net/sunxingzhesunjinbiao/article/details/42195013 我们知道,在Android系统中,每一个应用程序都运行在独立的进程中,这也保证了当其中一个程序出现异常而不会影响另一个应用程序的正常运转.在许多情况下,我们activity都会与各种系统的service打交道,很显然,我们写的程序中activity与系统serv

[Android] 彻底了解Binder机制原理和底层实现

1.Binder通信机制介绍 这篇文章会先对比Binder机制与Linux的通信机制的差别,了解为什么Android会另起炉灶,采用Binder.接着,会根据 Binder的机制,去理解什么是Service  Manager,在C/S模型中扮演什么角色.最后,会从一次完整的通信活动中,去理解Binder通信的过程. 1.1 Android与Linux通信机制的比较 虽然Android继承使用Linux的内核,但Linux与Android的通信机制不同. 在Linux中使用的IPC通信机制如下:

Android深入浅出之Binder机制

一说明 Android系统最常见也是初学者最难搞明白的就是Binder了,很多很多的Service就是通过Binder机制来和客户端通讯交互的.所以搞明白Binder的话,在很大程度上就能理解程序运行的流程.我们这里将以MediaService的例子来分析Binder的使用:l        ServiceManager,这是Android OS的整个服务的管理程序l        MediaService,这个程序里边注册了提供媒体播放的服务程序MediaPlayerService,我们最后只

Android进程间通信(IPC)机制Binder简介和学习计划

在Android系统,每个应用程序是由多个Activity和Service部件,这些Activity和Service有可能在相同的处理被执行,此外,还可以在不同的过程中进行. 然后.不是在同一个过程Activity或者Service是怎样通信的呢?这就是本文中要介绍的Binder进程间通信机制了. 我们知道,Android系统是基于Linux内核的,而Linux内核继承和兼容了丰富的Unix系统进程间通信(IPC)机制. 有传统的管道(Pipe).信号(Signal)和跟踪(Trace).这三项

转Android进程间通信(IPC)机制Binder简要介绍和学习计划

转自:http://blog.csdn.net/luoshengyang/article/details/6618363/ 在Android系统中,每一个应用程序都是由一些Activity和Service组成的,这些Activity和Service有可能运行在同一个进程中,也有可能运行在不同的进程中.那么,不在同一个进程的Activity或者Service是如何通信的呢?这就是本文中要介绍的Binder进程间通信机制了. <Android系统源代码情景分析>一书正在进击的程序员网(http:/

浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6621566 上一篇文章Android进程间通信(IPC)机制Binder简要介绍和学习计划简要介绍了Android系统进程间通信机制Binder的总体架构,它由Client.Server.Service Manager和驱动程序Binder四个组件构成.本文着重介绍组件Service Manager,它是整个Binder机制的守护进程,用来管理