Android跨進(jìn)程通信IPC之5——Binder的三大接口

Android跨進(jìn)程通信IPC整體內(nèi)容如下

本片文章的主要目的是讓大家對Binder有個(gè)初步的了解,既然是初步了解,肯定所是以源碼上的注釋為主夺欲,讓大家對Binder有一個(gè)更直觀的認(rèn)識跪帝。PS:大部分注釋我是寫在類里面了, 重要的我會(huì)單獨(dú)的拿出來些阅。
主要內(nèi)容如下:

1伞剑、IInterface
2、IBinder
3市埋、Binder與BinderProxy類
4黎泣、總結(jié)

一、IInterface

/**
 * Base class for Binder interfaces.  When defining a new interface,
 * you must derive it from IInterface.
 */
public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}

(一)缤谎、類注釋

簡單的翻譯一下:

IInterface是Binder中相關(guān)接口的基類抒倚。 定義新接口的時(shí)候,你必須從IInterface派生坷澡。

(二)托呕、抽象方法注釋

如果想獲取和該接口關(guān)聯(lián)的Binder對象。你必須使用這個(gè)方法來而不是使用一個(gè)簡單的類型轉(zhuǎn)化频敛。這樣代理對象才能返回正確的結(jié)果

(三)项郊、總結(jié)

所以可以這樣說IInterface接口提供了類型轉(zhuǎn)化的功能凡橱,將服務(wù)或者服務(wù)代理類轉(zhuǎn)為IBinder類型辆沦。其實(shí)實(shí)際的類型轉(zhuǎn)換是由BnInterface隧饼、BpInterface兩個(gè)類完成的抹估,BnInterface將服務(wù)類轉(zhuǎn)換成IBinder類型抚笔,而BpInterface則將代理服務(wù)類轉(zhuǎn)換成IBinder類型苟翻。在通過Binder Driver傳遞Binder對象時(shí)衰倦,必須進(jìn)行類型轉(zhuǎn)換花鹅,比如在想系統(tǒng)注冊服務(wù)時(shí)食绿,需要先將服務(wù)類型轉(zhuǎn)換成IBinder侈咕,在其傳遞給Context Manager。

二器紧、IBinder

/**
 * Base interface for a remotable object, the core part of a lightweight
 * remote procedure call mechanism designed for high performance when
 * performing in-process and cross-process calls.  This
 * interface describes the abstract protocol for interacting with a
 * remotable object.  Do not implement this interface directly, instead
 * extend from {@link Binder}.
 * 
 * <p>The key IBinder API is {@link #transact transact()} matched by
 * {@link Binder#onTransact Binder.onTransact()}.  These
 * methods allow you to send a call to an IBinder object and receive a
 * call coming in to a Binder object, respectively.  This transaction API
 * is synchronous, such that a call to {@link #transact transact()} does not
 * return until the target has returned from
 * {@link Binder#onTransact Binder.onTransact()}; this is the
 * expected behavior when calling an object that exists in the local
 * process, and the underlying inter-process communication (IPC) mechanism
 * ensures that these same semantics apply when going across processes.
 * 
 * <p>The data sent through transact() is a {@link Parcel}, a generic buffer
 * of data that also maintains some meta-data about its contents.  The meta
 * data is used to manage IBinder object references in the buffer, so that those
 * references can be maintained as the buffer moves across processes.  This
 * mechanism ensures that when an IBinder is written into a Parcel and sent to
 * another process, if that other process sends a reference to that same IBinder
 * back to the original process, then the original process will receive the
 * same IBinder object back.  These semantics allow IBinder/Binder objects to
 * be used as a unique identity (to serve as a token or for other purposes)
 * that can be managed across processes.
 * 
 * <p>The system maintains a pool of transaction threads in each process that
 * it runs in.  These threads are used to dispatch all
 * IPCs coming in from other processes.  For example, when an IPC is made from
 * process A to process B, the calling thread in A blocks in transact() as
 * it sends the transaction to process B.  The next available pool thread in
 * B receives the incoming transaction, calls Binder.onTransact() on the target
 * object, and replies with the result Parcel.  Upon receiving its result, the
 * thread in process A returns to allow its execution to continue.  In effect,
 * other processes appear to use as additional threads that you did not create
 * executing in your own process.
 * 
 * <p>The Binder system also supports recursion across processes.  For example
 * if process A performs a transaction to process B, and process B while
 * handling that transaction calls transact() on an IBinder that is implemented
 * in A, then the thread in A that is currently waiting for the original
 * transaction to finish will take care of calling Binder.onTransact() on the
 * object being called by B.  This ensures that the recursion semantics when
 * calling remote binder object are the same as when calling local objects.
 * 
 * <p>When working with remote objects, you often want to find out when they
 * are no longer valid.  There are three ways this can be determined:
 * <ul>
 * <li> The {@link #transact transact()} method will throw a
 * {@link RemoteException} exception if you try to call it on an IBinder
 * whose process no longer exists.
 * <li> The {@link #pingBinder()} method can be called, and will return false
 * if the remote process no longer exists.
 * <li> The {@link #linkToDeath linkToDeath()} method can be used to register
 * a {@link DeathRecipient} with the IBinder, which will be called when its
 * containing process goes away.
 * </ul>
 * 
 * @see Binder
 */
public interface IBinder {
    /**
     * The first transaction code available for user commands.
     * 第一個(gè)可用于用戶命令的事務(wù)代碼耀销。
     */
    int FIRST_CALL_TRANSACTION  = 0x00000001;
    /**
     * The last transaction code available for user commands.
     * 最后一個(gè)可用于用戶命令的事務(wù)代碼。
     */
    int LAST_CALL_TRANSACTION   = 0x00ffffff;
    
    /**
     * IBinder protocol transaction code: pingBinder().
     * IBinder協(xié)議事物碼:在pingBinder()會(huì)用到
     */
    int PING_TRANSACTION        = ('_'<<24)|('P'<<16)|('N'<<8)|'G';
    
    /**
     * IBinder protocol transaction code: dump internal state.
     * IBinder協(xié)議事物碼: 代表清除內(nèi)部狀態(tài) 
     */
    int DUMP_TRANSACTION        = ('_'<<24)|('D'<<16)|('M'<<8)|'P';
    
    /**
     * IBinder protocol transaction code: execute a shell command.
     * IBinder協(xié)議事物碼:代表執(zhí)行一個(gè)shell命令
     * @hide
     */
    int SHELL_COMMAND_TRANSACTION = ('_'<<24)|('C'<<16)|('M'<<8)|'D';

    /**
     * IBinder protocol transaction code: interrogate the recipient side
     * of the transaction for its canonical interface descriptor.
     *  IBinder協(xié)議事物碼:代表詢問被調(diào)用方的接口描述符號
     */
    int INTERFACE_TRANSACTION   = ('_'<<24)|('N'<<16)|('T'<<8)|'F';

