안드로이드 프레임워크 프로그래밍(18) [Native에서 원하는 ServiceManager 불러오기]

 요즘 안드로이드 Framework를 공부하면서 드는 생각이 있습니다. 정말 구글의 안드로이드 제작자들이 경이롭다고 생각될 정도로 안드로이드 운영체제는 심오하면서도 동작원리가 매우 신기하다는 생각이 듭니다.

 이번 포스팅에서는 Native에서 등록하였던 Service를 ServiceManager에서 불러들이는 과정에 대해 살펴보도록 하겠습니다.


 먼저 예제로 CameraService를 불러들이는 예제를 살펴보도록 하겠습니다.


/frameworks/av/camera/CameraBase.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace {
    sp<ICameraService>        gCameraService;
    const int                 kCameraServicePollDelay = 500000// 0.5s
    const char*               kCameraServiceName      = "media.camera";
 
    Mutex                     gLock;
 
    class DeathNotifier : public IBinder::DeathRecipient
    {
    public:
        DeathNotifier() {
        }
 
        virtual void binderDied(const wp<IBinder>& who) {
            ALOGV("binderDied");
            Mutex::Autolock _l(gLock);
            gCameraService.clear();
            ALOGW("Camera service died!");
        }
    };
 
    sp<DeathNotifier>         gDeathNotifier;
}; // namespace anonymous
cs

/frameworks/av/camera/CameraBase.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
    Mutex::Autolock _l(gLock);
    if (gCameraService.get() == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16(kCameraServiceName));
            if (binder != 0) {
                break;
            }
            ALOGW("CameraService not published, waiting...");
            usleep(kCameraServicePollDelay);
        } while(true);
        if (gDeathNotifier == NULL) {
            gDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(gDeathNotifier);
        gCameraService = interface_cast<ICameraService>(binder);
    }
    ALOGE_IF(gCameraService == 0"no CameraService!?");
    return gCameraService;
}
cs

 위에서 보시는 바와 같이 ServiceManager를 통해 getService() 함수로 CameraService의 바인더를 불러오고 있는 모습을 보실 수 있습니다. 그렇다면 위의 바인더가 어떠한 방식으로 호출이 되는지 자세히 알아보도록 하겠습니다.


/frameworks/native/libs/binder/IServiceManager.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)
    {
    }
 
    virtual sp<IBinder> getService(const String16& name) const
    {
        unsigned n;
        for (n = 0; n < 5; n++){
            sp<IBinder> svc = checkService(name);
            if (svc != NULL) return svc;
            ALOGI("Waiting for service %s...\n", String8(name).string());
            sleep(1);
        }
        return NULL;
    }
 
    virtual sp<IBinder> checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        return reply.readStrongBinder();
    }
....
}
cs

 IServiceManager.cpp 내에 있는 BpServiceManager를 통해 Binder를 받는 과정을 나타내고 있습니다. 위 과정을 마치게 되면 Binder를 CameraService의 Binder를 얻을 수 있게 됩니다.

 getService() 함수를 통해 부르고자 하는 Service의 명을 전달 받은 후 그 안에 있는 checkService()함수를 호출하여 Parcel을 통해 원하는 Service의 Binder를 얻게 됩니다.


혹시 위에서 Binder를 받기 위해 활용되는 Parcel에 대해 자세히 알고 싶으신 분께서는 아래 포스팅을 참조해 주시기 바랍니다.

안드로이드 프레임워크 프로그래밍(15) [Native 단계에서의 Parcel 전송(1)]

안드로이드 프레임워크 프로그래밍(16) [Native 단계에서의 Parcel 전송(2)]


여기서 chechService() 함수의 동작 과정에 대해 살펴보도록 하겠습니다.


Parcel data, reply;

전송보낼 data와 전송을 받을 reply인 Parcel 클래스 변수를 선언합니다.


data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());

data Parcel에 인터페이스 토큰을 작성합니다. 여기서 인자값으로 들어오는 값은 "android.os.IServiceManager"입니다.

위 함수에 대해 좀 더 자세히 알고 싶으신 분은 아래 포스팅을 참조해 주시기 바랍니다.


http://elecs.tistory.com/87


data.writeString16(name);

찾고자 하는 System Service의 이름을 입력합니다. 여기에서는 "media.camera"가 되겠군요.


remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);

지금까지 data에 기록하였던 내용을 Binder로 전송합니다. 이 과정을 통해 reply로  data의 내용에 대한 응답인 Parcel을 전송받게 됩니다.


return reply.readStrongBinder();

전달 받은 Parcel인 reply를 통해 Service의 BpBinder를 반환합니다.

여기서 수신된 Parcel로부터 binder를 얻는 과정을 살펴보도록 합니다.


/frameworks/native/libs/binder/Parcel.cpp


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}
 
....
 
status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);
    
    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}
 
....
 
