Android跨進程通信IPC之5——Binder的三大接口

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

本片文章的主要目的是讓大家對Binder有個初步的了解,既然是初步了解,肯定所是以源碼上的注釋為主,讓大家對Binder有一個更直觀的認識。PS:大部分注釋我是寫在類里面了, 重要的我會單獨的拿出來。
主要內(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)接口的基類。 定義新接口的時候,你必須從IInterface派生。

(二)、抽象方法注釋

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

(三)、總結(jié)

所以可以這樣說IInterface接口提供了類型轉(zhuǎn)化的功能,將服務(wù)或者服務(wù)代理類轉(zhuǎn)為IBinder類型。其實實際的類型轉(zhuǎn)換是由BnInterface、BpInterface兩個類完成的,BnInterface將服務(wù)類轉(zhuǎn)換成IBinder類型,而BpInterface則將代理服務(wù)類轉(zhuǎn)換成IBinder類型。在通過Binder Driver傳遞Binder對象時,必須進行類型轉(zhuǎn)換,比如在想系統(tǒng)注冊服務(wù)時,需要先將服務(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.
     * 第一個可用于用戶命令的事務(wù)代碼。
     */
    int FIRST_CALL_TRANSACTION  = 0x00000001;
    /**
     * The last transaction code available for user commands.
     * 最后一個可用于用戶命令的事務(wù)代碼。
     */
    int LAST_CALL_TRANSACTION   = 0x00ffffff;
    
    /**
     * IBinder protocol transaction code: pingBinder().
     * IBinder協(xié)議事物碼:在pingBinder()會用到
     */
    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í)行一個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é)議事物碼:向目標對象發(fā)出一個呼叫。在parcel中的數(shù)據(jù)是用于
     * 分發(fā)一個與對象結(jié)合的共享信息服務(wù)。它可以是任何東西,只要它不超
     * 過130個UTF-8字符,保證適用于常見的信息服務(wù)。 作為 
     * Build.VERSION_CODES#HONEYCOMB_MR2的一部分,所有的binder
     * 對象都支持這個協(xié)議,為了在跨平臺間完整推送同時也為了支持舊的交
     * 互碼,一個默認的實現(xiàn)是在主日志中記錄了一個推送,作為廣播的一個
     * 簡單模仿。
     * 并且,為了完成消息的派送,對象必須返回給調(diào)用者一個說明,
     * 表明是舊的信息。
     */
    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 有一個調(diào)用者在呼叫它。這個app負
     * 責計算和維護自己的呼叫者數(shù)目。 并且可以展示這個值來告訴用戶app
     * 的狀態(tài)。這個是可選的命令,app不需要掌管它,所以默認是實現(xiàn)是什
     * 么都不做。
     * 這是沒有響應(yīng)的,并且不會對系統(tǒng)帶來影響,但是它提高了app的自控
     * (我真的不知道怎么翻譯,elf-esteem其實是自尊的意思)
     */
    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,表明呼叫者會馬上返回,
     * 不必等結(jié)果從被呼叫者返回。只有當呼叫者和被呼叫者在不同的進程中
     * 才有效.
     */
    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.
     *  獲取一個支持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,主機進程消失,否則結(jié)果為true(始終默認true)由對
     * 手方來實現(xiàn)pingBinder()這個方法。
     */
    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所在的進程是否仍然存在
     * 如果進程不存在,則返回false。 請注意,如果返回true,則調(diào)用返回時
     * 進程可能已經(jīng)死機。
     */
    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);
}

注釋有點多,我們一個一個來

(一)、類注釋

