본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[android/안드로이드] aidl 을 이용하여 service 에 bind 하기.

by 돼지왕 왕돼지 2012. 2. 8.
반응형

안녕하세요 돼지왕왕돼지입니다.
오늘은 aidl을 이용하여 원격 서비스에 bind 하는 방법에 대해 알아보도록 하겠습니다.


AIDL 이 뭐고, 왜 필요해요?


- Android에서는 기본적으로 process간 memory 접근이 불가능합니다. Process간 Communication을 위해서는 운영체제가 이해할 수 있는 primitive형태로 object를 marshalling ( 분해의 개념 ) 받는 측에서 unmarshalling ( 조립의 개념 ) 해준다면 가능합니다.
 
AIDL ( Android Interface Definition Language ) 가 marshalling & unmarshalling 작업을 해줍니다. (직접하려면 엄청 어렵다고 합니다.) 이 AIDL을 통해 IPC ( InterProcess Communication )이 가능해 집니다.
 
 


AIDL 사용해서 IPC 구현하는법, 즉 bind 하는 법 알려주세요.


1. .aidl 파일 생성


AIDL은 Java의 primitive type에 대해서는 import 없이 쓸 수 있습니다. String, CharSequence, List류, Map류도 import 없이 사용 할 수 있습니다. 앞에서 제시한 primitive type과 기본 object 류를 제외하고는 parameter 값으로 사용할 때, in, out, inout 을 설정해줘야 합니다. ( in 이 default 입니다 )

다음이 aidl 파일의 default format 입니다.

package [PACKAGE NAME]
import [위에 정의되지 않은 TYPE들]

interface [INTERFACE NAME]{
  int [FUNCTION명]( [PARAMETERS] );
}







2. makefile에 .aidl 추가 


이클립스를 사용한다면 이 단계는 pass 해도 됩니다. 다만, gen 에 aidl 에 매칭되는 java 파일이 생성되는지를 꼭 확인해야합니다.
이클립스 ADT 플러그인이 이 java 파일의 생성을 알아서 해줍니다. ( 안드로이드 tools/ 폴더에 AIDL 이라 불리는 컴파일러가 있다지요? )

만약 자체적으로 build 를 한다면, makefile 에 .aidl 을 추가해주어야 합니다.
대부분 이클립스를 사용하기 때문에 그 내용을 다루진 않겟습니다.



3. Interface method 구현. 

AIDL이 만든 인터페이스 파일은 Stub 이라는 내부 추상 클래스를 가지는데, 이 녀석을 구현해주어야 합니다.

// @ Service
private final [AIDL Interface 명].Stub mBinder = new [AIDL Interface 명].Stub(){
    // implementation
    public [return value] [.aidl에 정의한 함수명]{
        // to sth..
    }
}  

 
- RPC ( Remote Process Call )는 synchronized call ( 동기화 호출 )입니다. 따라서 해당 aidl 함수가 오랜 시간 작업 후에 return 을 한다면 main thread 에서 호출을 하면 안됩니다. Main Thread에서 호출 시 ANR 을 초래할 수 있습니다. 

- AIDL 에서는 method만을 지원합니다. static field 는 지원하지 않습니다.
 
- AIDL function 에서 throw 하는 exception은 caller 에게 전달되지 않습니다.
 
 
 

4. 인터페이스를 client에게 제시하기

 
 

@ Service
// several interface can be provided
public Ibinder onBind( Intent intent ){
    if ( [AIDL 인터페이스 이름1].class.getName().equals( intent.getAction() ) ){
       return mBinder;
    } 
    if ( [AIDL 인터페이스 이름2].class.getName().equals( intent.getAction() ) ){
       return mSecondaryBinder;
    }
}

private final [AIDL 인터페이스 이름1].Stub mBinder = new  [AIDL 인터페이스 이름1] .Stub(){
  // impleement.
}
 
private final  [AIDL 인터페이스 이름2] .Stub mSecondaryBinder = new  [AIDL 인터페이스 이름2] .Stub(){
  // Implement.
}






 
[Parcelable Object 도 parameter 로 전달 가능하다.]
 
  
 

5. IPC method 호출


  5-1. .aidl 파일이 정의했던 인터페이스 타입 변수 선언

  5-2. ServiceConnection 구현

  5-3. ServiceConnection 구현 전달하는 Context.bindService() 호출

  5-4. ServiceConnection.onServiceConnected() 에서 IBinder instance를 받는다.  여기서 asInterface( (IBinder) service )를 호출.

  5-5. DeadObjectException 처리를 항상 해주며, (유일한 exception). Interface를 통해 함수를 호출한다.

  5-6. 연결을 끊으려면, Context.unbindService()를 호출한다.

[AIDL 인터페이스 이름] mService;

@ServiceConnection 의 onServiceConnected callback function
public void onServiceConnected( ComponentName name, IBinder service ){
     mService = [AIDL 인터페이스 이름].Stub.asInterface( service );

}

// 사용
try{
     mService.[aidl function]; 
}
catch( DeadObjectException e ){
     //...



이상입니다. 
여러분도 이제 AIDL 을 쉽게 사용할 수 있겠죠?? 
 





반응형

댓글