(转)Android IPC机制详解

o 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
(
...)
;

这个函数在循环中重复执行下列动作:

  1. talkWithDriver 通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)读取请求和写回结果。
  2. executeCommand 执行相应的请求

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

  1. 对于控制对象生命周期的请求,像BR_ACQUIRE/BR_RELEASE直接做了处理。
  2. 对于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域用于区分不同的请求:

  1. binder_thread_write用于发送请求或返回结果。
  2. binder_thread_read用于读取结果。

从binder_thread_write中调用binder_transaction中转请求和返回结果,binder_transaction的实现如下:

对请求的处理:

  1. 通过对象的handle找到对象所在的进程,如果handle为空就认为对象是context_mgr,把请求发给context_mgr所在的进程。
  2. 把请求中所有的binder对象全部放到一个RB树中。
  3. 把请求放到目标进程的队列
原文地址:https://www.cnblogs.com/greywolf/p/3031194.html