    /**
     * IBinder protocol transaction code: send a tweet to the target
     * object.  The data in the parcel is intended to be delivered to
     * a shared messaging service associated with the object; it can be
     * anything, as long as it is not more than 130 UTF-8 characters to
     * conservatively fit within common messaging services.  As part of
     * {@link Build.VERSION_CODES#HONEYCOMB_MR2}, all Binder objects are
     * expected to support this protocol for fully integrated tweeting
     * across the platform.  To support older code, the default implementation
     * logs the tweet to the main log as a simple emulation of broadcasting
     * it publicly over the Internet.
     * 
     * <p>Also, upon completing the dispatch, the object must make a cup
     * of tea, return it to the caller, and exclaim "jolly good message
     * old boy!".
     * IBinder協(xié)議事物碼:向目標(biāo)對象發(fā)出一個(gè)呼叫铲汪。在parcel中的數(shù)據(jù)是用于
     * 分發(fā)一個(gè)與對象結(jié)合的共享信息服務(wù)熊尉。它可以是任何東西,只要它不超
     * 過130個(gè)UTF-8字符掌腰,保證適用于常見的信息服務(wù)狰住。 作為 
     * Build.VERSION_CODES#HONEYCOMB_MR2的一部分,所有的binder
     * 對象都支持這個(gè)協(xié)議齿梁,為了在跨平臺間完整推送同時(shí)也為了支持舊的交
     * 互碼催植,一個(gè)默認(rèn)的實(shí)現(xiàn)是在主日志中記錄了一個(gè)推送肮蛹,作為廣播的一個(gè)
     * 簡單模仿。
     * 并且创南,為了完成消息的派送伦忠,對象必須返回給調(diào)用者一個(gè)說明,
     * 表明是舊的信息稿辙。
     */
    int TWEET_TRANSACTION   = ('_'<<24)|('T'<<16)|('W'<<8)|'T';

    /**
     * IBinder protocol transaction code: tell an app asynchronously that the
     * caller likes it.  The app is responsible for incrementing and maintaining
     * its own like counter, and may display this value to the user to indicate the
     * quality of the app.  This is an optional command that applications do not
     * need to handle, so the default implementation is to do nothing.
     * 
     * <p>There is no response returned and nothing about the
     * system will be functionally affected by it, but it will improve the
     * app's self-esteem.
     * IBinder協(xié)議事物碼:異步地告訴app 有一個(gè)調(diào)用者在呼叫它昆码。這個(gè)app負(fù)
     * 責(zé)計(jì)算和維護(hù)自己的呼叫者數(shù)目。 并且可以展示這個(gè)值來告訴用戶app
     * 的狀態(tài)邻储。這個(gè)是可選的命令赋咽,app不需要掌管它,所以默認(rèn)是實(shí)現(xiàn)是什
     * 么都不做吨娜。
     * 這是沒有響應(yīng)的脓匿,并且不會(huì)對系統(tǒng)帶來影響,但是它提高了app的自控
     * (我真的不知道怎么翻譯宦赠,elf-esteem其實(shí)是自尊的意思)
     */
    int LIKE_TRANSACTION   = ('_'<<24)|('L'<<16)|('I'<<8)|'K';

    /** @hide */
    //隱藏的API
    int SYSPROPS_TRANSACTION = ('_'<<24)|('S'<<16)|('P'<<8)|'R';

    /**
     * Flag to {@link #transact}: this is a one-way call, meaning that the
     * caller returns immediately, without waiting for a result from the
     * callee. Applies only if the caller and callee are in different
     * processes.
     * 用于transact()方法中的flag亦镶,表示單向RPC,表明呼叫者會(huì)馬上返回袱瓮,
     * 不必等結(jié)果從被呼叫者返回。只有當(dāng)呼叫者和被呼叫者在不同的進(jìn)程中
     * 才有效.
     */
    int FLAG_ONEWAY             = 0x00000001;

    /**
     * Limit that should be placed on IPC sizes to keep them safely under the
     * transaction buffer limit.
     * @hide
     * 為了讓其安全地保持在事物緩沖區(qū)限制之下爱咬,應(yīng)該限制IPC的大小
     *  隱藏的API
     */
    public static final int MAX_IPC_SIZE = 64 * 1024;

    /**
     * Get the canonical name of the interface supported by this binder.
     *  獲取一個(gè)支持binder的接口規(guī)范名稱
     */
    public String getInterfaceDescriptor() throws RemoteException;

    /**
     * Check to see if the object still exists.
     * 
     * @return Returns false if the
     * hosting process is gone, otherwise the result (always by default
     * true) returned by the pingBinder() implementation on the other
     * side.
     * 檢查對象是否仍然存在尺借。
     * 如果返回false,主機(jī)進(jìn)程消失精拟,否則結(jié)果為true(始終默認(rèn)true)由對
     * 手方來實(shí)現(xiàn)pingBinder()這個(gè)方法燎斩。
     */
    public boolean pingBinder();

    /**
     * Check to see if the process that the binder is in is still alive.
     *
     * @return false if the process is not alive.  Note that if it returns
     * true, the process may have died while the call is returning.
     * 檢查該binder所在的進(jìn)程是否仍然存在
     * 如果進(jìn)程不存在,則返回false蜂绎。 請注意栅表,如果返回true,則調(diào)用返回時(shí)
     * 進(jìn)程可能已經(jīng)死機(jī)师枣。
     */
    public boolean isBinderAlive();
    
    /**
     * Attempt to retrieve a local implementation of an interface
     * for this Binder object.  If null is returned, you will need
     * to instantiate a proxy class to marshall calls through
     * the transact() method.
     */
    public IInterface queryLocalInterface(String descriptor);

    /**
     * Print the object's state into the given stream.
     * 
     * @param fd The raw file descriptor that the dump is being sent to.
     * @param args additional arguments to the dump request.
     */
    public void dump(FileDescriptor fd, String[] args) throws RemoteException;

    /**
     * Like {@link #dump(FileDescriptor, String[])} but always executes
     * asynchronously.  If the object is local, a new thread is created
     * to perform the dump.
     *
     * @param fd The raw file descriptor that the dump is being sent to.
     * @param args additional arguments to the dump request.
     */
    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;

    /**
     * Execute a shell command on this object.  This may be performed asynchrously from the caller;
     * the implementation must always call resultReceiver when finished.
     *
     * @param in The raw file descriptor that an input data stream can be read from.
     * @param out The raw file descriptor that normal command messages should be written to.
     * @param err The raw file descriptor that command error messages should be written to.
     * @param args Command-line arguments.
     * @param resultReceiver Called when the command has finished executing, with the result code.
     * @hide
     */
    public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ResultReceiver resultReceiver) throws RemoteException;

    /**
     * Perform a generic operation with the object.
     * 
     * @param code The action to perform.  This should
     * be a number between {@link #FIRST_CALL_TRANSACTION} and
     * {@link #LAST_CALL_TRANSACTION}.
     * @param data Marshalled data to send to the target.  Must not be null.
     * If you are not sending any data, you must create an empty Parcel
     * that is given here.
     * @param reply Marshalled data to be received from the target.  May be
     * null if you are not interested in the return value.
     * @param flags Additional operation flags.  Either 0 for a normal
     * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
     */
    public boolean transact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException;

    /**
     * Interface for receiving a callback when the process hosting an IBinder
     * has gone away.
     * 
     * @see #linkToDeath
     */
    public interface DeathRecipient {
        public void binderDied();
    }

    /**
     * Register the recipient for a notification if this binder
     * goes away.  If this binder object unexpectedly goes away
     * (typically because its hosting process has been killed),
     * then the given {@link DeathRecipient}'s
     * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
     * will be called.
     * 
     * <p>You will only receive death notifications for remote binders,
     * as local binders by definition can't die without you dying as well.
     * 
     * @throws RemoteException if the target IBinder's
     * process has already died.
     * 
     * @see #unlinkToDeath
     */
    public void linkToDeath(DeathRecipient recipient, int flags)
            throws RemoteException;

    /**
     * Remove a previously registered death notification.
     * The recipient will no longer be called if this object
     * dies.
     * 
     * @return {@code true} if the <var>recipient</var> is successfully
     * unlinked, assuring you that its
     * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
     * will not be called;  {@code false} if the target IBinder has already
     * died, meaning the method has been (or soon will be) called.
     * 
     * @throws java.util.NoSuchElementException if the given
     * <var>recipient</var> has not been registered with the IBinder, and
     * the IBinder is still alive.  Note that if the <var>recipient</var>
     * was never registered, but the IBinder has already died, then this
     * exception will <em>not</em> be thrown, and you will receive a false
     * return value instead.
     */
    public boolean unlinkToDeath(DeathRecipient recipient, int flags);
}

