안드로이드 Native 코드 분석 : IMPLEMENT_META_INTERFACE()

안드로이드/프레임워크 2015. 3. 27. 00:46

 안드로이드 프레임워크를 분석하는 과정에서 시스템 서비스와 관련된 부분에 대해 분석을 하다보면 다음과 같은 이름의 함수를 만나보실 수 있을 것입니다.


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

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");


 위 함수는 겉으로 보기에는 뭔가 거창한 듯한 함수처럼 보입니다만 사실은 #define으로 정의된 매크로입니다. 이 매크로는 header 파일인 IInterface.h에 선언되어 있음을 확인하실 수 있습니다.


/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
#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

 보시는 바와 같이 #define을 통해 정의되어 있는 것을 확인하실 수 있습니다. 이 매크로에서 맨 오른쪽 부분에 BackSlash가 처리되어 있는 것은 해당 매크로 #define이 한 줄에서 끝나지 않고 있음을 의미합니다. 그리고 내용을 확인하시다 보면 다음과 같은 내용이 있습니다.


I##INTERFACELLI##INTERFACE() { }


 여기서 '##'이란 해당 기호 앞뒤에 있는 글자를 곧바로 붙여쓰라는 의미로 이해해 주신다면 쉽게 넘어가실 수 있으리라 생각합니다.

 INTERFACE가 'ServiceManager', Name이 '"android.os.IServiceManager"'로 정의되었다는 가정하에 Macro의 결과물은 다음과 같이 나타낼 수 있습니다.


/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
    const android::String16 IServiceManager::descriptor("android.os.IServiceManager");
    const android::String16&                                            
            IServiceManager::getInterfaceDescriptor() const {              
        return IServiceManager::descriptor;                                
    }                                                                   
    android::sp<IServiceManager> IServiceManager::asInterface(                
            const android::sp<android::IBinder>& obj)                   
    {                                                                   
        android::sp<IServiceManager> intr;                                 
        if (obj != NULL) {                                              
            intr = static_cast<IServiceManager*>(                          
                obj->queryLocalInterface(                               
                        IServiceManager::descriptor).get());               
            if (intr == NULL) {                                         
                intr = new BpServiceManager(obj);                          
            }                                                           
        }                                                               
        return intr;                                                    
    }                                                                   
    IServiceManager::IServiceManager() { }                                    
    IServiceManager::~IServiceManager() { }                                  
cs

Macro를 해독하면 다음과 같은 코드가 적용되고 있음을 알 수 있습니다.

 이 함수가 어떤 부분에서 중요하다는 의미인지 지금까지 설명드린 것 만으로는 충분히 이해하실 수 없으실 겁니다. 하지만 아래의 코드를 확인해 보신다면 단박에 위 매크로의 용도를 눈치채실 수 있을 겁니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)
    {
    }
....
 
    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 내에 있는 getInterfaceDescriptor() 함수를 찾아보았는데 전혀 찾아낼 수가 없어서 다른 곳에서 이리저리 찾아봤건만 저렇게 Macro를 통해 구현되어 있다는 것은 꿈에도 생각하지 못했습니다! 참으로 안드로이드의 세계는 알거 같으면서도 어려운 구조로군요.

 안드로이드 프레임워크 소스 내에는 위에서 소개드렸던 매크로 외에도 다음과 같이 2종류의 Macro가 존재합니다.


#define DECLARE_META_INTERFACE(INTERFACE) 

#define CHECK_INTERFACE(interface, data, reply)


 위 두 매크로 또한 제가 위에서 설명드린 바와 같이 해석을 해두신다면 원리를 쉽게 파악하실 수 있을 것입니다!

300x250

우분투 사용중 안보이거나 깨진 언어가 나올 때 언어 설치방법

공대생의 팁 2015. 3. 26. 12:23

 우분투가 상당히 매력적인 부분 중 하나라면 다양한 언어를 지원해준다는 점입니다. 심지어 이렇게 한글도 제공하는 환경인 것을 보면 우분투는 이름 그대로 공동체 정신을 담고 있는 것은 아닌가 싶습니다.


 우분투를 사용하다가 종종 괴랄하게 등장하는 언어들이 보입니다. 이는 자신의 우분투에 해당 언어가 설치되어 있지 않아 보이지 않는 현상입니다.


 위키피디아를 사용하던 중 생전 처음보는 괴랄한 글자들이 보시는 바와 같이 튀어나오고 있습니다. 과연 이 언어는 무엇일까요



 잠시 한글위키로 넘어온 후 다른 언어로 된 위키백과 모두 보기를 눌러봅니다.



 언어 목록들 중 유독 글자가 깨져서 보이는 것이 하나 보입니다. 써있기로는 Burmese라 되어 있군요,



 확인해보니 해당 글은 버마어(미얀마어)였습니다. 이렇게 자신의 우분투 환경에서 존재하지 않는 언어를 확인하셨다면 해당 언어를 찾아 우분투에 설치하도록 합니다.



