Binder In Native

關於Binder的設計思想與Driver層實現細節能夠看這個:Android Binder設計與實現 - 設計篇,這裏首先簡要歸納一下。html

Service的每一個Binder實體位於Service所屬的進程種中,Binder實體在驅動中被表示爲binder_node,並經過成員refs指向了驅動中全部對這個Binder實體的引用,Binder引用在驅動被表示爲binder_ref,並經過成員node指向所引用的Binder實體。node

每一個使用Binder的進程都會在它的ProcessState的構造函數中打開Binder設備,當打開Binder設置時會調用驅動的binder_open,在binder_open中,會爲使用Binder的進程建立一個binde_proc節點,binder_proc的成員nodes索引了這個進程建立的全部Binder實體,refs_by_desc與refs_by_node則是分別以這個進程引用的Binder實體的引用號與引用的實體在內核中的內在地址爲索引構建的紅黑樹。這樣每一個進程均可以經過本身的binder_proc節點檢索到全部本身建立的Binder實體與全部對其餘Binder實體的引用。android

匿名Binder要經過實名Binder傳遞,而實名Binder要向ServiceManager註冊。因此首先必定要有進程經過調用ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0)成爲ServiceManager,當有進程申請成爲ServiceManager時,驅動就經過binder_new_node創建內核中的第一個binder_node節點。數組

數據在驅動中以binder_transaction_date結構傳輸,binder_transaction_data的成員ptr.buffer指向要發送的數據的內存地址,在進程間也能夠傳送Binder實體或引用,好比發送匿名Binder,當Binder實體或引用在數據中傳輸時,就須要一個方法將Binder實體或引用在數據中的位置指出來,ptr.offsets就指向Binder偏移數組,offsets_size指明瞭Binder偏移數組的大小,經過這兩個成員驅動就能夠找到傳輸的數據中的全部Binder實體或引用。Binder實體或引用在傳遞時被表示爲flat_binder_object,flat_binder_object的type域表示傳輸的Binder的類型,TYPE_BINDER_(WEAK)_TYPE表示傳輸的是Binder實體,TYPE_BINDER_(WEAK)_HANDLE表示的是Binder引用,BINDER_TYPE_FD表示文件Binder。函數

Client要向Service發送請求,必定要得到對Service的Binder實體的引用,Client向Service發送請求時,以引用號指明要向哪一個Service發送請求,引用號0表示向ServiceManager發送請求。ui

通常狀況下,若是Client要向某一Service進行一個請求,首先會經過向引用號爲0的Binder引用發送GET_SERVICE請求得到本身須要的Service在的引用,而後再向這個引用即這個引用對應的Service發送請求。this

驅動會將全部發送到引用號爲0的請求轉發至ServiceManager,當一個進程向0號引用即ServiceManager請求某一個Service時,ServiceManager會檢測一個表查找Client請求的Service是否已向本身註冊,當Binder實體向ServiceManager註冊時,ServiceManager會將Binder實體的名字與引用存入一個查找表中,若是已經註冊,就將Service所註冊的Binder引用返回給請求的進程。spa

當ServiceManager將某一進程請求的Service的Binder引用發送給這一進程時,因爲傳送的是引用,因此flat_binder_object的type的值是TYPE_BINDER_(WEAK)_HANDLE,驅動經過binder_transaction_date的ptr.offsets和offsets_size知道了返回數據中包含Binder實體或引用,而後經過這兩個成員找出數據中的Binder實體或引用,經過flat_binder_object的type成員知道了返回數據中包含的是Binder引用,而後新建一個對Service的Binder實體的引用並同時保存到Binder實體在驅動中的節點binder_node的refs成員與Client進程的binder_proc中。線程

Client獲得了Service的引用就能夠以這個引用向Service發送請求了,數據包是binder_transaction_date結構體,其成員target是一個聯合,target.handle表示Client對Service的引用號,target.ptr表示Binder實體在Service進程中的內存地址,當Client向Service發送請求時填充target.handle域,驅動根據Client所屬的binder_proc節點與引用號handle得到Client對Service的Binder實體的引用binder_ref,而後經過binder_ref的node成員得到Service的Binder實體在內核中的節點binder_node,而後將Client的請求添加到Service進程的等待隊列或Service進程某一線程的等待隊列,Service就能夠處理Client的請求了。設計

 

接下來看下Native層對Binder的使用。

Binder被實現爲一個字符設備,應用程序經過ioctl調用與Binder驅動程序進行通訊。首先看實現一個ServiceDemo涉及到的類結構關係。