注釋有點(diǎn)多怪瓶,我們一個(gè)一個(gè)來

(一)、類注釋

簡單的翻譯一下:

  • 一個(gè)遠(yuǎn)程對象的基接口践美,是為高性能而設(shè)計(jì)的輕量級遠(yuǎn)程調(diào)用機(jī)制的核心部分洗贰,它不僅用于遠(yuǎn)程調(diào)用,也可以用于進(jìn)程內(nèi)調(diào)用陨倡。這個(gè)接口描述了與遠(yuǎn)程對象進(jìn)行交互的抽象協(xié)議敛滋。建議繼承Binder類,而不是直接實(shí)現(xiàn)這個(gè)接口兴革。
    IBinder的主要API是transact()绎晃,與它對應(yīng)另一個(gè)方法是Binder.onTransact蜜唾。第一個(gè)方法使你可以向遠(yuǎn)端的IBinder對象發(fā)送調(diào)用,第二個(gè)方法使你自己的遠(yuǎn)程對象能夠響應(yīng)接收到的調(diào)用庶艾。IBinder的API都是同步執(zhí)行的袁余,比如transact()直到對方的Binder.onTransact()方法調(diào)用完成后才返回。而在跨進(jìn)程的時(shí)候落竹,在IPC的幫助下泌霍,也是同樣的效果。
    通過transact()發(fā)送的數(shù)據(jù)是Parcel述召,Parcel是一種一般的緩沖區(qū)朱转,除了有數(shù)據(jù)外還帶有一些描述它內(nèi)容的元數(shù)據(jù)。元數(shù)據(jù)用于管理IBinder對象的引用积暖,這樣就能在緩沖去從一個(gè)進(jìn)程移動(dòng)到另一個(gè)進(jìn)程時(shí)藤为,保存這些引用。這樣就保證了當(dāng)一個(gè)IBinder被寫入到Parcel并發(fā)送到另一個(gè)進(jìn)程中夺刑,如果另一個(gè)進(jìn)程把同一個(gè)IBinder的引用回發(fā)到原來的進(jìn)程缅疟,那么這個(gè)原來的進(jìn)程就能接收到發(fā)出的那個(gè)IBinder的引用。這種機(jī)制使IBinder和Binder像唯一標(biāo)志符那樣在進(jìn)程間管理遍愿。
    系統(tǒng)為每一個(gè)進(jìn)程維持一個(gè)存放交互的線程池存淫。這些交互的線程用于派發(fā)所有從其他進(jìn)程發(fā)來的IPC調(diào)用。例如:當(dāng)一個(gè)IPC從進(jìn)程A發(fā)到進(jìn)程B沼填,A中那個(gè)發(fā)出調(diào)用的線程就阻塞在transact()中了桅咆。進(jìn)程B中的交互線程池的一個(gè)線程池接收了這個(gè)調(diào)用,它調(diào)用Binder.onTransact()坞笙,完成后用一個(gè)Parcel來作為結(jié)果返回岩饼。然后進(jìn)程A中的那個(gè)等待線程在收到返回的Parcel才能繼續(xù)執(zhí)行。實(shí)際上薛夜,另一個(gè)進(jìn)程看起來就像當(dāng)前進(jìn)程的一個(gè)線程籍茧,但不是當(dāng)前進(jìn)程創(chuàng)建的。
    Binder機(jī)制還支持進(jìn)程間的遞歸調(diào)用梯澜。例如寞冯,進(jìn)程A執(zhí)行自己的IBinder的transact()調(diào)用進(jìn)程B的Binder,而進(jìn)程B在其Binder.onTransact()中又用transact()向進(jìn)程A發(fā)起調(diào)用,那么進(jìn)程A在等待它發(fā)布出的調(diào)用返回的同時(shí)晚伙,還會(huì)用Binder.onTransact()響應(yīng)進(jìn)程B的transact()简十。總之撬腾,Binder造成的結(jié)果就是讓我們感覺到跨進(jìn)程的調(diào)用與進(jìn)程內(nèi)的調(diào)用沒有什么區(qū)別螟蝙。
    當(dāng)操作遠(yuǎn)程對象的時(shí)候,你需要經(jīng)常查看它們是否有效民傻,有3種方法可以使用:
    • 1 transact()方法將在IBinder所在的進(jìn)程不存在時(shí)拋出RemoteException異常
    • 2 如果目標(biāo)進(jìn)程不存在胰默,那么調(diào)用pingBinder()時(shí)返回false\
    • 3 可以用linkToDeath()方法向IBinder注冊一個(gè)IBinder.DeathRecipient场斑,在IBinder代表的進(jìn)程退出時(shí)被調(diào)用。

(二)牵署、重要方法注釋

1漏隐、queryLocalInterface(String descriptor) 方法
    /**
     * Attempt to retrieve a local implementation of an interface
     * for this Binder object.  If null is returned, you will need
     * to instantiate a proxy class to marshall calls through
     * the transact() method.
     */
    public IInterface queryLocalInterface(String descriptor);

翻譯如下:

用于接收一個(gè)用于當(dāng)前binder對象的本地接口的實(shí)現(xiàn)。如果返回null奴迅,你需要通過transact()方法去實(shí)例化一個(gè)代理類青责。

2、dump(FileDescriptor fd, String[] args) 方法
    /**
     * Print the object's state into the given stream.
     * 
     * @param fd The raw file descriptor that the dump is being sent to.
     * @param args additional arguments to the dump request.
     */
    public void dump(FileDescriptor fd, String[] args) throws RemoteException;

翻譯如下:

將對象狀態(tài)打印入給定的數(shù)據(jù)流中.

  • 入?yún)d:轉(zhuǎn)儲(chǔ)發(fā)送到的原始文件描述符取具。
  • 入?yún)rgs: 轉(zhuǎn)儲(chǔ)請求的附加參數(shù)
3脖隶、dumpAsync(FileDescriptor fd, String[] args) 方法
    /**
     * Like {@link #dump(FileDescriptor, String[])} but always executes
     * asynchronously.  If the object is local, a new thread is created
     * to perform the dump.
     *
     * @param fd The raw file descriptor that the dump is being sent to.
     * @param args additional arguments to the dump request.
     */
    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;

翻譯如下:

