Binder 简介

Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中一种跨进程通信方式,还可以理解为是一种物理设备,它的设备驱动是 /dev/binder ;从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,等等)和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获得服务器提供的服务或数据,这里的服务包括普通服务和基于 AIDL 的服务。 Android 开发中,Binder主要用在Service中,包括AIDL和Message,Message的底层其实就是AIDL.

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/mac/AndroidStudioProjects/ProcessDemo/app/src/main/aidl/com/example/mac/processdemo/bean/IBookManager.aidl
 */
package com.example.mac.processdemo.bean;
// Declare any non-default types here with import statements

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

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

        /**
         * Cast an IBinder object into an com.example.mac.processdemo.bean.IBookManager interface,
         * generating a proxy if needed.
         */
        public static com.example.mac.processdemo.bean.IBookManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.mac.processdemo.bean.IBookManager))) {
                return ((com.example.mac.processdemo.bean.IBookManager) iin);
            }
            return new com.example.mac.processdemo.bean.IBookManager.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_getBookList: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.example.mac.processdemo.bean.Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    com.example.mac.processdemo.bean.Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.example.mac.processdemo.bean.Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    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;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.mac.processdemo.bean.IBookManager {
            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.util.List<com.example.mac.processdemo.bean.Book> getBookList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.example.mac.processdemo.bean.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.mac.processdemo.bean.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void addBook(com.example.mac.processdemo.bean.Book book) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            /**
             * 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();
                }
            }
        }

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

    public java.util.List<com.example.mac.processdemo.bean.Book> getBookList() throws android.os.RemoteException;

    public void addBook(com.example.mac.processdemo.bean.Book book) throws android.os.RemoteException;

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

上面是系统生成的 .aidl 对应的 java 类,这个类是继承了IInterface的接口,在Binder中传输的接口都需要继承IInterface接口。看一下它的结构,首先它声明了在IBookManager.aidl中定义的两个方法 getBookList 和 addBook,同时它还定义了两个整形的id分别用于标记这两个方法,这两个id用于标识在transact 过程中客户端所请求的到底是哪个方法。接着,它声明了一个内部类Stub,这个Stub就是一个Binder类,当客户端和服务端都处于同一个进程时,方法调用不会走跨进程的transact过程,当两者位于不同进程时,方法调用会走transact过程,这个逻辑由Stub的内部代理类Proxy来完成。

下面详细介绍这两个类和方法:

DESCRIPTOR

Binder的唯一标识,一般用当前类名标识。

asInterface(android.os.IBinder obj)

用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,这种转换过程是区分进程的,如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装后后的Stub.proxy对象。

asBinder

此方法用于返回当前 Binder 对象。

onTransact

这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

服务端通过code可以确定客户端请求的目标方法是什么,接着从data中取出目标方法所需的参数,然后执行目标方法。当目标方法执行完毕后,就向reply中写入返回值,onTransact方法执行结束。注意:如果此方法返回false,那么客户端的请求会失败,可以利用这个特性来做权限验证。

Proxy#getBookList

这个方法运行在客户端,当客户端远程调用这个方法时,首先创建该方法所需要的输入型Parcel对象_data、输出型Parcel对象_reply对象和返回值对象List;然后把该方法的参数写入_data中;接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_replay中取出RPC过程的返回结果;最后返回_reply中的数据。

Proxy#addBook

这个方法运行在客户端,它的运行过程和getBookList是一样的,只是没有返回值。

注意:

(1)客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,耗时操作不能在UI线程中发起远程请求;

(2)由于服务端的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采用同步的方式实现,因为它已经运行在一个线程中了。

linkToDeath 和 unlinkToDeath 方法

Binder运行在服务端进程,如果服务端由于某种原因异常终止,Binder连接断裂(称之为Binder死亡),会导致我们远程调用失败,通过 linkToDeath 可以给Binder设置一个死亡代理,当Binder死亡时,就会收到通知,这个时候可以重新发起连接请求从而恢复连接。

给Binder设置死亡代理

首先声明一个DeathRecipient对象。DeathPecipient是一个借口,其内部只有一个方法 binderDied,需要实现这个方法,当Binder死亡的时候,系统会回调binderDied方法,然后就可以移除之前绑定的binder代理并重新绑定远程服务:

 private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (mBookManager == null)
                return;

            mBookManager.asBinder().unlinkToDeath(deathRecipient,0);
            mBookManager = null;

            //TODO :这里重新绑定远程服务

        }
    };

其次,在客户端绑定远程服务成功后,给binder设置死亡代理:

mService = IMessageBoxManager.Stub.asInterface(binder);
binder.linkToDeath(deathRecipient, 0);

通过上面两个步骤,就给binder设置了死亡代理,当Binder死亡的时候就可以收到通知,通过Binder的方法 isBinderAlive 也可以判断Binder是否死亡。

时间: 2024-10-10 02:40:00

Binder 简介的相关文章

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

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

[gitbook] Android框架分析系列之Android Binder详解

请支持作者原创: https://mr-cao.gitbooks.io/android/content/android-binder.html Android Binder详解 Table of Contents 1. binder简介 2. binder的实现 2.1. IBinder类简介 2.2. IInterface类简介 2.3. BpBinder和BBinder简介 2.4. ProcessState和IPCThreadState简介 2.5. ServiceManager简介 2.

从Activity的启动流程理解Binder

简述 关于Activity启动流程和Binder的文章很多,大多数是分开来讲的,本文将二者结合起来,着重分析启动流程中跨进程方面的细节,其实,启动流程看似调用繁多,主要是复杂在Activity栈管理等方面,如果将其看作一个整体,整个启动流程就简单很多.在启动流程中,App和AMS的跨进程调用是其中的重点,理解了这个,会加深对Binder和启动流程的理解认知,也能窥到Framework层的冰山一角.另外我也发现,很多文章在讲启动流程的时候,关于ActivityMangagerService进程如何

AIDL实现Android IPC

1.AIDL文本解释 在软件工程中,接口定义语言(IDL)已经成为通用术语,是用来描述软件组件接口的特定语言.在Android中,该IDL被称为Android接口定义语言(AIDL),它是纯文本文件,使用Java类似语法编写.但是,编写Java接口的编写AIDL文件还有有些不同的. 首先,对所有的非原始类型参数,需要指定如下三种类型方向指示符之一:in,out,inout.in类型方向指示符只用于输入,客户端不会看到Service对对象的修改.out类型表明输入对象不包含相关的数据,但会由Ser

SpringMVC表单标签简介

转自:SpringMVC表单标签简介 在使用SpringMVC的时候我们可以使用Spring封装的一系列表单标签,这些标签都可以访问到ModelMap中的内容.下面将对这些标签一一介绍. 在正式介绍SpringMVC的表单标签之前,我们需要先在JSP中声明使用的标签,具体做法是在JSP文件的顶部加入以下指令: <%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

转 理解Android系统Binder机制

一.Binder机制概述 在Android开发中,很多时候我们需要用到进程间通信,所谓进程间通信,实现进程间通信的机制有很多种,比如说socket.pipe等,Android中进程间通信的方式主要有三种: 1.标准Linux Kernel IPC 接口: 2.标准D-BUS接口: 3.Binder接口. 其中,Binder机制是使用最且最被认可的,因为Binder机制有以下优点: 1.相对于其它IPC机制,Binder机制更加简洁和快速: 2.消耗的内存相对更少: 3.传统的IPC机制可能会增加

Android系统Binder机制学习总结

一.Binder机制概述 在Android开发中,很多时候我们需要用到进程间通信,所谓进程间通信,实现进程间通信的机制有很多种,比如说socket.pipe等,Android中进程间通信的方式主要有三种: 1.标准Linux Kernel IPC 接口: 2.标准D-BUS接口: 3.Binder接口. 其中,Binder机制是使用最且最被认可的,因为Binder机制有以下优点: 1.相对于其它IPC机制,Binder机制更加简洁和快速: 2.消耗的内存相对更少: 3.传统的IPC机制可能会增加

【Android 系统开发】 Android 系统启动流程简介

Android 系统启动总结 : Android 系统启动分底层 Linux 内核启动 和 应用系统启动; -- 底层系统启动 : 系统上电, bootloader 启动, linux kernel 启动, init 进程启动; -- 应用系统启动 : init 进程启动关键的进程如 Zygote 进程 和 System Server 等系统服务, 之后进入 Home 界面; 一. Android 底层系统启动流程(Bootloader Kernel init) 1. 系统上电 执行 ROM 引

SpringMVC&lt;from:form&gt;表单标签和&lt;input&gt;表单标签简介 转http://blog.csdn.net/hp_yangpeng/article/details/51906654

SpringMVC<from:form>表单标签和<input>表单标签简介 在使用SpringMVC的时候我们可以使用spring封装的一系列表单标签,这些标签都可以访问到ModelMap中的内容.下面将对这些标签一一介绍. 在正式介绍SpringMVC的表单标签之前,我们需要先在JSP中声明使用的标签,具体做法是在JSP文件的顶部加入以下指令: Jsp代码 <%@taglib uri="http://www.springframework.org/tags/fo