RefBase是Android實現指針管理的類,牽扯到引用計數的都繼承自這個類,而後經過sp,wp實現強引用計數與弱引用計數的管理。

Binder使用Client-Server的通訊方式,要實現一個Server,須要先定義一套接口,Client與Server同時實現這套接口,Server端完成實際的功能,Client端只是對Server端功能調用的封裝,因爲這套接口須要跨進程調用,須要對全部接口一一編號,Server端根據接口編號決定調用什麼函數。在上圖中對接口的定義就是IServiceDemo。

要實現進程間通訊,首先須要定義通訊的協議,而後嚮應用程序提供通訊的接口,Binder Driver定義了通訊協議,IBinder,BpBinder,BBinder承擔了通訊接口的工做,IBinder定義了通訊的接口,BpBinder是Client訪問服務端的代理對象,負責打開Binder設備並與Binder設備通訊,BBinder做爲服務端與Binder設備通訊的接口。Client經過BpBinder鏈接Binder Driver,而後Binder Driver經過BBinder與Server通訊,從而完成進程間通訊。

IServiceDemo定義了Client與Server通訊的接口,須要Client與Server同時實現,咱們已經知道,Client經過BpBinder與Server的BBinder進行通訊,那麼Client端怎麼獲得BpBinder,Server端怎麼獲得BBinder呢?從上圖能夠看到,IServiceDemo繼承自IInterface,其實IInterface就定義了一個方法asBinder,返回一個IBinder對象的指針,應該是經過這個方法得到BpBinder與BBinder對象了。看asBinder實現能夠知道,asBinder直接調用了onAsBinder,onAsBinder是一個虛方法,因此是調用子類的具體實現。咱們發現,IInterface有兩個子類BpInterface與BnInterface,在這兩個類中都實現了onAsBinder,在BpInterface中,onAsBinder返回了remote(),remote()實際上是返回一個BpBinder對象,後面會看到。在BnInterface中,onAsBinder直接返回this指針,而BnInterface繼承自BBinder,因此BnInterface的onAsBinder返回了一個BBinder對象,BpBinder與BBinder都有了,Client就能夠與Server通訊了。

前面說到remote()返回一個BpBinder對象,那麼這個對象是如何返回的呢?從上圖看到,BnInterface是繼承自BBinder的,可是BpInterface並無繼承自BpBinder,可是咱們發現,BpInterface的構造函數接收一個IBinder類型的參數,咱們看一下BpInterface的構造函數:

template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)
{
} 

BpInterface繼承自BpRefBase,在BpInterface的初始化列表中調用了父類BpRefBase的構造函數,將IBinder remote傳了過去。再看BpRefBase的構造函數:

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    if (mRemote) {
        mRemote->incStrong(this);           // Removed on first IncStrong().
        mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
    }
}

直接將BpInterface傳過來的IBinder remote保存到了成員mRemote中,而remote()函數就直接返回了這個mRemote對象。

經過BpInterface的構造函數保存了BpBinder對象,那麼BpInterface的構造函數是何時調用的,而做爲構造函數參數傳遞進去的BpBinder又是何時構造的?以ServiceManager爲例,實名Binder須要經過addService向ServiceManager註冊,這也是進程間通訊,那麼咱們就須要得到ServiceManager的BpBinder,即BpInterface的子類BpServiceManager對象,來看一下BpServiceManager的獲取方法:

sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

    {
        AutoMutex _l(gDefaultServiceManagerLock);
        if (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
        }
    }

    return gDefaultServiceManager;
}

單例模式,看以上代碼的紅色部分,ProcessState表明進程對象,每一個進程只有一個,在ProcessState::self()中經過單例模式返回每一個進程的ProcessState的惟一實例,在ProcessState的函數函數中經過open調用打開了Binder設備,並經過mmap創建了內存映射。open引發binder driver中的binder_open被調用,binder_open中新建binder_proc節點,初始化todo隊列與wait隊列,並將binder_proc節點保存在binder_open第二個參數struct file *flip的flip->private_data中及binder_procs中。

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
    return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            b = new BpBinder(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}

handle是0,lookupHandleLocked的返回結果會是NULL,因此會執行紅色部分新建一個BpBinder,defaultServiceManager中紅色部分能夠簡化爲:

gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