類似dump(FileDescriptor, String[])方法,但是總是異步執(zhí)行暇检。如果對象在本地产阱, 一個(gè)新的線程將會(huì)被創(chuàng)建去執(zhí)行這個(gè)操作。

  • 入?yún)d:轉(zhuǎn)儲(chǔ)發(fā)送到的原始文件描述符块仆。
  • 入?yún)rgs: 轉(zhuǎn)儲(chǔ)請求的附加參數(shù)
4构蹬、shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,String[] args, ResultReceiver resultReceiver) 方法
    /**
     * Execute a shell command on this object.  This may be performed asynchrously from the caller;
     * the implementation must always call resultReceiver when finished.
     *
     * @param in The raw file descriptor that an input data stream can be read from.
     * @param out The raw file descriptor that normal command messages should be written to.
     * @param err The raw file descriptor that command error messages should be written to.
     * @param args Command-line arguments.
     * @param resultReceiver Called when the command has finished executing, with the result code.
     * @hide
     */
    public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,String[] args, ResultReceiver resultReceiver) throws RemoteException;

翻譯如下:

對此對象執(zhí)行shell命令。 可以異步執(zhí)行; 執(zhí)行完畢后必須始終調(diào)用resultReceiver悔据。

  • 入?yún)n:可以讀取輸入數(shù)據(jù)流的原始文件描述符庄敛。
  • 入?yún)ut: 正常命令消息應(yīng)寫入的原始文件描述符。
  • 入?yún)rr:命令錯(cuò)誤消息應(yīng)寫入的原始文件描述符科汗。
  • 入?yún)rgs: 命令行參數(shù)铐姚。
  • 入?yún)esultReceiver: 當(dāng)命令執(zhí)行結(jié)束后,使用結(jié)果代碼調(diào)用肛捍。
5、transact(int code, Parcel data, Parcel reply, int flags)方法
    /**
     * Perform a generic operation with the object.
     * 
     * @param code The action to perform.  This should
     * be a number between {@link #FIRST_CALL_TRANSACTION} and
     * {@link #LAST_CALL_TRANSACTION}.
     * @param data Marshalled data to send to the target.  Must not be null.
     * If you are not sending any data, you must create an empty Parcel
     * that is given here.
     * @param reply Marshalled data to be received from the target.  May be
     * null if you are not interested in the return value.
     * @param flags Additional operation flags.  Either 0 for a normal
     * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
     */
    public boolean transact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException;

翻譯如下:

對對象執(zhí)行一個(gè)通用的操作

  • 入?yún)ode:操作碼必須在FIRST_CALL_TRANSACTION和LAST_CALL_TRANSACTION之間
  • 入?yún)ata: 傳輸給目標(biāo)的數(shù)據(jù)之众。如果你沒有傳輸任何數(shù)據(jù)拙毫,你必須創(chuàng)建一個(gè)空的Parcel
  • 入?yún)eply:從目標(biāo)接收的數(shù)據(jù)」缀蹋可以是null如果你對返回的值不感興趣缀蹄。
  • 入?yún)lags: 附加操作標(biāo)志。0是指普通的RPC膘婶∪鼻埃或者FLAG_ONEWAY,指單向RPC悬襟。
6衅码、linkToDeath(DeathRecipient recipient, int flags)方法
    /**
     * Register the recipient for a notification if this binder
     * goes away.  If this binder object unexpectedly goes away
     * (typically because its hosting process has been killed),
     * then the given {@link DeathRecipient}'s
     * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
     * will be called.
     * 
     * <p>You will only receive death notifications for remote binders,
     * as local binders by definition can't die without you dying as well.
     * 
     * @throws RemoteException if the target IBinder's
     * process has already died.
     * 
     * @see #unlinkToDeath
     */
    public void linkToDeath(DeathRecipient recipient, int flags)
            throws RemoteException;

翻譯如下:

注冊一個(gè)recipient用于提示binder消失。如果binder對象異常地消失(例如由于主進(jìn)程被殺)脊岳,DeathRecipient中的binderDied會(huì)被調(diào)用.

7逝段、unlinkToDeath(DeathRecipient recipient, int flags)方法
    /**
     * Remove a previously registered death notification.
     * The recipient will no longer be called if this object
     * dies.
     * 
     * @return {@code true} if the <var>recipient</var> is successfully
     * unlinked, assuring you that its
     * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
     * will not be called;  {@code false} if the target IBinder has already
     * died, meaning the method has been (or soon will be) called.
     * 
     * @throws java.util.NoSuchElementException if the given
     * <var>recipient</var> has not been registered with the IBinder, and
     * the IBinder is still alive.  Note that if the <var>recipient</var>
     * was never registered, but the IBinder has already died, then this
     * exception will <em>not</em> be thrown, and you will receive a false
     * return value instead.
     */
    public boolean unlinkToDeath(DeathRecipient recipient, int flags);
}

翻譯如下:

刪除以前注冊的死亡通知垛玻。 如果對象死亡,則recipient不再會(huì)被調(diào)用

(三)奶躯、內(nèi)部接口注釋

1帚桩、DeathRecipient(int code, Parcel data, Parcel reply, int flags)方法
   /**
     * Interface for receiving a callback when the process hosting an IBinder
     * has gone away.
     * 
     * @see #linkToDeath
     */
    public interface DeathRecipient {
        public void binderDied();
    }

翻譯如下:

當(dāng)持有IBinder進(jìn)程消失,會(huì)回調(diào)這個(gè)接口

(四)嘹黔、總結(jié):

通過上面對IBinder注釋账嚎,我們大概可以知道以下信息

  • 1、IBindre是遠(yuǎn)程對象的基接口儡蔓,不僅可以在跨進(jìn)程可以調(diào)用郭蕉,也可以在進(jìn)程內(nèi)部調(diào)用
  • 2、在遠(yuǎn)程調(diào)用的時(shí)候浙值,一端用IBinder.transact()發(fā)送恳不,另一端用Binder的Binder.onTransact()接受,并且是同步的
  • 3开呐、transact()方法發(fā)送的是Parcel烟勋。
  • 4、系統(tǒng)為每個(gè)進(jìn)程維護(hù)一個(gè)進(jìn)行跨進(jìn)程調(diào)用的線程池筐付。
  • 5卵惦、可以使用pingBinder()方法來檢測目標(biāo)進(jìn)程是否存在
  • 6、可以調(diào)用linkToDeath()來向IBinder注冊一個(gè)IBinder.DeathRecipien瓦戚。用于目標(biāo)進(jìn)程退出時(shí)候的提醒沮尿。
  • 7、建議繼承Binder類较解,而不是直接實(shí)現(xiàn)這個(gè)接口畜疾。

三、Binder與BinderProxy類

(一)印衔、Binder

