android IPC及原理簡介

yangxi_001發表於2013-11-20

Linux 系統中程式間通訊的方式有:socket, named pipe,message queque, signal,share memory。Java系統中的程式間通訊方式有socket, named pipe等。android應用程式理所當然可以應用JAVA的IPC機制實現程式間的通訊,

取 而代之的是Binder通訊。Google為什麼要採用這種方式呢,這取決於Binder通訊方式的高效率。 Binder通訊是通過linux的binder driver來實現的。Binder通訊操作類似執行緒遷移(thread migration),兩個程式間IPC看起來就象是一個程式進入另一個程式執行程式碼然後帶著執行的結果返回。

Binder 的使用者空間為每一個程式維護著一個可用的執行緒池,執行緒池用於處理到來的IPC以及執行程式本地訊息,Binder通訊是同步而不是非同步。Android中 的Binder通訊是基於Service與Client的,所有需要IBinder通訊的程式都必須建立一個IBinder介面。

系統中有一個程式管理所有的system service,Android虛擬機器不允許使用者新增非授權的System service,當然現在原始碼開發了,我們可以修改一些程式碼來實現新增底層system Service的目的。

對 使用者程式來說,我們也要建立server,或者Service用於程式間通訊,這裡有一ActivityManagerService管理JAVA應用層 所有的service建立與連線(connect)。disconnect,所有的 Activity也是通過這個service來啟動,載入的。ActivityManagerService也是載入在Systems Servcie中的。

Android 虛擬機器啟動之前系統會先啟動service Manager程式,service Manager開啟binder驅動,並通知binder kernel驅動程式這個程式將作為System Service Manager。然後該程式將進入一個迴圈,等待處理來自其他程式的資料。使用者建立一個System service後,通過defaultServiceManager得到一個遠端ServiceManager的介面。

通 過這個介面我們可以呼叫 addService函式將System service新增到Service Manager程式中,然後client可以通過getService獲取到需要連線的目的Service的IBinder物件。這個IBinder是 Service的BBinder在binder kernel的一個參考,所以service IBinder 在binder kernel中不會存在相同的兩個IBinder物件。

每 一個Client程式同樣需要開啟Binder驅動程式。對使用者程式而言,我們獲得這個物件就可以通過binder kernel訪問service物件中的方法。Client與Service在不同的程式中,通過這種方式實現了類似執行緒間的遷移的通訊方式,對使用者程式 而言當呼叫Service返回的IBinder介面後,訪問Service中的方法就如同呼叫自己的函式。

實現介面時有幾個原則:

丟擲的異常不要返回給呼叫者. 跨程式拋異常處理是不可取的。IPC呼叫是同步的。如果你知道一個IPC服務需要超過幾毫秒的時間才能完成地話,你應該避免在Activity的主執行緒中呼叫。

也就是IPC呼叫會掛起應用程式導致介面失去響應. 這種情況應該考慮單起一個執行緒來處理,能在AIDL介面中宣告靜態屬性。IPC的呼叫步驟:

1. 宣告一個介面型別的變數,該介面型別在.aidl檔案中定義。

2. 實現ServiceConnection。

3. 呼叫ApplicationContext.bindService(),並在ServiceConnection實現中進行傳遞. 

4. 在ServiceConnection.onServiceConnected()實現中,你會接收一個IBinder例項(被呼叫的Service). 呼叫    YourInterfaceName.Stub.asInterface((IBinder)service)將引數轉換YourInterface類 型。

5. 呼叫介面中定義的方法。 你總要檢測到DeadObjectException異常,該異常在連線斷開時被丟擲。它只會被遠端方法丟擲。

6. 斷開連線,呼叫介面例項中的ApplicationContext.unbindService()

IPC 及原理

IBinder介面

IBinder介面是對跨程式的物件的抽象。普通物件在當前程式可以訪問,如果希望物件能被其它程式訪問,那就必須實現IBinder介面。IBinder介面可以指向本地物件,也可以指向遠端物件,呼叫者不需要關心指向的物件是本地的還是遠端。