BpBinder有了,咱們在前面也知道了BpBinder會作爲參數傳遞給BpInterface的構造函數,那麼BpInterface的構造函數是何時調用的?從以上代碼看,應該是interface_cast了,將參數BpBinder轉化爲了BpInterface的子類BpServiceManager,再來看interface_cast的實現。

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

INTERFACE即爲IServiceManager,繼承自IInterface的類都會聲明DELCARE_META_INTERFACE與IMPLEMENT_META_INTERFACE,看一下IMPLEMENT_META_INTERFACE的實現:

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }      

在IMPLEMENT_META_INTERFACE宏中實現了asInterface,上述紅色代碼中,obj即傳進來的BpBinder(0),最上面的圖的註釋中說了BpBinder的queryLocalInterface返回NULL,因此會執行藍色代碼,INTERFACE是Servicemanager,因此會新建一個BpServiceManager對象。BpServiceManager對象有了,對過其asBinder方法返回的BpBinder對象就能夠與Server進行通訊了。

 

Client有了代理對像BpInterface,那麼怎麼經過這個代理對象與Server進行通訊呢?標準方法是下面這樣:

remote()->transact(SET_MASTER_VOLUME, data/*parcel*/, &reply/*parcel*/);

前面已經說了,Client經過BpBinder經由Binder驅動、BBinder與Server端通訊,從這裏看確實是這樣,remote()返回BpBinder對象,調用BpBinder的transact來與Server通訊,transact是定義在IBinder中的,BpBinder與BBinder都實現了這個方法。

在BpBinder::transact的實現中,直接調用了IPCThreadState::transact,前面說過ProcessState表明進程對象,每一個進程有一個,在ProcessState的構造函數會打與Binder設備並進行mmap,而這裏的IPCThreadState就表示線程對象,使用LTS(Local Thread Storage)每一個線程有一個IPCThreadState對象,Binder通訊是線程與線程的通訊,這裏咱們能經過IPCThreadState::transact與Server端進行通訊。

IPCThreasState::transact方法首先調用writeTransactionDate將請求數據封裝進binder_transaction_data結構並寫入Parcel mOut中。而後調用waitForResponse。

waitForResponse會調用talkWithDriver,talkWithDriver經過ioctl(driverFD,BINDER_WIRTE_READ,&binder_write_read)與Binder驅動進行通訊,當Server處理完請求後talkWithDriver成功返回,而後waitForResponse中讀取Binder Driver返回的指令並執行相應的動做。

在Server中,binder thread的joinThreadPool中會調用taklWithDriver等待Client請求,當有請求到來時talkWithDriver返回,讀取command,調用executeCommand處理請求。在executeCommand中調用BBinder的transact處理請求,BBinder::transact會調用虛方法onTransact來完成具體功能,具體實現就是BnServiceManager::onTransact或BnServiceDemo::onTransact等等。通常會有一個類繼承自BnXXXXX完成具體功能,在BnXXXXX的onTransact中會調用完成相應功能的接口,因爲是虛方法,就會調用到具體實現類。

 

註冊上下文管理者--ServiceManager

經過 ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); 一個進程能夠註冊成爲上下文件管理者,在ServiceManager就是執行這條ioctl請求。

ioctl調用會執行Binder Driver的binder_ioctl函數,binder_ioctl根據第二個參數cmd執行相應的同做,看下BINDER_SET_CONTEXT_MGR對應的處理:

case BINDER_SET_CONTEXT_MGR:
                if (binder_context_mgr_node != NULL) {
                        printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");
                        ret = -EBUSY;
                        goto err;
                }
                if (binder_context_mgr_uid != -1) {
                        if (binder_context_mgr_uid != current->cred->euid) {
                                printk(KERN_ERR "binder: BINDER_SET_"
                                       "CONTEXT_MGR bad uid %d != %d\n",
                                       current->cred->euid,
                                       binder_context_mgr_uid);
                                ret = -EPERM;
                                goto err;
                        }
                } else
                        binder_context_mgr_uid = current->cred->euid;
                binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
                if (binder_context_mgr_node == NULL) {
                        ret = -ENOMEM;
                        goto err;
                }
                binder_context_mgr_node->local_weak_refs++;
                binder_context_mgr_node->local_strong_refs++;
                binder_context_mgr_node->has_strong_ref = 1;
                binder_context_mgr_node->has_weak_ref = 1;
                break;

很簡單,就是經過binder_new_node獲取到一個binder_node保存到全局變量binder_context_mgr_node中,同時保存了UID,只能有一個context_manager。

相關文章
相關標籤/搜索