/**
 * Base class for a remotable object, the core part of a lightweight
 * remote procedure call mechanism defined by {@link IBinder}.
 * This class is an implementation of IBinder that provides
 * standard local implementation of such an object.
 *
 * <p>Most developers will not implement this class directly, instead using the
 * <a href="{@docRoot}guide/components/aidl.html">aidl</a> tool to describe the desired
 * interface, having it generate the appropriate Binder subclass.  You can,
 * however, derive directly from Binder to implement your own custom RPC
 * protocol or simply instantiate a raw Binder object directly to use as a
 * token that can be shared across processes.
 *
 * <p>This class is just a basic IPC primitive; it has no impact on an application's
 * lifecycle, and is valid only as long as the process that created it continues to run.
 * To use this correctly, you must be doing so within the context of a top-level
 * application component (a {@link android.app.Service}, {@link android.app.Activity},
 * or {@link android.content.ContentProvider}) that lets the system know your process
 * should remain running.</p>
 *
 * <p>You must keep in mind the situations in which your process
 * could go away, and thus require that you later re-create a new Binder and re-attach
 * it when the process starts again.  For example, if you are using this within an
 * {@link android.app.Activity}, your activity's process may be killed any time the
 * activity is not started; if the activity is later re-created you will need to
 * create a new Binder and hand it back to the correct place again; you need to be
 * aware that your process may be started for another reason (for example to receive
 * a broadcast) that will not involve re-creating the activity and thus run its code
 * to create a new Binder.</p>
 *
 * @see IBinder
 */
public class Binder implements IBinder {
    /*
     * Set this flag to true to detect anonymous, local or member classes
     * that extend this Binder class and that are not static. These kind
     * of classes can potentially create leaks.
     * 通過設(shè)置這個(gè)標(biāo)記來檢測是否是Binder的匿名內(nèi)部類啡捶,或者Binder的
     * 本地內(nèi)部類,因?yàn)檫@些類可能會(huì)存在潛在的內(nèi)存泄露  handler里面也
     * 有這段話哦~
     */
    private static final boolean FIND_POTENTIAL_LEAKS = false;
    private static final boolean CHECK_PARCEL_SIZE = false;
    static final String TAG = "Binder";

    /** @hide */
    public static boolean LOG_RUNTIME_EXCEPTION = false; // DO NOT SUBMIT WITH TRUE

    /**
     * Control whether dump() calls are allowed.
     * 控制是否允許dump()方法的調(diào)用奸焙。
     */
    private static String sDumpDisabled = null;

    /**
     * Global transaction tracker instance for this process.
     * 進(jìn)程的全局事務(wù)跟蹤器實(shí)例瞎暑。
     */
    private static TransactionTracker sTransactionTracker = null;

    // Transaction tracking code.
    // 事務(wù)跟蹤代碼

    /**
     * Flag indicating whether we should be tracing transact calls.
     * 標(biāo)志, 表示我們是否應(yīng)該跟蹤事務(wù)調(diào)用与帆。
     */
    private static boolean sTracingEnabled = false;

    /**
     * Enable Binder IPC tracing.
     * 啟動(dòng) Binder IPC 跟蹤
     * @hide
     */
    public static void  enableTracing() {
        sTracingEnabled = true;
    };

    /**
     * Disable Binder IPC tracing.
     * 關(guān)閉 Binder IPC 跟蹤
     * @hide
     */
    public static void  disableTracing() {
        sTracingEnabled = false;
    }

    /**
     * Check if binder transaction tracing is enabled.
     * 檢查 Binder的事務(wù)跟蹤是否已啟用
     * @hide
     */
    public static boolean isTracingEnabled() {
        return sTracingEnabled;
    }

    /**
     * Get the binder transaction tracker for this process.
     * 獲取此進(jìn)程的 Binder 事務(wù)跟蹤器了赌。
     * @hide
     */
    public synchronized static TransactionTracker getTransactionTracker() {
        if (sTransactionTracker == null)
            sTransactionTracker = new TransactionTracker();
        return sTransactionTracker;
    }

    /* mObject is used by native code, do not remove or rename */
    // mObject 會(huì)被Native 代碼調(diào)用,不要?jiǎng)h除或重命名
    private long mObject;
    private IInterface mOwner;
    private String mDescriptor;

    /**
     * Return the ID of the process that sent you the current transaction
     * that is being processed.  This pid can be used with higher-level
     * system services to determine its identity and check permissions.
     * If the current thread is not currently executing an incoming transaction,
     * then its own pid is returned.
     * 返回向您發(fā)送正在處理的當(dāng)前事務(wù)的進(jìn)程的ID玄糟。 該pid可以與更高級
     * 別的系統(tǒng)服務(wù)一起使用勿她,以確定其身份和檢查權(quán)限。 如果當(dāng)前線程當(dāng)
     * 前沒有執(zhí)行傳入事務(wù)阵翎,則返回其自己的pid嫂拴。
     */
    public static final native int getCallingPid();
    
    /**
     * Return the Linux uid assigned to the process that sent you the
     * current transaction that is being processed.  This uid can be used with
     * higher-level system services to determine its identity and check
     * permissions.  If the current thread is not currently executing an
     * incoming transaction, then its own uid is returned.
     * 將分配給您的Linux uid返回給向您發(fā)送正在處理的當(dāng)前事務(wù)的進(jìn)程播揪。
     * 這個(gè)uid可以與更高級別的系統(tǒng)服務(wù)一起使用,以確定其身份和檢查
     * 權(quán)限筒狠。 如果當(dāng)前線程當(dāng)前沒有執(zhí)行傳入事務(wù)猪狈,則返回其自己的uid。
     */
    public static final native int getCallingUid();

    /**
     * Return the UserHandle assigned to the process that sent you the
     * current transaction that is being processed.  This is the user
     * of the caller.  It is distinct from {@link #getCallingUid()} in that a
     * particular user will have multiple distinct apps running under it each
     * with their own uid.  If the current thread is not currently executing an
     * incoming transaction, then its own UserHandle is returned.
     * 返回分配給發(fā)送給正在處理的當(dāng)前事務(wù)的進(jìn)程的UserHandle辩恼。 這是
     * 呼叫者的用戶雇庙。 與getCallingUid()不同,特定用戶將具有多個(gè)不同的
     * 應(yīng)用程序灶伊,每個(gè)應(yīng)用程序都具有自己的uid疆前。 如果當(dāng)前線程當(dāng)前沒有
     * 執(zhí)行傳入事務(wù),則返回其自己的UserHandle聘萨。
     */
    public static final UserHandle getCallingUserHandle() {
        return UserHandle.of(UserHandle.getUserId(getCallingUid()));
    }

    /**
     * Reset the identity of the incoming IPC on the current thread.  This can
     * be useful if, while handling an incoming call, you will be calling
     * on interfaces of other objects that may be local to your process and
     * need to do permission checks on the calls coming into them (so they
     * will check the permission of your own local process, and not whatever
     * process originally called you).
     * 重置當(dāng)前線程的IPC的身份竹椒。 如果在處理來電時(shí),您將會(huì)調(diào)用
     * 其他對象的接口米辐,這些對象可能在本地進(jìn)程中胸完,并且需要對其中的調(diào)
     * 用進(jìn)行權(quán)限檢查(不管原來的進(jìn)程是如何調(diào)用你的,他們都將將檢查
     * 您自己進(jìn)程的的訪問權(quán)限)翘贮。
     *  //最后一句話我實(shí)在是翻譯不好
     * @return Returns an opaque token that can be used to restore the
     * original calling identity by passing it to
     * {@link #restoreCallingIdentity(long)}.
     *
     *  返回一個(gè)不透明的token赊窥,通過restoreCallingIdentity(long)這個(gè)方法
     *  可以恢復(fù)原始呼叫的身份標(biāo)識
     * @see #getCallingPid()
     * @see #getCallingUid()
     * @see #restoreCallingIdentity(long)
     */
    public static final native long clearCallingIdentity();

