안드로이드는 크게 2가지 native(c++)과 java framework로 나뉘며 java framework 에서는 JNI를 통해 native framework를 재사용할 수 있다.
여기서 자바 프레임워크 서비스는 크게 2가지 방법으로 관리가 되는데 하나는 native와 마찬가지로 context manager를 이용하여 서비스를 등록하고 사용하는 방법, 두 번째는 Activity Manager를 이용해서 서비스를 이용하는 방법이다.
1. 구조
기본적으로 JAVA 프레임워크의 동작도 native와 매우 유사하다 IPC를 통해 데이터를 주고받으며 해당 IPC부분은 native와 완전 동일하다 단, jni를 통해서 클라이언트 및 서버의 java단과 native단을 연결해주는 작업이 추가된 것이다.
Java Framework에서 proxy와 stub은 보통 AIDL을 통해서 자동 구현이 가능하다. 현재는 native 및 hal에 대해서도 AIDL이 지원 가능한 것으로 알고있다(Android 10인가 11부터 지원 가능한 것으로 알고있음..)
다시 말 해 AIDL언어로 작성을 하면 IInterface를 참조하는 해당 기능의 interface, proxy, stub이 자동으로 생성되고 java framework 통신을 진행하기 위한 골격이 완성된다.
2. Service Manager
결국에 java framework에서도 bind driver에 서비스를 등록하고 서비스를 find함으로써 native와 마찬가지로 동작한다. 다만 native에서는 바로 context manager를 호출해서 진행하지만,
Java 단에서는 바로 context manager를 호출할 수 없기 때문에 service manager를 호출하고 service manager가 jni를 통해 native단의 context manager를 호출함으로써 동작한다.
Service Manager는 Context Manager와 대화를 진행하기위해 Binder Proxy를 이용한다. Binder Proxy는 실제적으로 JNI를 통해 native로 연결되는 곳으로 Service Manager의 RPC값을 받아서 전달한다.
Service Manager의 동작을 조금 더 자세히 보면 위와 같다. 위 과정은 서비스를 등록하는 동작이다. (추가적으로 서비스를 find하는 과정은 native와 마찬가지로 등록 과정과 유사하다)
Service Manager에서 서비스 등록을 위해 addService()를 호출하면 BInderInternal을 통해 JNI 연결을 진행하고 native Layer에 존재하는 processState로 연결된다.
여기서 processState란 native에서도 context Manager 통신을 위한 BpBinder를 생성하는 역할을 담당한다. 즉 processState를 통해 BpBinder를 생성할 수 있다.
하지만 java framework에서 BpBinder 객체를 생성하고 접근하기 위해서는 BinderProxy라는 또 다른 객체가 필요하다. 때문에 다시 JNI를 통해 java단으로 올라가서 BpBinder 객체에 접근이 가능한 Binder Proxy 객체를 생성하게 된다. 그리고 이 객체를 접근하는 곳은 ServiceManagerProxy이다. 즉 다시 ServiceManagerProxy 객체가 생성된다.
이렇게 생성된 ServiecManagerProxy는 Service Manager에서 접근이 가능한 객체로 실제 addService를 실행하면 ServiecManagerProxy에서 해당 커맨드를 받고 BpBinder로 JNI르 통해 내려가서 Context Manager에 명령을 전달한다.
결과적으로 BinderInternal은 Context Manager동작을 위한 Service Manager의 초기화 과정이고 실제 addService와 같이 Context Manager접근을 통한 동작은 ServiceManager Proxy를 이용한다.
위에서 언급한 바와 같이 실제 Service를 find해서 사용하는 경우에도 Service Manager에서 ServiceManagerProxy의 getSerivce()함수를 호출함으로써 서비스 등록과 같은 구조로 동작한다.
3. Parcel
Parcel은 native에서 데이터 송수신 시 데이터를 전달하기위한 버퍼 역할을 했다. Parcel은 java framework service에서도 마찬가지로 buf 역할을 한다.
Java 역시 결국 통신은 IPC를 통한 native영역에서 이루어지며 이 때 native와 마찬가지로 parcel을 이용한다. 하지만 java단까지 data가 올라와야 되기 때문에 java단 Parcel도 존재한다.
즉 정리하면 jni를 통해 Parcel(java)와 Parcel(native)가 통신하며 실제 IPC는 기존 native와 마찬가지로 동작한다고 볼 수 있다.
Ref
https://dev-ahn.tistory.com/92
[책] 인사이드 안드로이드