검색결과 리스트
글
안드로이드 Native 코드 분석 : sp<> - Smart Pointer
안드로이드 카메라 동작 원리에 대해 공부를 하면서 안드로이드 소스코드를 분석하고 있습니다. 옆에 C++ 서적을 읽어가며 보다보면 어느 정도 이해하고 넘어갈 수 있는 부분들이 많이 있었습니다만 책에서도 찾아보기 어려운 내용이 들이닥치더군요. 그 부분이 바로 sp<T> 구문이었습니다.
/framework/base/core/jni/android_hardware_Camera.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) { sp<Camera> camera; Mutex::Autolock _l(sLock); JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); if (context != NULL) { camera = context->getCamera(); } ALOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); if (camera == 0) { jniThrowRuntimeException(env, "Method called after release()"); } if (pContext != NULL) *pContext = context; return camera; } | cs |
코드 내부를 살펴보면 뜬금없이 등장하는 'sp<Camera>' 부분이 영 이해가 되지 않더군요. 이를 헤더를 뒤져가며 찾는 것도 너무나도 어려웠는데 이를 좀 더 자세히 살펴보았습니다.
/frameworks/base/core/jni/android_hardware_Camera.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #define LOG_TAG "Camera-JNI" #include <utils/Log.h> #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <android_runtime/android_graphics_SurfaceTexture.h> #include <android_runtime/android_view_Surface.h> #include <cutils/properties.h> #include <utils/Vector.h> #include <gui/GLConsumer.h> #include <gui/Surface.h> #include <camera/Camera.h> #include <binder/IMemory.h> | cs |
위 헤더파일들 중 #include<binder/IMemory.h>로 이동해 봅니다.
/frameworks/native/include/binder/IMemory.h
1 2 3 4 5 6 7 8 9 10 | #ifndef ANDROID_IMEMORY_H #define ANDROID_IMEMORY_H #include <stdint.h> #include <sys/types.h> #include <sys/mman.h> #include <utils/RefBase.h> #include <utils/Errors.h> #include <binder/IInterface.h> | cs |
다음으로 안드로이드 JNI의 핵심을 이해할 수 있는 #include<utils/RefBase.h> 로 이동하신 후
/system/core/include/utils/RefBase.h
1 2 3 4 5 6 7 8 9 10 11 12 | #ifndef ANDROID_REF_BASE_H #define ANDROID_REF_BASE_H #include <cutils/atomic.h> #include <stdint.h> #include <sys/types.h> #include <stdlib.h> #include <string.h> #include <utils/StrongPointer.h> #include <utils/TypeHelpers.h> | cs |
끝으로 #include<utils/StongPointer.h> 로 이동해 주시면
/system/core/include/utils/StrongPointer.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 40 41 42 43 44 45 46 47 48 | template<typename T> class sp { public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp<T>& other); template<typename U> sp(U* other); template<typename U> sp(const sp<U>& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp<T>& other); template<typename U> sp& operator = (const sp<U>& other); template<typename U> sp& operator = (U* other); //! Special optimization for use by ProcessState (and nobody else). void force_set(T* other); // Reset void clear(); // Accessors inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; } // Operators COMPARE(==) COMPARE(!=) COMPARE(>) COMPARE(<) COMPARE(<=) COMPARE(>=) private: template<typename Y> friend class sp; template<typename Y> friend class wp; void set_pointer(T* ptr); T* m_ptr; }; | cs |
드디어 우리들이 찾고 있던 sp<T>가 구현된 StrongPointer를 찾아내실 수 있습니다. 과연 이 녀석은 무슨 역할을 하는 것일까요?
안드로이드 소스코드에 사용되고 있는 sp<T>는 스마트포인터(Smart Pointer)를 말하는 것이며 보통 Struct나 int같이 C에서 기본적으로 제공되고 있는 것들은 *을 통해 간단하게 포인터로 사용하는 것이 가능합니다. sp<T>는 이를 객체인 Class를 포인터처럼 사용할 수 있도록 하기 위해 사용되는 도구라고 설명드릴 수 있겠습니다. 이를 사용하면 사용자는 포인터로 지정된 객체를 실제 객체를 다루듯이 사용하실 수 있다는 장점을 가지고 있습니다.
Strong Pointer를 쓰는 가장 중요한 이유는 포인터 객체의 할당과 삭제를 직접 제어할 수 있다는 것입니다. Java와 같이 Gabage Collector 기능이 있는 경우 객체를 할당 해준 후 사용하지 않으면 알아서 할당에서 사라지지만 C/C++의 경우 해당 기능이 존재하지 않습니다. 그렇기 때문에 sp<T>를 활용해 메모리를 관리해 준다면 좀 더 쾌적한 프로그램을 만들 수 있을 것입니다.
위 코드에서 47번째 줄의 내용을 주목해 봅시다. m_ptr이라는 이름의 변수가 있는데 이 변수의 타입은 T, 즉 sp에 전달되는 클래스 자신의 주소값을 저장하는 상황임을 알 수 있습니다.
그렇다면 여기서 잠시 코드의 내부롤 살짝 살펴보도록 하겠습니다.
1 2 3 4 5 6 | template<typename T> sp<T>::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } | cs |
객체의 스마트포인터가 할당된 경우 입니다. 기존에 해당 객체가 존재할 경우 incStrong()를 통해 참조 갯수를 늘립니다.
1 2 3 4 5 | template<typename T> sp<T>::~sp() { if (m_ptr) m_ptr->decStrong(this); } | cs |
객체의 스마트포인터 하나가 할당이 해제된 경우입니다. decString()를 통해 참조 갯수를 줄입니다.
1 2 3 4 5 6 7 | template<typename T> void sp<T>::clear() { if (m_ptr) { m_ptr->decStrong(this); m_ptr = 0; } } | cs |
객체 자체의 할당을 해제합니다. 해당 포인터를 0으로 하여 할당을 해제합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | template <typename T> class sp { public: inline sp() : m_ptr(0) { } .... // Accessors inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; } .... private: template<typename Y> friend class sp; template<typename Y> friend class wp; void set_pointer(T* ptr); T* m_ptr; }; | cs |
앞에서도 제시되었었던 Smart Pointer인 sp 클래스 내부의 모습입니다. Accessors 주석 아래에 작성된 부분은 Smart Pointer에 연결된 포인터에 접근에 관하여 다루고 있는 모습입니다.
안드로이드 소스코드를 이해하는 데에는 이 정도의 지식만 알고 넘어가시면 될 듯 합니다. 좀 더 자세한 내용을 알고 싶으신 분들은 위에서 언급한 코드를 직접 살펴보시면 좋을 것입니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
안드로이드 프레임워크 프로그래밍(12) [IServiceManager 등록과정] (1) | 2015.03.23 |
---|---|
안드로이드 프레임워크 프로그래밍(11) [JAVA 프레임워크와 Native 프레임워크 연결 원리] (2) | 2015.03.18 |
SurfaceView에서 SurfaceHolder의 동작원리(Principle of SurfaceHolder in SurfaceView) (1) | 2015.02.26 |
안드로이드 프레임워크 프로그래밍(10) [Native C/C++ 코드에서 Java 호출] (0) | 2015.02.18 |
안드로이드 프레임워크 프로그래밍(9) [프레임워크에 JNI를 활용해 C/C++ 코드 추가하기] (0) | 2015.02.17 |