검색결과 리스트
글
안드로이드 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 |
설정
트랙백
댓글
글
SurfaceView에서 SurfaceHolder의 동작원리(Principle of SurfaceHolder in SurfaceView)
짫은 시간에 화면에 다양한 변화를 나타내는 데에 사용되는 SurfaceView에서 사용되는 SurfaceHolder이 어떻게 동작하는 지에 대해 궁금해서 안드로이드 소스를 이리저리 살펴보게 되었습니다. 본 포스팅에서는 실행 방법을 제 나름대로 탐색한 결과에 대해 작성하였습니다.
시작하기에 앞서 SurfaceView에서 가장 많이 사용되는 Camera 애플리케이션에 대해 알아봅시다. 제가 이전에 작성한 카메라 작동에 관한 포스팅은 아래 링크를 참조해 주시길 바랍니다.
SurfaceView를 사용하기 위해서는 SurfaceHolder를 사용해야 합니다. SurfaceHolder에 사용하고자 하는 기능을 넣은 후 이를 등록하면 SurfaceView에서는 이를 토대로 동작을 수행하게 됩니다.
1 2 3 4 5 6 7 8 9 10 | protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); surfaceView = (SurfaceView)findViewById(R.id.surfaceView); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(surfaceListener); } | cs |
위 코드에서 확인하는 바와 같이 SurfaceView를 XML로 생성한 SurfaceView와 연결한 후
해당 SurfaceView에 SurfaceHolder를 연결한 후 해당 Holder에 surfaceListener를 추가하는 과정입니다.
여기서 surfaceListener는 다음과 같이 선언됩니다.
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 | private SurfaceHolder.Callback surfaceListener = new SurfaceHolder.Callback() { @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub camera.release(); } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub camera = Camera.open(); try { camera.setPreviewDisplay(holder); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(width, height); camera.startPreview(); } }; | cs |
위에서 보시는 것과 같이 SurfaceHolder 내에 있는 Callback 인터페이스 내의 3개의 Method를 선언한 것을 보실 수 있습니다. 이 내용이 SurfaceView 내의 Holder에 적용되는 것이지요.
이번에는 SurfaceView에서 getHolder()가 동작하는 방식에 대해 보도록 하겠습니다.
/frameworks/base/core/java/android/view/SurfaceView.java
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 | public class SurfaceView extends View { .... private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() { private static final String LOG_TAG = "SurfaceHolder"; @Override public boolean isCreating() { return mIsCreating; } @Override public void addCallback(Callback callback) { synchronized (mCallbacks) { // This is a linear search, but in practice we'll // have only a couple callbacks, so it doesn't matter. if (mCallbacks.contains(callback) == false) { mCallbacks.add(callback); } } } .... } .... /** * Return the SurfaceHolder providing access and control over this * SurfaceView's underlying surface. * * @return SurfaceHolder The holder of the surface. */ public SurfaceHolder getHolder() { return mSurfaceHolder; } } | cs |
SurfaceView 클래스를 선언한 후 getHolder() 함수를 호출하게 되면 위의 소스에서 보는 바와 같이 SurfaceView 클래스 내에 있는 mSurfaceHolder 객체를 return 해주는 구조임을 알 수 있습니다.
mSurfaceHolder는 SurfaceView 클래스 내부에 Interface인 SurafceHolder.Callback을 정의하여 선언하였음을 확인하실 수 있습니다. 해당 Holder 내에 addCallbacks()가 정의되어있어 Application 단계에서 설정하였던 surfaceListener를 등록하고 있는 모습을 보실 수 있습니다.
그렇다면 SurfaceView 클래스 내부에 있는 mCallbacks 객체에 등록된 surfaceListener는 어떤 방식으로 동작하는지 살펴보도록 하겠습니다. mCallbacks 또한 SurfaceView.java 내부에서 동작되는 모습을 확인하실 수 있습니다.
아래 코드의 내용들이 상당히 많습니다만 한 줄 한 줄이 상당히 중요한 관계로 관련 코드를 모두 올려봅니다. 물론 핵심 코드는 볼드체 및 밑줄로 눈에 띄도록 표기하였습니다.
/frameworks/base/core/java/android/view/SurfaceView.java
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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | public class SurfaceView extends View { static private final String TAG = "SurfaceView"; static private final boolean DEBUG = false; final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<SurfaceHolder.Callback>(); .... private void updateWindow(boolean force, boolean redrawNeeded) { if (!mHaveFrame) { return; } ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null) { mTranslator = viewRoot.mTranslator; } if (mTranslator != null) { mSurface.setCompatibilityTranslator(mTranslator); } int myWidth = mRequestedWidth; if (myWidth <= 0) myWidth = getWidth(); int myHeight = mRequestedHeight; if (myHeight <= 0) myHeight = getHeight(); getLocationInWindow(mLocation); final boolean creating = mWindow == null; final boolean formatChanged = mFormat != mRequestedFormat; final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; final boolean visibleChanged = mVisible != mRequestedVisible; if (force || creating || formatChanged || sizeChanged || visibleChanged || mLeft != mLocation[0] || mTop != mLocation[1] || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) { if (DEBUG) Log.i(TAG, "Changes: creating=" + creating + " format=" + formatChanged + " size=" + sizeChanged + " visible=" + visibleChanged + " left=" + (mLeft != mLocation[0]) + " top=" + (mTop != mLocation[1])); .... try { final boolean visible = mVisible = mRequestedVisible; mLeft = mLocation[0]; mTop = mLocation[1]; mWidth = myWidth; mHeight = myHeight; mFormat = mRequestedFormat; .... mSurfaceLock.lock(); try { redrawNeeded |= creating | reportDrawNeeded; SurfaceHolder.Callback callbacks[] = null; final boolean surfaceChanged = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0; if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) { mSurfaceCreated = false; if (mSurface.isValid()) { if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed"); callbacks = getSurfaceCallbacks(); for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); } } } mSurface.transferFrom(mNewSurface); if (visible && mSurface.isValid()) { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { mSurfaceCreated = true; mIsCreating = true; if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated"); if (callbacks == null) { callbacks = getSurfaceCallbacks(); } for (SurfaceHolder.Callback c : callbacks) { c.surfaceCreated(mSurfaceHolder); } } if (creating || formatChanged || sizeChanged || visibleChanged || realSizeChanged) { if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat + " w=" + myWidth + " h=" + myHeight); if (callbacks == null) { callbacks = getSurfaceCallbacks(); } for (SurfaceHolder.Callback c : callbacks) { c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight); } } if (redrawNeeded) { if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded"); if (callbacks == null) { callbacks = getSurfaceCallbacks(); } for (SurfaceHolder.Callback c : callbacks) { if (c instanceof SurfaceHolder.Callback2) { ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded( mSurfaceHolder); } } } } } finally { mIsCreating = false; if (redrawNeeded) { if (DEBUG) Log.i(TAG, "finishedDrawing"); mSession.finishDrawing(mWindow); } mSession.performDeferredDestroy(mWindow); } } catch (RemoteException ex) { } if (DEBUG) Log.v( TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + " w=" + mLayout.width + " h=" + mLayout.height + ", frame=" + mSurfaceFrame); } .... private SurfaceHolder.Callback[] getSurfaceCallbacks() { SurfaceHolder.Callback callbacks[]; synchronized (mCallbacks) { callbacks = new SurfaceHolder.Callback[mCallbacks.size()]; mCallbacks.toArray(callbacks); } return callbacks; } .... } | cs |
위 코드를 처음 보는 사람이라면 코드의 양이 다소 방대하여 이해하기 힘드실 수 있습니다. 일단 위에서 강조한 부분에 대해 좀 더 자세히 설명드리도록 하겠습니다.
final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<SurfaceHolder.Callback>();
mCallBacks는 Java에서 제공하는 ArrayList로 구성된 Object입니다. 이 ArrayList 안에 Application에서 호출했던 addCallbacks()를 통해 Listener가 등록됩니다.
private void updateWindow(boolean force, boolean redrawNeeded)
본 함수를 통해 SurfaceView의 화면이 변경될 수 있도록 할 수 있습니다. 해당 함수를 잘 보시면 SurfaceHolder.Callback 인터페이스를 통해 선언한 함수들이 실행되는 것을 보실 수 있습니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
| 안드로이드 프레임워크 프로그래밍(11) [JAVA 프레임워크와 Native 프레임워크 연결 원리] (2) | 2015.03.18 |
|---|---|
| 안드로이드 Native 코드 분석 : sp<> - Smart Pointer (0) | 2015.03.02 |
| 안드로이드 프레임워크 프로그래밍(10) [Native C/C++ 코드에서 Java 호출] (0) | 2015.02.18 |
| 안드로이드 프레임워크 프로그래밍(9) [프레임워크에 JNI를 활용해 C/C++ 코드 추가하기] (0) | 2015.02.17 |
| 안드로이드 프레임워크 프로그래밍(8) [JNI에서 작성된 C++ 코드에서 C 코드 함수 호출하기] (0) | 2015.02.16 |
설정
트랙백
댓글
글
[VMware] NX / XD is required. The processor must support and it must be enabled in the BIOS.
올해 말에 정식으로 공개될 Windows 10의 체험판을 사용해 보기 위해 VMware를 설치한 후 Windows 10를 설치해보려고 하였을 때 다음과 같은 에러를 맞이하게 되었습니다.
평소 VirtualBox만 사용하다 보니 이러한 오류는 생전 처음 보는 상황이었습니다. 확인해보니 자신의 CPU 설정에 문제가 있어 위와 같은 상황이 발생한 것이었습니다. Intel사의 CPU의 경우 XD, AMD사의 CPU의 경우 NX 비트 설정때문에 저러한 상황이 발생합니다.
NX(Not eXecute)와 XD(eXecute Disable)은 모두 같은 것을 의미하는 것으로 프로그램 실행중 특정 비트를 통해 해당 프로그램을 실행하지 않도록 설정하는 Bit를 마련할 것인지를 묻는 것을 의미합니다.
위와 같은 경고문이 뜨면서 VMware가 더이상 진행이 되지 않는 이유는 자신의 컴퓨터 CPU가 해당 기능을 설정하지 않았기 때문에 발생합니다. 이 설정은 자신의 컴퓨터의 BIOS 설정 모드를 통해 바꾸어 주실 수 있습니다. 컴퓨터를 켜는 순간 바로 BIOS 설정모드(대부분 F2 또는 F10)으로 들어가셔서 CPU 관련 설정 부분을 보시면 해당 설정 유무를 결정할 수 있는 메뉴를 찾으실 수 있습니다. 해당 메뉴를 Enabled로 설정하신 후 컴퓨터를 재부팅 하시면 VMware가 정상적으로 실행되는 것을 보실 수 있습니다.
위 사진은 Samsung Magic Station에서의 BIOS 설정 화면을 나타낸 것입니다. 보이시는 대로 No Execute Protection을 Enabled로 설정해주시면 되겠습니다.
'공대생의 팁' 카테고리의 다른 글
| 우분투 사용중 안보이거나 깨진 언어가 나올 때 언어 설치방법 (0) | 2015.03.26 |
|---|---|
| 티스토리 블로그를 반년간 하면서... (0) | 2015.03.12 |
| Windows XP에서 DOS 파일 실행시 EMS 문제 해결방법 (0) | 2015.01.26 |
| WF2411 공유기를 통한 외부 기기와 소켓 통신 프로그래밍 (3) | 2014.11.02 |
| 윈도7 기반 서버 컴퓨터와 소켓 프로그래밍이 안될 때 (0) | 2014.11.01 |