    /**
     * Restore the identity of the incoming IPC on the current thread
     * back to a previously identity that was returned by {@link
     * #clearCallingIdentity}.
     *  恢復(fù)之前當(dāng)前線程上的傳入IPC的身份標(biāo)識薯鼠。這個(gè)身份標(biāo)識是由
     *  clearCallingIdentity()方法改變的
     * @param token The opaque token that was previously returned by
     * {@link #clearCallingIdentity}.
     * token 參數(shù)是  以前由{@link #clearCallingIdentity}返回的 tocken
     *
     * @see #clearCallingIdentity
     */
    public static final native void restoreCallingIdentity(long token);

    /**
     * Sets the native thread-local StrictMode policy mask.
     *  設(shè)置 native層線程的StrictMode策略掩碼乞而。
     * <p>The StrictMode settings are kept in two places: a Java-level
     * threadlocal for libcore/Dalvik, and a native threadlocal (set
     * here) for propagation via Binder calls.  This is a little
     * unfortunate, but necessary to break otherwise more unfortunate
     * dependencies either of Dalvik on Android, or Android
     * native-only code on Dalvik.
     *
     *  StrictMode設(shè)置保存在兩個(gè)地方:Java級別的 本地線程  在libcore / Dalvik中進(jìn)行設(shè)置,
     * 和 native的 本地線程則通過Binder調(diào)用來設(shè)置离熏。 這有點(diǎn)兒不幸芍耘,但總
     * 比依賴于Android上的Dalvik或者Android上Dalvik的native-only代碼要好
     * @see StrictMode
     * @hide
     */
    public static final native void setThreadStrictModePolicy(int policyMask);

    /**
     * Gets the current native thread-local StrictMode policy mask.
     * 獲取當(dāng)前native 的StrictMode策略掩碼
     * @see #setThreadStrictModePolicy
     * @hide
     */
    public static final native int getThreadStrictModePolicy();

    /**
     * Flush any Binder commands pending in the current thread to the kernel
     * driver.  This can be
     * useful to call before performing an operation that may block for a long
     * time, to ensure that any pending object references have been released
     * in order to prevent the process from holding on to objects longer than
     * it needs to.
     * 將當(dāng)前線程中的Binder命令刷新到內(nèi)核驅(qū)動(dòng)程序中址遇。這在執(zhí)行可能會(huì)
     * 長時(shí)間阻塞的操作之前調(diào)用是有用的,因?yàn)檫@樣可以確保已經(jīng)釋放了
     * 任何掛起的對象引用斋竞,以防止進(jìn)程持續(xù)到比需要的對象更長的時(shí)間倔约。
     */
    public static final native void flushPendingCommands();
    
    /**
     * Add the calling thread to the IPC thread pool.  This function does
     * not return until the current process is exiting.
    * 將調(diào)用線程添加到IPC線程池。 此方法在當(dāng)前進(jìn)程退出之前不返回窃页。
     */
    public static final native void joinThreadPool();

    /**
     * Returns true if the specified interface is a proxy.
     * 如果指定的接口是代理,則返回true复濒。
     * @hide
     */
    public static final boolean isProxy(IInterface iface) {
        return iface.asBinder() != iface;
    }

    /**
     * Call blocks until the number of executing binder threads is less
     * than the maximum number of binder threads allowed for this process.
     * 調(diào)用塊直到執(zhí)行綁定線程數(shù)量小于此進(jìn)程允許的綁定線程的最大數(shù)量脖卖。
     * @hide
     */
    public static final native void blockUntilThreadAvailable();

    /**
     * Default constructor initializes the object.
     */
    public Binder() {
        init();

        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Binder> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
    }
    
    /**
     * Convenience method for associating a specific interface with the Binder.
     * After calling, queryLocalInterface() will be implemented for you
     * to return the given owner IInterface when the corresponding
     * descriptor is requested.
     */
    public void attachInterface(IInterface owner, String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }
    
    /**
     * Default implementation returns an empty interface name.
     */
    public String getInterfaceDescriptor() {
        return mDescriptor;
    }

    /**
     * Default implementation always returns true -- if you got here,
     * the object is alive.
     */
    public boolean pingBinder() {
        return true;
    }

    /**
     * {@inheritDoc}
     *
     * Note that if you're calling on a local binder, this always returns true
     * because your process is alive if you're calling it.
     */
    public boolean isBinderAlive() {
        return true;
    }
    
    /**
     * Use information supplied to attachInterface() to return the
     * associated IInterface if it matches the requested
     * descriptor.
     */
    public IInterface queryLocalInterface(String descriptor) {
        if (mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }

    /**
     * Control disabling of dump calls in this process.  This is used by the system
     * process watchdog to disable incoming dump calls while it has detecting the system
     * is hung and is reporting that back to the activity controller.  This is to
     * prevent the controller from getting hung up on bug reports at this point.
     * @hide
     *
     * @param msg The message to show instead of the dump; if null, dumps are
     * re-enabled.
     */
    public static void setDumpDisabled(String msg) {
        synchronized (Binder.class) {
            sDumpDisabled = msg;
        }
    }

    /**
     * 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 {
                    IoUtils.closeQuietly(fd);
                }
            }
            // Write the StrictMode header.
            if (reply != null) {
                reply.writeNoException();
            } else {
                StrictMode.clearGatheredViolations();
            }
            return true;
        } else if (code == SHELL_COMMAND_TRANSACTION) {
            ParcelFileDescriptor in = data.readFileDescriptor();
            ParcelFileDescriptor out = data.readFileDescriptor();
            ParcelFileDescriptor err = data.readFileDescriptor();
            String[] args = data.readStringArray();
            ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
            try {
                if (out != null) {
                    shellCommand(in != null ? in.getFileDescriptor() : null,
                            out.getFileDescriptor(),
                            err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
                            args, resultReceiver);
                }
            } finally {
                IoUtils.closeQuietly(in);
                IoUtils.closeQuietly(out);
                IoUtils.closeQuietly(err);
                // Write the StrictMode header.
                if (reply != null) {
                    reply.writeNoException();
                } else {
                    StrictMode.clearGatheredViolations();
                }
            }
            return true;
        }
        return false;
    }

    /**
     * Implemented to call the more convenient version
     * {@link #dump(FileDescriptor, PrintWriter, String[])}.
     */
    public void dump(FileDescriptor fd, String[] args) {
        FileOutputStream fout = new FileOutputStream(fd);
        PrintWriter pw = new FastPrintWriter(fout);
        try {
            doDump(fd, pw, args);
        } finally {
            pw.flush();
        }
    }

    void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
        final String disabled;
        synchronized (Binder.class) {
            disabled = sDumpDisabled;
        }
        if (disabled == null) {
            try {
                dump(fd, pw, args);
            } catch (SecurityException e) {
                pw.println("Security exception: " + e.getMessage());
                throw e;
            } catch (Throwable e) {
                // Unlike usual calls, in this case if an exception gets thrown
                // back to us we want to print it back in to the dump data, since
                // that is where the caller expects all interesting information to
                // go.
                pw.println();
                pw.println("Exception occurred while dumping:");
                e.printStackTrace(pw);
            }
        } else {
            pw.println(sDumpDisabled);
        }
    }

