IPC 메커니즘 Binder 분석

이선정
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;
}

매개변수 설명:
  • 코드는 요청된 ID 번호입니다.
  • 데이터는 요청한 매개 변수입니다.
  • reply가 되돌아온 결과입니다.
  • flags FLAG 와 같은 추가 IDONEWAY.일반적으로 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 위에서 간단한 포장을 하면 우리는 서비스 대상과 같은 인터페이스를 얻을 수 있고 호출자는 호출 대상이 원격인지 로컬인지에 관심을 가질 필요가 없다.Service Manager의 경우: (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;
    }
    ...
    } ;

    BpService Manager는 IService Manager와 Ibinder 두 인터페이스를 실현하고 호출자는 BpService Manager의 대상을 하나의 IService Manager 대상이나 Ibinder 대상으로 볼 수 있다.호출자가 BpService Manager 대상을 IService Manager 대상으로 사용할 때, 모든 요청은 BpBinder::transact에 대한 봉인일 뿐입니다.이러한 봉인으로 인해 호출자는 IService Manager의 대상이 로컬인지 원격인지 신경 쓸 필요가 없다.
    고객은defaultService Manager 함수를 사용하여 BpService Manager 객체를 만듭니다. (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 대상을 만들고interfacecast 및 IMPLEMENTMETA_INTERFACE(Service Manager, android.os.IService Manager)는 Binder 대상을 IService Manager 대상으로 포장합니다.원리적으로 BpService Manager 객체가 만들어진 것과 같습니다.
    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관리자 객체, context관리자는 실제로 Service Manager입니다.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은 대상이 존재하는지 확인하기 위해 요청합니다. 핑빈더의 반환 값을 호출자에게 간단하게 되돌려줍니다.다른 요청은 onTransact 처리에 맡깁니다.onTransact는 Bbinder에서 설명한 보호된 형식의 허함수입니다. 이것은 하위 클래스를 실현해야 합니다.예를 들어 Camera Service의 구현은 다음과 같습니다.
    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)을 통해 요청을 읽고 결과를 되돌려줍니다.
  • excuteCommand에서 요청 수행
  • IPCthreadState::executeCommand(int32 t cmd) 함수에서 다음을 수행합니다.
  • 객체의 라이프 사이클을 제어하는 요청, 예를 들어 BRACQUIRE/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 함수입니다.이상하게도 아무도 thecontext_object 초기화, thecontext_object는 빈 포인터입니다.이유는 contextmgr의 요청이 서비스 관리자에게 보내졌기 때문에else 문장에 오지 않습니다.
    o 코어 모듈
    android는 프로세스 간의 메시지를 전달하기 위해 내장 모듈binder를 사용합니다.모듈 소스 코드는binder에 있습니다.c에서, 이것은 문자 드라이버로 주로 binder 를 통과한다ioctl은 사용자 공간의 프로세스와 데이터를 교환합니다.여기서 BINDERWRITE_READ는 데이터를 읽고 쓰는 데 사용되며, 패키지의 cmd 도메인은 여러 요청을 구분하는 데 사용됩니다.
  • binder_thread_write는 요청을 보내거나 결과를 되돌려 주는 데 사용됩니다.
  • binder_thread_read는 결과를 읽는 데 사용됩니다.

  • binder 에서thread_write에서 binder 호출transaction에서 요청 및 반환 결과,bindertransaction의 구현은 다음과 같습니다.
    요청 처리:
  • 대상의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 ;

    Service Manager(frameworks/base/cmds/서비스 관리자)는 다음과 같은 방식으로 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을 어떻게 얻는가
  • 서비스 제공자는default Service Manager를 통해 서비스 관리자의 대상을 받고add Service를 호출하여 서비스 관리자에 등록합니다.
  • 서비스 사용자는default Service Manager를 통해 서비스 매니저의 대상을 받은 다음 get Service를 호출하여 서비스 이름으로 서비스 대상의handle을 찾습니다.

  • o 서비스 대상의handle을 통해 서비스가 있는 프로세스를 어떻게 찾습니까
    0은 서비스 관리자의handle을 표시하고 get 서비스는 시스템 서비스의handle을 찾을 수 있습니다.이handle은 서비스 대상을 대표할 뿐입니다. 내부 모듈은handle을 통해 서비스가 있는 프로세스를 어떻게 찾습니까?
  • Service Manager: Service Manager에서 binder 호출됨become_context_관리자가 자신을 사용하여 contextmgr, 모든 handle이 0인 요청은 서비스 관리자에게 전송됩니다.
  • 시스템 서비스와 응용 프로그램의 Listener에 대해 첫 번째 커널 모듈을 요청할 때(예를 들어add Service를 호출할 때) 커널 모듈은 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 코드(execute Command)에서 이루어졌는데, 어떻게 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는 브로드캐스트 메시지를 제공하지 않지만 Activity Manager 서비스로 브로드캐스트를 수행할 수 있습니다.(frameworks/base/core/java/android/app/ActivityManagerNative.java)
    브로드캐스트 메시지를 수신하려면 인터페이스BroadcastReceiver를 실행한 다음ActivityManagerProxy::registerReceiver 등록을 호출해야 합니다.
    ActivityManagerProxy:::broadcastIntent 를 트리거하여 호출합니다.(응용 프로그램은 그것을 직접 호출하지 않고 컨텍스트 포장을 호출한다)

    좋은 웹페이지 즐겨찾기