transact是IBinder介面中一個比較重要的函式,它的函式原型如下:

virtual status_t transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) = 0;

android中的IPC的基本模型是基於客戶/伺服器(C/S)架構的。

客戶端

請求通過核心模組中轉

服務端

如果IBinder指向的是一個客戶端代理,那transact只是把請求傳送給伺服器。服務端的IBinder的transact則提供了實際的服務。

o 客戶端

BpBinder是遠端物件在當前程式的代理,它實現了IBinder介面。它的transact函式實現如下:

status_t BpBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

    // Once a binder has died, it will never come back to life.

    if (mAlive) {

        status_t status = IPCThreadState::self()->transact(

            mHandle, code, data, reply, flags);

        if (status == DEAD_OBJECT) mAlive = 0;

        return status;

    }

 

    return DEAD_OBJECT;

}

引數說明:

?  code 是請求的ID號。

?  data 是請求的引數。

?  reply 是返回的結果。

?  flags 一些額外的標識,如FLAG_ONEWAY。通常為0。

transact只是簡單的呼叫了IPCThreadState::self()的transact,在IPCThreadState::transact中:

status_t IPCThreadState::transact(int32_t handle,

                                  uint32_t code, const Parcel& data,

                                  Parcel* reply, uint32_t flags)

{

    status_t err = data.errorCheck();

 

    flags |= TF_ACCEPT_FDS;

 

    IF_LOG_TRANSACTIONS() {

        TextOutput::Bundle _b(alog);

        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "

            << handle << " / code " << TypeCode(code) << ": "

            << indent << data << dedent << endl;

    }

 

    if (err == NO_ERROR) {

        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),

            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");

        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);

    }

 

    if (err != NO_ERROR) {

        if (reply) reply->setError(err);

        return (mLastError = err);

    }

 

    if ((flags & TF_ONE_WAY) == 0) {

        if (reply) {

            err = waitForResponse(reply);

        } else {

            Parcel fakeReply;

            err = waitForResponse(&fakeReply);

        }

 

        IF_LOG_TRANSACTIONS() {

            TextOutput::Bundle _b(alog);

            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "

                << handle << ": ";

            if (reply) alog << indent << *reply << dedent << endl;

            else alog << "(none requested)" << endl;

        }

    } else {

        err = waitForResponse(NULL, NULL);

    }

 

    return err;

}

 

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)

{

    int32_t cmd;

    int32_t err;

 

    while (1) {

        if ((err=talkWithDriver()) < NO_ERROR) break;

        err = mIn.errorCheck();

        if (err < NO_ERROR) break;

        if (mIn.dataAvail() == 0) continue;

 

        cmd = mIn.readInt32();

 

        IF_LOG_COMMANDS() {

            alog << "Processing waitForResponse Command: "

                << getReturnString(cmd) << endl;

        }

 

        switch (cmd) {

        case BR_TRANSACTION_COMPLETE:

            if (!reply && !acquireResult) goto finish;

            break;

 

        case BR_DEAD_REPLY:

            err = DEAD_OBJECT;

            goto finish;

 

        case BR_FAILED_REPLY:

            err = FAILED_TRANSACTION;

            goto finish;

 

        case BR_ACQUIRE_RESULT:

            {

                LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");

                const int32_t result = mIn.readInt32();

                if (!acquireResult) continue;

                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;

            }

            goto finish;

 

        case BR_REPLY:

            {

                binder_transaction_data tr;

                err = mIn.read(&tr, sizeof(tr));

                LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");

                if (err != NO_ERROR) goto finish;

 

                if (reply) {

                    if ((tr.flags & TF_STATUS_CODE) == 0) {

                        reply->ipcSetDataReference(

                            reinterpret_cast(tr.data.ptr.buffer),

                            tr.data_size,

                            reinterpret_cast(tr.data.ptr.offsets),

                            tr.offsets_size/sizeof(size_t),

                            freeBuffer, this);

                    } else {

                        err = *static_cast(tr.data.ptr.buffer);

                        freeBuffer(NULL,

                            reinterpret_cast(tr.data.ptr.buffer),

                            tr.data_size,

                            reinterpret_cast(tr.data.ptr.offsets),

                            tr.offsets_size/sizeof(size_t), this);

                    }

                } else {

                    freeBuffer(NULL,

                        reinterpret_cast(tr.data.ptr.buffer),

                        tr.data_size,

                        reinterpret_cast(tr.data.ptr.offsets),

                        tr.offsets_size/sizeof(size_t), this);

                    continue;

                }

            }

            goto finish;

 

        default:

            err = executeCommand(cmd);

            if (err != NO_ERROR) goto finish;

            break;

        }

    }

 

finish:

    if (err != NO_ERROR) {

        if (acquireResult) *acquireResult = err;

        if (reply) reply->setError(err);

        mLastError = err;

    }

 

    return err;

}