    /**
     * Like {@link #dump(FileDescriptor, String[])}, but ensures the target
     * executes asynchronously.
     */
    public void dumpAsync(final FileDescriptor fd, final String[] args) {
        final FileOutputStream fout = new FileOutputStream(fd);
        final PrintWriter pw = new FastPrintWriter(fout);
        Thread thr = new Thread("Binder.dumpAsync") {
            public void run() {
                try {
                    dump(fd, pw, args);
                } finally {
                    pw.flush();
                }
            }
        };
        thr.start();
    }

    /**
     * Print the object's state into the given stream.
     * 
     * @param fd The raw file descriptor that the dump is being sent to.
     * @param fout The file to which you should dump your state.  This will be
     * closed for you after you return.
     * @param args additional arguments to the dump request.
     */
    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
    }

    /**
     * @param in The raw file descriptor that an input data stream can be read from.
     * @param out The raw file descriptor that normal command messages should be written to.
     * @param err The raw file descriptor that command error messages should be written to.
     * @param args Command-line arguments.
     * @param resultReceiver Called when the command has finished executing, with the result code.
     * @throws RemoteException
     * @hide
     */
    public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ResultReceiver resultReceiver) throws RemoteException {
        onShellCommand(in, out, err, args, resultReceiver);
    }

    /**
     * Handle a call to {@link #shellCommand}.  The default implementation simply prints
     * an error message.  Override and replace with your own.
     * <p class="caution">Note: no permission checking is done before calling this method; you must
     * apply any security checks as appropriate for the command being executed.
     * Consider using {@link ShellCommand} to help in the implementation.</p>
     * @hide
     */
    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ResultReceiver resultReceiver) throws RemoteException {
        FileOutputStream fout = new FileOutputStream(err != null ? err : out);
        PrintWriter pw = new FastPrintWriter(fout);
        pw.println("No shell command implementation.");
        pw.flush();
        resultReceiver.send(0, null);
    }

    /**
     * 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;
    }
    
    /**
     * Local implementation is a no-op.
     */
    public void linkToDeath(DeathRecipient recipient, int flags) {
    }

    /**
     * Local implementation is a no-op.
     */
    public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
        return true;
    }
    
    protected void finalize() throws Throwable {
        try {
            destroy();
        } finally {
            super.finalize();
        }
    }

    static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
        if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
            // Trying to send > 800k, this is way too much
            StringBuilder sb = new StringBuilder();
            sb.append(msg);
            sb.append(": on ");
            sb.append(obj);
            sb.append(" calling ");
            sb.append(code);
            sb.append(" size ");
            sb.append(parcel.dataSize());
            sb.append(" (data: ");
            parcel.setDataPosition(0);
            sb.append(parcel.readInt());
            sb.append(", ");
            sb.append(parcel.readInt());
            sb.append(", ");
            sb.append(parcel.readInt());
            sb.append(")");
            Slog.wtfStack(TAG, sb.toString());
        }
    }

    private native final void init();
    private native final void destroy();

    // Entry point from android_util_Binder.cpp's onTransact
    private boolean execTransact(int code, long dataObj, long replyObj,
            int flags) {
        Parcel data = Parcel.obtain(dataObj);
        Parcel reply = Parcel.obtain(replyObj);
        // theoretically, we should call transact, which will call onTransact,
        // but all that does is rewind it, and we just got these from an IPC,
        // so we'll just call it directly.
        boolean res;
        // Log any exceptions as warnings, don't silently suppress them.
        // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
        try {
            res = onTransact(code, data, reply, flags);
        } catch (RemoteException|RuntimeException e) {
            if (LOG_RUNTIME_EXCEPTION) {
                Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
            }
            if ((flags & FLAG_ONEWAY) != 0) {
                if (e instanceof RemoteException) {
                    Log.w(TAG, "Binder call failed.", e);
                } else {
                    Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
                }
            } else {
                reply.setDataPosition(0);
                reply.writeException(e);
            }
            res = true;
        } catch (OutOfMemoryError e) {
            // Unconditionally log this, since this is generally unrecoverable.
            Log.e(TAG, "Caught an OutOfMemoryError from the binder stub implementation.", e);
            RuntimeException re = new RuntimeException("Out of memory", e);
            reply.setDataPosition(0);
            reply.writeException(re);
            res = true;
        }
        checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
        reply.recycle();
        data.recycle();

        // Just in case -- we are done with the IPC, so there should be no more strict
        // mode violations that have gathered for this thread.  Either they have been
        // parceled and are now in transport off to the caller, or we are returning back
        // to the main transaction loop to wait for another incoming transaction.  Either
        // way, strict mode begone!
        StrictMode.clearGatheredViolations();

        return res;
    }
}
1、類注釋
  • 遠(yuǎn)程對象的基類巧颈,由IBinder定義的輕量級遠(yuǎn)程調(diào)用機(jī)制的核心部分畦木。這個(gè)類是IBinder的實(shí)現(xiàn)類。它提供了這種對象的標(biāo)準(zhǔn)本地實(shí)現(xiàn)砸泛。
  • 大多數(shù)開發(fā)人員不會(huì)直接使用這個(gè)類十籍,而是使用 AIDL工具來實(shí)現(xiàn)這個(gè)接口蛆封,使其生成適當(dāng)?shù)腂inder子類。 但是勾栗,您可以直接從Binder派生自己的自定義RPC協(xié)議惨篱,也可以直接實(shí)例化一個(gè)原始的Binder對象,把它當(dāng)做一個(gè)token围俘,來進(jìn)行跨進(jìn)程通信砸讳。
  • 這個(gè)Binder類是一個(gè)基礎(chǔ)的IPC原生類,它對application的生命周期沒有影響的界牡,它僅當(dāng)創(chuàng)建它的進(jìn)程還活著的時(shí)候才有效簿寂。所以為了正確的使用它,你必須在一個(gè)頂級的app組件里明確地讓系統(tǒng)知道宿亡,
    這個(gè)Binder類是一個(gè)基礎(chǔ)的IPC原生類常遂,它對applicant的生命周期沒有影響,它僅當(dāng)創(chuàng)建它的進(jìn)程還活著的時(shí)候才有效挽荠。所以為了正確地使用它克胳,你必須在一個(gè)頂級app組件(例如service、activity或者ContentProvider)里明確地讓系統(tǒng)知道坤按,您的進(jìn)程應(yīng)該保持運(yùn)行毯欣。
  • 你必須牢記你的進(jìn)程可能會(huì)消失的情況,如果發(fā)生了這種情況臭脓,你必須在進(jìn)程重啟的時(shí)候創(chuàng)建一個(gè)新的Binder酗钞,并且關(guān)聯(lián)這個(gè)進(jìn)程。例如来累,如果你在Activity里面使用了Binder砚作,你的Activity進(jìn)程可能會(huì)被殺死,過了一會(huì)后嘹锁,如果activity比重新啟動(dòng)了葫录,這時(shí)候你要重新創(chuàng)建的一個(gè)新的Binder,并且把這個(gè)心的Binder放回之前的位置领猾。你也要注意到是米同,你的進(jìn)程可能因?yàn)橐恍┰?比如接收broadcast)而啟動(dòng),在這種情況下摔竿,是不需要重新創(chuàng)建Activity的面粮,這時(shí)候就需要運(yùn)行其他的一些代碼去創(chuàng)建Binder對象。