우분투의 시스템 설정 메뉴로 들어가신 후 언어 지원을 클릭합니다.



다음으로 '언어 설치/제거' 버튼을 눌러줍니다.



설치할 언어들의 목록들이 펼쳐지는 것을 보실 수 있습니다. 우리는 이 곳에서 버마어(미얀마어)를 추가합니다.



자신의 슈퍼유저 암호를 입력하시면 해당 언어의 설치가 시작됩니다.



해당 언어를 설치하신 후 우분투를 리셋하시면 깨져 보이지 않던 언어가 드디어 모습을 드러내게 됩니다.



300x250

Timer를 활용하여 특정 파형간 간격 측정방법

임베디드/MCU 2015. 3. 25. 00:02

 아날로그 회로를 사용할 때 알고 싶은 정보들 중 하나로 특정 파형 간의 간격을 시간으로 구하는 것일겁니다. 그런데 이 파형이 간헐적이라면 사람의 감으로 대략적으로 알 수 있겠습니다만 1MHz 정도 되는 파형으로는 절대 사람의 힘으로는 알 수 없을 것입니다. 이러한 파형을 측정하기 위해 사용되는 것이 바로 MCU에서 사용되는 Timer와 Counter이지요.


 2015년 현재 웨어러블이 주목받고 있습니다. 사람의 몸에 직접 착용하여 사용하는 기기이다 보니 사람의 생체를 활용한 기능들이 속속 선보이고 있습니다. 삼성전자의 갤럭시워치에는 심전도 측정 기능이 등장하였는데요 심박수를 측정할 때도 이 Timer가 쓰이는 것이지요.



  

 2015년 현재의 대표적인 상징물이라 할 수 있는 스마트워치

심전도, 만보계 등 생체를 활용한 기능들이 활용되고 있다.


 이번 포스팅에서는 특정 파형에서 원하는 구간을 측정하여 해당 구간의 시간 간격을 타이머로 구하는 방법에 대해 이야기하려 합니다. 파형으로 심전도 측정값을 활용하여 진행해 보도록 하겠습니다.




 다음과 같이 특정한 파형이 있다고 가정해 봅시다. 우리는 위 파형에서 보이고 있는 Peak 값을 구해볼 것입니다. MCU에서 해당 부분만 검출하기 위해서 아날로그 비교기(Analog Comparator)를 통해 검출해내 보겠습니다.


 여기서 잠시 Analog Comparator의 동작 방식에 대해 간단하게 이해를 하고 넘어가겠습니다.


 Analog Comparator은 기본적으로 2개의 입력과 1개의 출력으로 구성되어 있습니다. 이 때 Vin+을 Input1로, Vin-을 Input2라 가정합니다. 쉽게 설명하자면 Input1과 Input2의 전압차이가 +일 경우 Output의 값은 1이 되며 Input1과 Input2의 전압차이가 -가 될 경우 Output의 값은 0이 됩니다. 아래는 Analog Comparator을 사용한 입출력값과 결과값을 나타냅니다.




 출력결과를 확인하시면 우리들이 흔히 접하는 0과 1의 디지털 파형이 되는 것을 보실 수 있습니다. 이제 이 Output값을 이용해서 우리는 각 1이되는 값 사이의 간격을 측정해 볼 것입니다. 여기서 Output의 파형을 상세하게 보도록 하겠습니다.



 아날로그 파형에서 자신이 측정하고자 하던 파형 사이의 간격은 다음과 같이 측정하면 될 것입니다. 이 때 파형을 측정하는 방법을 다음과 같이 4가지로 보실 수 있습니다.


1. 파형이 1이 될 때

2. 파형이 0이 될 때

3. 파형이 Positive Edge(0에서 1로 올라가는 순간)이 될 때

4. 파형이 Negative Edge(1에서 0으로 내려가는 순간)이 될 때


 Interrupt를 공부하신 분이라면 이 부분에서 '아하!'하고 이해하실 수 있을 것입니다. 그렇습니다. 출력 부분을 Interrupt 처리가 가능한 입력 부분에 연결하실 후 Positive Edge가 발생하는 순간부터 Timer를 동작시켜 시간을 측정하신 후 그 다음 Interrupt가 들어오는 순간 Timer의 동작을 종료시킨 후 해당 값을 확인하시면 파형간 간격을 측정하실 수 있으실 것입니다.

300x250