這裡transact把請求經核心模組傳送了給服務端,服務端處理完請求之後,沿原路返回結果給呼叫者。這裡也可以看出請求是同步操作,它會等待直到結果返回為止。

在BpBinder之上進行簡單包裝,我們可以得到與服務物件相同的介面,呼叫者無需要關心呼叫的物件是遠端的還是本地的。拿ServiceManager來說:
(frameworks/base/libs/utils/IServiceManager.cpp)

class BpServiceManager : public BpInterface

{

public:

    BpServiceManager(const sp& impl)

        : BpInterface(impl)

    {

    }

...

    virtual status_t addService(const String16& name, const sp& service)

    {

        Parcel data, reply;

        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());

        data.writeString16(name);

        data.writeStrongBinder(service);

        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

        return err == NO_ERROR ? reply.readInt32() : err;

    }

...

};

BpServiceManager 實現了 IServiceManager和IBinder兩個介面,呼叫者可以把BpServiceManager的物件看作是一個 IServiceManager物件或者IBinder物件。當呼叫者把BpServiceManager物件當作IServiceManager物件使 用時,所有的請求只是對BpBinder::transact的封裝。這樣的封裝使得呼叫者不需要關心IServiceManager物件是本地的還是遠 程的了。

客戶通過defaultServiceManager函式來建立BpServiceManager物件:
(frameworks/base/libs/utils/IServiceManager.cpp)

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::self()->getContextObject(NULL)建立一個Binder物件,然後通過 interface_cast和IMPLEMENT_META_INTERFACE(ServiceManager, “android.os.IServiceManager”)把Binder物件包裝成 IServiceManager物件。原理上等同於建立了一個BpServiceManager物件。

ProcessState::self()->getContextObject呼叫ProcessState::getStrongProxyForHandle建立代理物件:

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為空,預設為context_manager物件,context_manager實際上就是ServiceManager。
o 服務端
服務端也要實現IBinder介面,BBinder類對IBinder介面提供了部分預設實現,其中transact的實現如下:

status_t BBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

    data.setDataPosition(0);

 

    status_t err = NO_ERROR;

    switch (code) {

        case PING_TRANSACTION:

            reply->writeInt32(pingBinder());

            break;

        default:

            err = onTransact(code, data, reply, flags);

            break;

    }

 

    if (reply != NULL) {

        reply->setDataPosition(0);

    }

 

    return err;

}

PING_TRANSACTION 請求用來檢查物件是否還存在,這裡簡單的把 pingBinder的返回值返回給呼叫者。其它的請求交給onTransact處理。onTransact是BBinder裡宣告的一個 protected型別的虛擬函式,這個要求它的子類去實現。比如CameraService裡的實現如下:

status_t CameraService::onTransact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

    // permission checks...

    switch (code) {

        case BnCameraService::CONNECT:

            IPCThreadState* ipc = IPCThreadState::self();

            const int pid = ipc->getCallingPid();

            const int self_pid = getpid();

            if (pid != self_pid) {

                // we're called from a different process, do the real check

                if (!checkCallingPermission(

                        String16("android.permission.CAMERA")))

                {

                    const int uid = ipc->getCallingUid();

                    LOGE("Permission Denial: "

                            "can't use the camera pid=%d, uid=%d", pid, uid);

                    return PERMISSION_DENIED;

                }

            }

            break;

    }

 

    status_t err = BnCameraService::onTransact(code, data, reply, flags);

 

    LOGD("+++ onTransact err %d code %d", err, code);

 

    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {

        // the 'service' command interrogates this binder for its name, and then supplies it

        // even for the debugging commands.  that means we need to check for it here, using

        // ISurfaceComposer (since we delegated the INTERFACE_TRANSACTION handling to

        // BnSurfaceComposer before falling through to this code).

 

        LOGD("+++ onTransact code %d", code);

 

        CHECK_INTERFACE(ICameraService, data, reply);

 

        switch(code) {

        case 1000:

        {

            if (gWeakHeap != 0) {

                sp h = gWeakHeap.promote();

                IMemoryHeap *p = gWeakHeap.unsafe_get();

                LOGD("CHECKING WEAK REFERENCE %p (%p)", h.get(), p);

                if (h != 0)

                    h->printRefs();

                bool attempt_to_delete = data.readInt32() == 1;

                if (attempt_to_delete) {

                    // NOT SAFE!

                    LOGD("DELETING WEAK REFERENCE %p (%p)", h.get(), p);

                    if (p) delete p;

                }

                return NO_ERROR;

            }

        }

        break;

        default:

            break;

        }

    }

    return err;

}

由此可見,服務端的onTransact是一個請求分發函式,它根據請求碼(code)做相應的處理。

o 訊息迴圈

服務端(任何程式都可以作為服務端)有一個執行緒監聽來自客戶端的請求,並迴圈處理這些請求。

如果在主執行緒中處理請求,可以直接呼叫下面的函式:

IPCThreadState::self()->joinThreadPool(mIsMain);

如果想在非主執行緒中處理請求,可以按下列方式:

        sp

 proc = ProcessState::self();

        if (proc->supportsProcesses()) {

            LOGV("App process: starting thread pool.\n");

            proc->startThreadPool();

        }

startThreadPool的實現原理:

void ProcessState::startThreadPool()

{

    AutoMutex _l(mLock);

    if (!mThreadPoolStarted) {

        mThreadPoolStarted = true;

        spawnPooledThread(true);

    }

}

 

void ProcessState::spawnPooledThread(bool isMain)

{

    if (mThreadPoolStarted) {

        int32_t s = android_atomic_add(1, &mThreadPoolSeq);

        char buf[32];

        sprintf(buf, "Binder Thread #%d", s);

        LOGV("Spawning new pooled thread, name=%s\n", buf);

        sp

 t = new PoolThread(isMain);

        t->run(buf);

    }

}

這裡建立了PoolThread的物件,實現上就是建立了一個執行緒。所有的執行緒類都要實現threadLoop虛擬函式。PoolThread的threadLoop的實現如下:

    virtual bool threadLoop()

    {

        IPCThreadState::self()->joinThreadPool(mIsMain);

        return false;

    }

上述程式碼,簡而言之就是建立了一個執行緒,然後線上程裡呼叫 IPCThreadState::self()->joinThreadPool函式。

下面再看joinThreadPool的實現:

do

{

...

        result = talkWithDriver();

        if (result >= NO_ERROR) {

            size_t IN = mIn.dataAvail();

            if (IN < sizeof(int32_t)) continue;

            cmd = mIn.readInt32();

            IF_LOG_COMMANDS() {

                alog << "Processing top-level Command: "

                    << getReturnString(cmd) << endl;

            }

            result = executeCommand(cmd);

        }

...

while(...);

這個函式在迴圈中重複執行下列動作:

talkWithDriver 通過ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)讀取請求和寫回結果。

executeCommand 執行相應的請求

在IPCThreadState::executeCommand(int32_t cmd)函式中:

對於控制物件生命週期的請求,像BR_ACQUIRE/BR_RELEASE直接做了處理。

對於BR_TRANSACTION請求,它呼叫被請求物件的transact函式。

按下列方式呼叫實際的物件:

if (tr.target.ptr) {

    sp<BBinder> b((BBinder*)tr.cookie);

    const status_t error = b->transact(tr.code, buffer, &reply, 0);

    if (error < NO_ERROR) reply.setError(error);

 

} else {

    const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);

    if (error < NO_ERROR) reply.setError(error);

}

如 果tr.target.ptr不為空,就把tr.cookie轉換成一個Binder物件,並呼叫它的transact函式。如果沒有目標物件,就呼叫 the_context_object物件的transact函式。奇怪的是,根本沒有誰對the_context_object進行初始 化,the_context_object是空指標。原因是context_mgr的請求發給了ServiceManager,所以根本不會走到else 語句裡來。

o 核心模組

android 使用了一個核心模組binder來中轉各個程式之間的訊息。模組原始碼放在binder.c裡,它是一個字元驅動程式,主要通過binder_ioctl 與使用者空間的程式交換資料。其中BINDER_WRITE_READ用來讀寫資料,資料包中有一個cmd域用於區分不同的請求:

binder_thread_write用於傳送請求或返回結果。

binder_thread_read用於讀取結果。

從binder_thread_write中呼叫binder_transaction中轉請求和返回結果,binder_transaction的實現如下:

對請求的處理:

通過物件的handle找到物件所在的程式,如果handle為空就認為物件是context_mgr,把請求發給context_mgr所在的程式。

把請求中所有的binder物件全部放到一個RB樹中。

把請求放到目標程式的佇列中,等待目標程式讀取。

如何成為context_mgr呢?核心模組提供了BINDER_SET_CONTEXT_MGR呼叫:

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

         ...

         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->euid) {

                                   printk(KERN_ERR "binder: BINDER_SET_"

                                          "CONTEXT_MGR bad uid %d != %d\n",

                                          current->euid,

                                          binder_context_mgr_uid);

                                   ret = -EPERM;

                                   goto err;

                          }

                 } else

                          binder_context_mgr_uid = current->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;

ServiceManager(frameworks/base/cmds/servicemanager)通過下列方式成為了context_mgr程式:

int binder_become_context_manager(struct binder_state *bs)

{

    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);

}

 

int main(int argc, char **argv)

{

    struct binder_state *bs;

    void *svcmgr = BINDER_SERVICE_MANAGER;

 

    bs = binder_open(128*1024);

 

    if (binder_become_context_manager(bs)) {

        LOGE("cannot become context manager (%s)\n", strerror(errno));

        return -1;

    }

 

    svcmgr_handle = svcmgr;

    binder_loop(bs, svcmgr_handler);

    return 0;

}

o 如何得到服務物件的handle

服務提供者通過defaultServiceManager得到ServiceManager物件,然後呼叫addService向服務管理器註冊。

服務使用者通過defaultServiceManager得到ServiceManager物件,然後呼叫getService通過服務名稱查詢到服務物件的handle。

o 如何通過服務物件的handle找到服務所在的程式

0表示服務管理器的handle,getService可以查詢到系統服務的handle。這個handle只是代表了服務物件,核心模組是如何通過handle找到服務所在的程式的呢?

對於ServiceManager: ServiceManager呼叫了binder_become_context_manager使用自己成為context_mgr,所有handle為0的請求都會被轉發給ServiceManager。