2继低、關(guān)于Binder的構(gòu)造函數(shù)

Binder就提供一個(gè)默認(rèn)的構(gòu)造函數(shù),代碼如下

    /**
     * Default constructor initializes the object.
     */
    public Binder() {
        init();

        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Binder> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
    }
    private native final void init();
  • 首先是執(zhí)行init()方法熬苍,init()是native層的,這里就暫不跟蹤了。
  • 判斷是否是匿名內(nèi)部類柴底,或者內(nèi)部類婿脸,如果是的話,打印日志柄驻。

通過上面我們知道Binder這個(gè)類的核心構(gòu)造函數(shù)是在native實(shí)現(xiàn)的狐树。

3、Binder的重要方法
(1)凿歼、attachInterface(IInterface, String)方法
    /**
     * Convenience method for associating a specific interface with the Binder.
     * After calling, queryLocalInterface() will be implemented for you
     * to return the given owner IInterface when the corresponding
     * descriptor is requested.
     * 將特定接口與Binder相關(guān)聯(lián)的快捷方法褪迟。 調(diào)用之后,將會(huì)實(shí)現(xiàn)
     * queryLocalInterface(), 當(dāng)你請求相應(yīng)的描述符時(shí)答憔,queryLocalInterface()
     * 將返回給定的所有者IInterface味赃。
     */
    public void attachInterface(IInterface owner, String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }
(2)、getInterfaceDescriptor()方法
    /**
     * Default implementation returns an empty interface name.
     * 默認(rèn)實(shí)現(xiàn)返回一個(gè)空的接口名稱虐拓。
     */
    public String getInterfaceDescriptor() {
        return mDescriptor;
    }
(3)心俗、pingBinder()方法
    /**
     * Default implementation always returns true -- if you got here,
     * the object is alive.
     * 默認(rèn)實(shí)現(xiàn)總是返回true - 如果你走到這里,對象是活著的蓉驹。
     */
    public boolean pingBinder() {
        return true;
    }
(4)城榛、isBinderAlive()方法
    /**
     * {@inheritDoc}
     *
     * Note that if you're calling on a local binder, this always returns true
     * because your process is alive if you're calling it.
     * 請注意,如果您正在調(diào)用本地的Binder态兴,則始終返回true
     * 如果你能調(diào)用他狠持,則你的進(jìn)程一定是活著的。
     */
    public boolean isBinderAlive() {
        return true;
    }
(5)瞻润、queryLocalInterface(String)方法
    /**
     * Use information supplied to attachInterface() to return the
     * associated IInterface if it matches the requested
     * descriptor.
     * 如果提供的描述符和之前關(guān)聯(lián)的IInterface(通過attachInterface()
     * 方法進(jìn)行關(guān)聯(lián))的描述符一致喘垂,則返回相對應(yīng)的IInterface
     */
    public IInterface queryLocalInterface(String descriptor) {
        if (mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }
(6)、setDumpDisabled(String)方法
   /**
     * Control disabling of dump calls in this process.  This is used by the system
     * process watchdog to disable incoming dump calls while it has detecting the system
     * is hung and is reporting that back to the activity controller.  This is to
     * prevent the controller from getting hung up on bug reports at this point.
     * @hide
     *
     * @param msg The message to show instead of the dump; if null, dumps are
     * re-enabled.
     */
    public static void setDumpDisabled(String msg) {
        synchronized (Binder.class) {
            sDumpDisabled = msg;
        }
    }

(二)绍撞、BinderProxy

final class BinderProxy implements IBinder {
    public native boolean pingBinder();
    public native boolean isBinderAlive();

    public IInterface queryLocalInterface(String descriptor) {
        return null;
    }

    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); }
        return transactNative(code, data, reply, flags);
    }

    public native String getInterfaceDescriptor() throws RemoteException;
    public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
    public native void linkToDeath(DeathRecipient recipient, int flags)
            throws RemoteException;
    public native boolean unlinkToDeath(DeathRecipient recipient, int flags);

    public void dump(FileDescriptor fd, String[] args) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeFileDescriptor(fd);
        data.writeStringArray(args);
        try {
            transact(DUMP_TRANSACTION, data, reply, 0);
            reply.readException();
        } finally {
            data.recycle();
            reply.recycle();
        }
    }
    
    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeFileDescriptor(fd);
        data.writeStringArray(args);
        try {
            transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
        } finally {
            data.recycle();
            reply.recycle();
        }
    }

    public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ResultReceiver resultReceiver) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeFileDescriptor(in);
        data.writeFileDescriptor(out);
        data.writeFileDescriptor(err);
        data.writeStringArray(args);
        resultReceiver.writeToParcel(data, 0);
        try {
            transact(SHELL_COMMAND_TRANSACTION, data, reply, 0);
            reply.readException();
        } finally {
            data.recycle();
            reply.recycle();
        }
    }

    BinderProxy() {
        mSelf = new WeakReference(this);
    }
    
    @Override
    protected void finalize() throws Throwable {
        try {
            destroy();
        } finally {
            super.finalize();
        }
    }
    
    private native final void destroy();
    
    private static final void sendDeathNotice(DeathRecipient recipient) {
        if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
        try {
            recipient.binderDied();
        }
        catch (RuntimeException exc) {
            Log.w("BinderNative", "Uncaught exception from death notification",
                    exc);
        }
    }
   
    final private WeakReference mSelf;
    private long mObject;
    private long mOrgue;
}

四正勒、總結(jié)

所以大體的結(jié)構(gòu)類圖圖下圖:


Java層的Binder對象模型.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市傻铣,隨后出現(xiàn)的幾起案子章贞,更是在濱河造成了極大的恐慌,老刑警劉巖非洲,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸭限,死亡現(xiàn)場離奇詭異,居然都是意外死亡两踏,警方通過查閱死者的電腦和手機(jī)败京,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缆瓣,“玉大人喧枷,你說我怎么就攤上這事虹统」耄” “怎么了隧甚?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渡冻。 經(jīng)常有香客問我戚扳,道長,這世上最難降的妖魔是什么族吻? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任帽借,我火速辦了婚禮,結(jié)果婚禮上超歌,老公的妹妹穿的比我還像新娘砍艾。我一直安慰自己,他們只是感情好巍举,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布脆荷。 她就那樣靜靜地躺著,像睡著了一般懊悯。 火紅的嫁衣襯著肌膚如雪蜓谋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天炭分,我揣著相機(jī)與錄音桃焕,去河邊找鬼。 笑死捧毛,一個(gè)胖子當(dāng)著我的面吹牛观堂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岖妄,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼型将,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了荐虐?” 一聲冷哼從身側(cè)響起七兜,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎福扬,沒想到半個(gè)月后腕铸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铛碑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年狠裹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汽烦。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涛菠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情俗冻,我是刑警寧澤礁叔,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站迄薄,受9級特大地震影響琅关,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讥蔽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一涣易、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冶伞,春花似錦新症、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至金抡,卻和暖如春瀑焦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梗肝。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工榛瓮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人巫击。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓禀晓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坝锰。 傳聞我的和親對象是個(gè)殘疾皇子粹懒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容