簡單的翻譯一下:

  • 一個遠程對象的基接口,是為高性能而設(shè)計的輕量級遠程調(diào)用機制的核心部分,它不僅用于遠程調(diào)用,也可以用于進程內(nèi)調(diào)用。這個接口描述了與遠程對象進行交互的抽象協(xié)議。建議繼承Binder類,而不是直接實現(xiàn)這個接口。
    IBinder的主要API是transact(),與它對應(yīng)另一個方法是Binder.onTransact。第一個方法使你可以向遠端的IBinder對象發(fā)送調(diào)用,第二個方法使你自己的遠程對象能夠響應(yīng)接收到的調(diào)用。IBinder的API都是同步執(zhí)行的,比如transact()直到對方的Binder.onTransact()方法調(diào)用完成后才返回。而在跨進程的時候,在IPC的幫助下,也是同樣的效果。
    通過transact()發(fā)送的數(shù)據(jù)是Parcel,Parcel是一種一般的緩沖區(qū),除了有數(shù)據(jù)外還帶有一些描述它內(nèi)容的元數(shù)據(jù)。元數(shù)據(jù)用于管理IBinder對象的引用,這樣就能在緩沖去從一個進程移動到另一個進程時,保存這些引用。這樣就保證了當一個IBinder被寫入到Parcel并發(fā)送到另一個進程中,如果另一個進程把同一個IBinder的引用回發(fā)到原來的進程,那么這個原來的進程就能接收到發(fā)出的那個IBinder的引用。這種機制使IBinder和Binder像唯一標志符那樣在進程間管理。
    系統(tǒng)為每一個進程維持一個存放交互的線程池。這些交互的線程用于派發(fā)所有從其他進程發(fā)來的IPC調(diào)用。例如:當一個IPC從進程A發(fā)到進程B,A中那個發(fā)出調(diào)用的線程就阻塞在transact()中了。進程B中的交互線程池的一個線程池接收了這個調(diào)用,它調(diào)用Binder.onTransact(),完成后用一個Parcel來作為結(jié)果返回。然后進程A中的那個等待線程在收到返回的Parcel才能繼續(xù)執(zhí)行。實際上,另一個進程看起來就像當前進程的一個線程,但不是當前進程創(chuàng)建的。
    Binder機制還支持進程間的遞歸調(diào)用。例如,進程A執(zhí)行自己的IBinder的transact()調(diào)用進程B的Binder,而進程B在其Binder.onTransact()中又用transact()向進程A發(fā)起調(diào)用,那么進程A在等待它發(fā)布出的調(diào)用返回的同時,還會用Binder.onTransact()響應(yīng)進程B的transact()。總之,Binder造成的結(jié)果就是讓我們感覺到跨進程的調(diào)用與進程內(nèi)的調(diào)用沒有什么區(qū)別。
    當操作遠程對象的時候,你需要經(jīng)常查看它們是否有效,有3種方法可以使用:
    • 1 transact()方法將在IBinder所在的進程不存在時拋出RemoteException異常
    • 2 如果目標進程不存在,那么調(diào)用pingBinder()時返回false\
    • 3 可以用linkToDeath()方法向IBinder注冊一個IBinder.DeathRecipient,在IBinder代表的進程退出時被調(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);

翻譯如下:

用于接收一個用于當前binder對象的本地接口的實現(xiàn)。如果返回null,你需要通過transact()方法去實例化一個代理類。

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)儲發(fā)送到的原始文件描述符。
  • 入?yún)rgs: 轉(zhuǎn)儲請求的附加參數(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í)行。如果對象在本地, 一個新的線程將會被創(chuàng)建去執(zhí)行這個操作。

  • 入?yún)d:轉(zhuǎn)儲發(fā)送到的原始文件描述符。
  • 入?yún)rgs: 轉(zhuǎn)儲請求的附加參數(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:命令錯誤消息應(yīng)寫入的原始文件描述符。
  • 入?yún)rgs: 命令行參數(shù)。
  • 入?yún)esultReceiver: 當命令執(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í)行一個通用的操作

  • 入?yún)ode:操作碼必須在FIRST_CALL_TRANSACTION和LAST_CALL_TRANSACTION之間
  • 入?yún)ata: 傳輸給目標的數(shù)據(jù)。如果你沒有傳輸任何數(shù)據(jù),你必須創(chuàng)建一個空的Parcel
  • 入?yún)eply:從目標接收的數(shù)據(jù)。可以是null如果你對返回的值不感興趣。
  • 入?yún)lags: 附加操作標志。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;

翻譯如下:

注冊一個recipient用于提示binder消失。如果binder對象異常地消失(例如由于主進程被殺),DeathRecipient中的binderDied會被調(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不再會被調(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();
    }

翻譯如下:

當持有IBinder進程消失,會回調(diào)這個接口

(四)、總結(jié):

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

  • 1、IBindre是遠程對象的基接口,不僅可以在跨進程可以調(diào)用,也可以在進程內(nèi)部調(diào)用
  • 2、在遠程調(diào)用的時候,一端用IBinder.transact()發(fā)送,另一端用Binder的Binder.onTransact()接受,并且是同步的
  • 3、transact()方法發(fā)送的是Parcel。
  • 4、系統(tǒng)為每個進程維護一個進行跨進程調(diào)用的線程池。
  • 5、可以使用pingBinder()方法來檢測目標進程是否存在
  • 6、可以調(diào)用linkToDeath()來向IBinder注冊一個IBinder.DeathRecipien。用于目標進程退出時候的提醒。
  • 7、建議繼承Binder類,而不是直接實現(xiàn)這個接口。

三、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è)置這個標記來檢測是否是Binder的匿名內(nèi)部類,或者Binder的
     * 本地內(nèi)部類,因為這些類可能會存在潛在的內(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.
     * 進程的全局事務(wù)跟蹤器實例。
     */
    private static TransactionTracker sTransactionTracker = null;

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

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

    /**
     * Enable Binder IPC tracing.
     * 啟動 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.
     * 獲取此進程的 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 會被Native 代碼調(diào)用,不要刪除或重命名
    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ā)送正在處理的當前事務(wù)的進程的ID。 該pid可以與更高級
     * 別的系統(tǒng)服務(wù)一起使用,以確定其身份和檢查權(quán)限。 如果當前線程當
     * 前沒有執(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ā)送正在處理的當前事務(wù)的進程。
     * 這個uid可以與更高級別的系統(tǒng)服務(wù)一起使用,以確定其身份和檢查
     * 權(quán)限。 如果當前線程當前沒有執(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ā)送給正在處理的當前事務(wù)的進程的UserHandle。 這是
     * 呼叫者的用戶。 與getCallingUid()不同,特定用戶將具有多個不同的
     * 應(yīng)用程序,每個應(yīng)用程序都具有自己的uid。 如果當前線程當前沒有
     * 執(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).
     * 重置當前線程的IPC的身份。 如果在處理來電時,您將會調(diào)用
     * 其他對象的接口,這些對象可能在本地進程中,并且需要對其中的調(diào)
     * 用進行權(quán)限檢查(不管原來的進程是如何調(diào)用你的,他們都將將檢查
     * 您自己進程的的訪問權(quán)限)。
     *  //最后一句話我實在是翻譯不好
     * @return Returns an opaque token that can be used to restore the
     * original calling identity by passing it to
     * {@link #restoreCallingIdentity(long)}.
     *
     *  返回一個不透明的token,通過restoreCallingIdentity(long)這個方法
     *  可以恢復(fù)原始呼叫的身份標識
     * @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ù)之前當前線程上的傳入IPC的身份標識。這個身份標識是由
     *  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è)置保存在兩個地方:Java級別的 本地線程  在libcore / Dalvik中進行設(shè)置,
     * 和 native的 本地線程則通過Binder調(diào)用來設(shè)置。 這有點兒不幸,但總
     * 比依賴于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.
     * 獲取當前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.
     * 將當前線程中的Binder命令刷新到內(nèi)核驅(qū)動程序中。這在執(zhí)行可能會
     * 長時間阻塞的操作之前調(diào)用是有用的,因為這樣可以確保已經(jīng)釋放了
     * 任何掛起的對象引用,以防止進程持續(xù)到比需要的對象更長的時間。
     */
    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線程池。 此方法在當前進程退出之前不返回。
     */
    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ù)量小于此進程允許的綁定線程的最大數(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、類注釋
  • 遠程對象的基類,由IBinder定義的輕量級遠程調(diào)用機制的核心部分。這個類是IBinder的實現(xiàn)類。它提供了這種對象的標準本地實現(xiàn)。
  • 大多數(shù)開發(fā)人員不會直接使用這個類,而是使用 AIDL工具來實現(xiàn)這個接口,使其生成適當?shù)腂inder子類。 但是,您可以直接從Binder派生自己的自定義RPC協(xié)議,也可以直接實例化一個原始的Binder對象,把它當做一個token,來進行跨進程通信。
  • 這個Binder類是一個基礎(chǔ)的IPC原生類,它對application的生命周期沒有影響的,它僅當創(chuàng)建它的進程還活著的時候才有效。所以為了正確的使用它,你必須在一個頂級的app組件里明確地讓系統(tǒng)知道,
    這個Binder類是一個基礎(chǔ)的IPC原生類,它對applicant的生命周期沒有影響,它僅當創(chuàng)建它的進程還活著的時候才有效。所以為了正確地使用它,你必須在一個頂級app組件(例如service、activity或者ContentProvider)里明確地讓系統(tǒng)知道,您的進程應(yīng)該保持運行。
  • 你必須牢記你的進程可能會消失的情況,如果發(fā)生了這種情況,你必須在進程重啟的時候創(chuàng)建一個新的Binder,并且關(guān)聯(lián)這個進程。例如,如果你在Activity里面使用了Binder,你的Activity進程可能會被殺死,過了一會后,如果activity比重新啟動了,這時候你要重新創(chuàng)建的一個新的Binder,并且把這個心的Binder放回之前的位置。你也要注意到是,你的進程可能因為一些原因(比如接收broadcast)而啟動,在這種情況下,是不需要重新創(chuàng)建Activity的,這時候就需要運行其他的一些代碼去創(chuàng)建Binder對象。
2、關(guān)于Binder的構(gòu)造函數(shù)

Binder就提供一個默認的構(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òu)造函數(shù)是在native實現(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)用之后,將會實現(xiàn)
     * queryLocalInterface(), 當你請求相應(yīng)的描述符時,queryLocalInterface()
     * 將返回給定的所有者IInterface。
     */
    public void attachInterface(IInterface owner, String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }
(2)、getInterfaceDescriptor()方法
    /**
     * Default implementation returns an empty interface name.
     * 默認實現(xiàn)返回一個空的接口名稱。
     */
    public String getInterfaceDescriptor() {
        return mDescriptor;
    }
(3)、pingBinder()方法
    /**
     * Default implementation always returns true -- if you got here,
     * the object is alive.
     * 默認實現(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)用他,則你的進程一定是活著的。
     */
    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()
     * 方法進行關(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)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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