對於系統服務和應用程式的Listener,在第一次請求核心模組時(比如呼叫addService),核心模組在一個RB樹中建立了服務物件和程式的對應關係。

         off_end = (void *)offp + tr->offsets_size;

         for (; offp < off_end; offp++) {

                 struct flat_binder_object *fp;

                 if (*offp > t->buffer->data_size - sizeof(*fp)) {

                          binder_user_error("binder: %d:%d got transaction with "

                                   "invalid offset, %d\n",

                                   proc->pid, thread->pid, *offp);

                          return_error = BR_FAILED_REPLY;

                          goto err_bad_offset;

                 }

                 fp = (struct flat_binder_object *)(t->buffer->data + *offp);

                 switch (fp->type) {

                 case BINDER_TYPE_BINDER:

                 case BINDER_TYPE_WEAK_BINDER: {

                          struct binder_ref *ref;

                          struct binder_node *node = binder_get_node(proc, fp->binder);

                          if (node == NULL) {

                                   node = binder_new_node(proc, fp->binder, fp->cookie);

                                   if (node == NULL) {

                                            return_error = BR_FAILED_REPLY;

                                            goto err_binder_new_node_failed;

                                   }

                                   node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;

                                   node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);

                          }

                          if (fp->cookie != node->cookie) {

                                   binder_user_error("binder: %d:%d sending u%p "

                                            "node %d, cookie mismatch %p != %p\n",

                                            proc->pid, thread->pid,

                                            fp->binder, node->debug_id,

                                            fp->cookie, node->cookie);

                                   goto err_binder_get_ref_for_node_failed;

                          }

                          ref = binder_get_ref_for_node(target_proc, node);

                          if (ref == NULL) {

                                   return_error = BR_FAILED_REPLY;

                                   goto err_binder_get_ref_for_node_failed;

                          }

                          if (fp->type == BINDER_TYPE_BINDER)

                                   fp->type = BINDER_TYPE_HANDLE;

                          else

                                   fp->type = BINDER_TYPE_WEAK_HANDLE;

                          fp->handle = ref->desc;

                          binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);

                          if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)

                                   printk(KERN_INFO "        node %d u%p -> ref %d desc %d\n",

                                          node->debug_id, node->ptr, ref->debug_id, ref->desc);

                 } break;

請求服務時,核心先通過handle找到對應的程式,然後把請求放到服務程式的佇列中。

o C呼叫JAVA

前面我們分析的是C程式碼的處理。對於JAVA程式碼,JAVA呼叫C的函式通過JNI呼叫即可。從核心時讀取請求是在C程式碼(executeCommand)裡進行了,那如何在C程式碼中呼叫那些用JAVA實現的服務呢?

android_os_Binder_init裡的JavaBBinder對Java裡的Binder物件進行包裝。

JavaBBinder::onTransact呼叫Java裡的execTransact函式:

        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,

            code, (int32_t)&data, (int32_t)reply, flags);

        jthrowable excep = env->ExceptionOccurred();

        if (excep) {

            report_exception(env, excep,

                "*** Uncaught remote exception!  "

                "(Exceptions are not yet supported across processes.)");

            res = JNI_FALSE;

 

            /* clean up JNI local ref -- we don't return to Java code */

            env->DeleteLocalRef(excep);

        }

o 廣播訊息

binder不提供廣播訊息,不過可以ActivityManagerService服務來實現廣播。
(frameworks/base/core/java/android/app/ActivityManagerNative.java)

接收廣播訊息需要實現介面BroadcastReceiver,然後呼叫ActivityManagerProxy::registerReceiver註冊。

觸發廣播呼叫ActivityManagerProxy::broadcastIntent。(應用程式並不直接呼叫它,而是呼叫Context對它的包裝)


Binder的實質就是要把物件從一個程式對映到另一個程式中,而不管這個物件是本地的還是遠端的。如果是本地物件,更好理解;如果是遠端物件,就按照我 們上面所講的來理解,即將遠端物件的“引用”從一個程式對映到另一個程式中,於是當使用這個遠端物件時,實際上就是使用遠端物件在本地的一個“引用”,類 似於把這個遠端物件當作一個本地物件在使用。這也就是Binder與其他IPC機制不同的地方。


轉自: http://my.oschina.net/zhangqingcai/blog/28547


更多Binder相關底層實現: http://book.51cto.com/art/201105/265299.htm

              http://blog.csdn.net/luoshengyang/article/details/6618363

              http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html

相關文章