`

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. 把请求放到目标进程的队列
      分享到:
      评论

    相关推荐

      Android IPC机制Messenger实例详解

      主要介绍了 Android IPC机制Messenger实例详解的相关资料,需要的朋友可以参考下

      详解Android跨进程IPC通信AIDL机制原理

      本篇文章主要介绍了详解Android跨进程IPC通信AIDL机制原理,详细的介绍了AIDL的概念和使用,具有一定的参考价值,有兴趣的可以了解一下

      Android主要机制深入分析

      Android 核心分析(25)------Android GDI 之共享缓冲区机制................................ 112 Android 核心分析(26)-----Android GDI 之SurfaceFlinger..................................... 116 Android ...

      android核心分析pdf

      Android核心分析(25)----Android GDI之共享缓冲区机制 Android核心分析(26)----Android GDI之SurfaceFlinger Android核心分析(27)----Android GDI SurfaceFlinger之动态结构示意图 Android核心分析(28)----...

      ANDROID源码分析实录

      《Android源码分析实录》共分为15章,主要内容包括走进Android世界、硬件抽象层详解、分析JNI(Java本地接口)层、Android内存系统分析、Andmid虚拟机系统详解、IPC通信机制详解、Zygote进程/System进程和应用程序...

      Android核心分析(pdf)

      Android核心分析(25)----Android GDI之共享缓冲区机制 Android核心分析(26)----Android GDI之SurfaceFlinger Android核心分析(27)----Android GDI SurfaceFlinger之动态结构示意图 Android核心分析(28)----...

      [经典文档]Android核心分析

      核心分析之二十四 ----- Android GDI之共享缓冲区机制 核心分析之二十五 ----- Android GDI之SurfaceFlinger 核心分析之二十六 ----- Android GDI之SurfaceFlinger动态结构示意图 核心分析之二十七 ----- Android ...

      浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路

      本文主要介绍 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路,这里详细介绍了相关Binder的资料,帮助大家理解学习Android 源码Binder通信机制,有兴趣的小伙伴可以参考下

      android 核心分析

      Android 核心分析(25)------Android GDI 之共享缓冲区机制................................ 112 Android 核心分析(26)-----Android GDI 之 SurfaceFlinger..................................... 116 Android 核心...

      Android核心设计思想分析

      Android核心分析(25)------AndroidGDI之共享缓冲区机制................................112 Android核心分析(26)-----AndroidGDI之SurfaceFlinger.....................................116 Android核心分析...

      移动安全系列教学下载共43份.zip

      Android安全开发基础--6--进程间通信机制(IPC).pdf Android安全开发基础--7--JVM Dalvik ART虚拟机.pdf Android安全开发基础--8--Java本地接口(JNI).pdf Android安全开发基础--9--Android系统的启动过程分析.pdf...

      Android核心分析

      Android 核心分析( 25 ) ------Android GDI 之共享缓冲区机制 ................................ 112 Android 核心分析( 26 ) -----Android GDI 之 SurfaceFlinger ..................................... 116 ...

      【推荐】超全的移动安全自学资料精编合集(43份).zip

      Android安全开发基础: 进程间通信机制(IPC) Android安全开发基础: JVM Dalvik ART虚拟机 Android安全开发基础: Java本地接口(JNI) Android安全开发基础: Android系统的启动过程分析 Android安全开发基础: 图形...

      Android进程通信之Messenger和AIDL使用详解

      提到的进程间通信(IPC:Inter-Process Communication),在Android系统中,一个进程是不能直接访问另一个进程的内存的,需要提供一些机制在不同的进程之间进行通信,Android官方推出了AIDL(Android Interface ...

    Global site tag (gtag.js) - Google Analytics