inline static status_t finish_unflatten_binder(
    BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
{
    return NO_ERROR;
}
cs

 위 코드의 주요 내용들을 하나씩 살펴보도록 하겠습니다.


const flat_binder_object* flat = in.readObject(false);

수신된 Parcel로부터 값을 읽어들입니다. 이 과정에서 flat_binder_object 구조체값이 넘어오게 됩니다.

이렇게 해서 넘어온 구조체값의 type는 BINDER_TYPE_HANDLE이 설정되어 있습니다.


*out = proc->getStrongProxyForHandle(flat->handle);

flat_binder_object에 저장된 서비스 핸들을 전달하여 BpBinder를 얻습니다. 위 함수의 구조는 다음과 같이 되어 있음을 확인하실 수 있습니다.

아래는 해당 함수가 동작하는 과정에 대해 확인해 보고자 하는 목적으로 첨부합니다.

위 함수에 대해 좀 더 자세한 내용을 참조하고 싶으신 분께서는 아래 포스팅을 참조해 주시길 바랍니다.


http://elecs.tistory.com/89


/frameworks/native/libs/binder/ProcessState.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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)) {
            if (handle == 0) {
                // Special case for context manager...
                // The context manager is the only object for which we create
                // a BpBinder proxy without already holding a reference.
                // Perform a dummy transaction to ensure the context manager
                // is registered before we create the first local reference
                // to it (which will occur when creating the BpBinder).
                // If a local reference is created for the BpBinder when the
                // context manager is not present, the driver will fail to
                // provide a reference to the context manager, but the
                // driver API does not return status.
                //
                // Note that this is not race-free if the context manager
                // dies while this code runs.
                //
                // TODO: add a driver API to wait for context manager, or
                // stop special casing handle 0 for context manager and add
                // a driver API to get a handle to the context manager with
                // proper reference counting.
 
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
 
            = 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;
}
 
 
cs

return finish_unflatten_binder(

                    static_cast<BpBinder*>(out->get()), *flat, in);

위 과정을 통해 이 함수의 수행이 무사히 수행되었음을 NO_ERROR을 반환함으로서 종료합니다.



이제 이 즈음에서 우리들이 처음부터 연구하였던 소스 CameraBase.cpp의 getService() 이후의 동작들에 대해 파악해 보도록 합시다.


/frameworks/av/camera/CameraBase.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
    Mutex::Autolock _l(gLock);
    if (gCameraService.get() == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16(kCameraServiceName));
            if (binder != 0) {
                break;
            }
            ALOGW("CameraService not published, waiting...");
            usleep(kCameraServicePollDelay);
        } while(true);
        if (gDeathNotifier == NULL) {
            gDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(gDeathNotifier);
        gCameraService = interface_cast<ICameraService>(binder);
    }
    ALOGE_IF(gCameraService == 0"no CameraService!?");
    return gCameraService;
}
cs


이제 위에서 남은 두 함수들에 대해 분석을 해 보도록 하겠습니다.


binder->linkToDeath(gDeathNotifier);

 getService() 함수를 통해 얻은 binder에 gDeathNotifier를 틍록합니다. linkToDeath() 함수는 해당 binder가 의도치 않은 상황에서 종료가 되었을 때 해당 클래스를 실행하라는 의도로 생각하시면 되겠습니다.


/frameworks/av/camera/CameraBase.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace {
    sp<ICameraService>        gCameraService;
    const int                 kCameraServicePollDelay = 500000// 0.5s
    const char*               kCameraServiceName      = "media.camera";
 
    Mutex                     gLock;
 
    class DeathNotifier : public IBinder::DeathRecipient
    {
    public:
        DeathNotifier() {
        }
 
        virtual void binderDied(const wp<IBinder>& who) {
            ALOGV("binderDied");
            Mutex::Autolock _l(gLock);
            gCameraService.clear();
            ALOGW("Camera service died!");
        }
    };
 
    sp<DeathNotifier>         gDeathNotifier;
}; // namespace anonymous
cs


gCameraService = interface_cast<ICameraService>(binder);

 위 코드를 통해 CameraService가 binder를 통해 등록됩니다. 이 함수가 어떻게 동작하는지 확인해 보도록 하겠습니다. 해당 함수에서 사용되는 기술에 대해 자세히 알고 싶으신 분은 아래 포스팅을 참조해 주시길 바랍니다.


http://elecs.tistory.com/87

http://elecs.tistory.com/88


/frameworks/av/include/camera/ICameraService.h

1
2
3
4
5
6
7
8
9
#include <binder/IInterface.h>
 
class ICameraService : public IInterface
{
....
public:
    DECLARE_META_INTERFACE(CameraService);
....
}
cs

/frameworks/native/include/binder/IInterface.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
....
#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \
 
 
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \
....
 
cs


/frameworks/av/camera/ICameraService.cpp

1
2
3
#include <binder/IInterface.h>
 
IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
cs


 위 내용을 종합하면 다음과 같은 내용임을 알아낼 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    static android::sp<ICameraService> asInterface(
            const android::sp<android::IBinder>& obj);
 
    const android::String16 ICameraService::descriptor("android.hardware.ICameraService");
    android::sp<ICameraService> ICameraService::asInterface(
            const android::sp<android::IBinder>& obj)
    {
        android::sp<ICameraService> intr;
        if (obj != NULL) {
            intr = static_cast<ICameraService*>(
                obj->queryLocalInterface(
                        ICameraService::descriptor).get());
            if (intr == NULL) {
                intr = new BpCameraService(obj);
            }
        }
        return intr;
    } 
cs

위 코드를 통해 gCameraService 내에 BpCameraService 클래스가 선언되는 것을 확인할 수 있다.

300x250