출처: http://baiduhix.blogspot.com.br/2015/08/android-how-to-do-findviewbyid-in.html

★ http://www.vogella.com/tutorials/AndroidLifeCycle/article.html

  • Activity and Fragment Lifecycle





  • Activity Lifecycle (출처: http://philosymbol.net/?p=571)
    : 안드로이드 어플리케이션은 자신의 프로세스 수명을 직접 제어하지 않으며, 안드로이드 런타임이 각 어플리케이션의 프로세스와 그 안에 있는 각 activity를 관리한다.
    : 런타임이 프로세스와 activity의 종료와 관리를 다루는 동안, activity의 상태는 자신의 부모 어플리케이션 프로세스의 우선순위를 결정하는데 사용된다.
    : 어플리케이션 우선순위는 런타임이 어플리케이션과 그 안에 실행중인 activity를 종료시킬 가능성에 영향을 미치게된다.

    - 활성(Active)
     : activity가 stack의 최상위에 있을 경우 이 activity는 현재 화면에 보이고 사용자 입력을 받는다.
     : 안드로이드는 무슨 일이 있어도 활성 상태에 있는 activity가 살아있도록 노력하며, 이 activity가 필요로 하는 리소스를 확보하기 위해 필요에 따라 stack의 아래쪽에 있는 activity들을 종료시킬 수 있다.
     : 다른 activity가 활성화되면 기존의 활성 activity는 일시 중지(Pause)된다.

    - 일시 중지(Active)
     : 경우에 따라 activity는 화면에는 보이지만 포커스를 지니지 않을 수 있다.
     : 이 상태는 투명한 activity나 화면 전체를 사용하지 않는 activity가 그 앞에 활성화되어 있는 경우이다.
     : 일시 중지 상태가 되는 경우 activity는 활성 상태인것처럼 다뤄지지만 사용자 입력을 받지 않는다.
     : 극단적인 경우, 안드로이드는 활성 activity를 위한 리소스 확보를 위해 일시 중지 상태의 activity를 종료시킬 수 있을 것이다.
     : 만약 activity가 완전히 가려지게 되면 그 activity는 중지상태가 된다.

    - 중지(Stop)
     : activity는 화면에 보이지 않는다.
     : 이 activity는 모든 상태 및 멤버 정보를 메모리에 남기지만, 만약 시스템이 활성 activity를 위해 메모리를 요청할 경우 리소스 확보를 위한 정리 후보 1순위가 된다.
     : activity가 중지될 때는 데이터와 현재 UI상태를 저장하는 것이 중요하다.
     : activity가 화면 밖으로 나가거나 닫히고 나면 그 activity는 비활성 상태가 된다.

    - 비활성(Inactive)
     : activity는 종료되고 난 이후와 시작되기 이전 비활성 상태에 머문다.
     : 비활성 activity는 activity stack에게 제거되며, 화면에 다시 나타내기 위해서는 재시작되어야 한다.

     



    - Activity 생명주기를 구성하는 메소드

    메소드 

    설명

     onCreate

     액티비티가 최초 생성시에 호출된다. 초기화 설정을 하는 곳으로 보관된 상태의 액티비티가 있다면, 그 상태를 저장중인 Bundle 객체를 받는다. onStart() 메소드가 이어진다. 강제종료가 불가능하다.

     onRestart

     액티비티가 정지 후 다시 시작되기 바로 직전에 호출된다.
    onStart() 메소드가 이어진다. 강제종료가 불가능하다. 

     onStart

     액티비티가 사용자에게 보여지기 직전에 호출된다. 액티비티가 보여지게되면 onResume() 메소드가, 안보이게 되면 onStop() 메소드가 이어진다. 강제종료가 불가능하다.

     onResume

     액티비티가 사용자와 상호작용하기 직전에 호출된다. (스택의 최상위에 위치) onPause() 메소드가 이어진다. 강제종료가 불가능하다.

     onPause

     시스템이 다른 액티비티를 시작하려 할 때 호출된다. 일반적으로 데이터 저장을 하기에 좋은 곳이다. 소스코드의 속도가 빨라야 한다. 왜냐하면 이 메소드가 끝나기 전까지 다음 액티비티가 실행되지 않기 때문인데 액티비티가 되돌아오면 onResume(), 보이지않게되면 onStop()이 이어진다. 강제종료가 불가능하다.

     onStop

     액티비티가 사용자에게 보이지 않을때 호출 된다. 액티비티가 제거되거나 다른 액티비티가 실행되어 해당 액티비티를 덮어버렸을때, 호출된다.
    액티비티가 되돌아오면 onRestart(), 액티비티가 사라지면 onDestroy() 가 이어진다. 강제종료가 가능하다.

     onDestroy

     액티비티 삭제 직전에 호출된다. 액티비티가 받는 마지막 호출 메소드로 시스템이 메모리 확보를 위해 액티비티 인스턴스를 없애버리거나, finish() 메소드가 호출되면 호출되는 메소드이다.
    isFinishing() 메소드로 두 가지를 분기할 수 있다. onStart() 메소드가 이어진다. 강제종료가 불가능하다. 



    - Activity 상태 저장 (출처: http://namsieon.com/286)


    시스템이 액티비티를 강제종료 했을때, 사용자는 이전의 액티비티로 돌아가고 싶을 수 있습니다. 이럴 경우 액티비티가 강제종료 되기 전에 상태를 저장할 수 있는
     
    onSaveInstanceState() 메소드를 구현하면 저장이 가능해 집니다.



    즉, 액티비티가 파괴되기전에 호출되는 메소드 인데요. ( onPause() 호출 이전에 호출됩니다. )
    이 메소드는 이름/값 쌍으로 이루어진 번들 객체(Bundle) 를 인수로 가집니다. 액티비티가 다시 시작되면 번들은 onSaveInstanceState() 와 onStart() 이후에 호출되는 onRestoreInstanceState() 에게 전달됩니다.



    ☞ onSaveInstanceState() , onRestoreInstanceState() 메소드는 생명주기 메소드는 아닙니다.
    따라서 항상 호출되지는 않으며 특정 상황 ( 액티비티 강제종료전에 onSaveInstance() 호출처럼 ) 에서만 호출됩니다. 단, 사용자 액션에 의해 종료될 때는 ( 사용자가 직접종료 ) 호출되지 않습니다.
    - 사용자가 되돌아가지 않을 생각으로 종료한 것으로 판단한 것이겠죠...

    onSaveInstanceState() 는 액티비티의 일시적인 상태 저장을 위한 것이므로 , 데이터 등을 안전하게 저장하려면 onPause() 메소드에서 처리해야 합니다.



  • Fragment
















'Programing > Android' 카테고리의 다른 글

Google I/O - Memory Management For Android  (0) 2016.05.03
Avoiding Memory Leaks  (0) 2016.05.03
Handler, Looper  (0) 2016.04.19
Parcelable vs. Serializable  (0) 2016.03.22
안드로이드 - 자바 시스템 프레임워크  (0) 2016.01.26
출처 : https://realm.io/kr/news/android-thread-looper-handler/

소개

안드로이드의 애플리케이션을 실행하면 시스템은 메인 액티비티를 메모리로 올려 프로세스로 만들며, 이 때 메인 스레드가 자동으로 생성됩니다. 메인 스레드는 안드로이드의 주요 컴퍼넌트를 실행하는 곳이자 UI를 그리거나 갱신하는 일을 담당할 수 있는 유일한 스레드이므로 UI 스레드라고도 불립니다.

안드로이드 화면을 구성하는 뷰나 뷰그룹을 하나의 스레드에서만 담당하는 원칙을 싱글 스레드 모델이라고 합니다. 싱글 스레드 모델의 규칙은 첫째, 메인 스레드(UI 스레드)를 블럭하지 말 것, 둘째, 안드로이드 UI 툴킷은 오직 UI 스레드에서만 접근할 수 있도록 할 것, 이 두 가지입니다. 이런 싱글 스레드 모델의 영향을 고려하지 않으면 애플리케이션의 성능이 저하될 수 있습니다. 긴 시간이 걸리는 작업을 메인 스레드에서 담당한다면 애플리케이션의 반응성이 낮아질 수 있고, 급기야 사용자의 불편함을 방지하고자 시스템이 애플리케이션을 ANR(Appication Not Responding) 상태로 전환시킬 수도 있습니다. 따라서 시간이 걸리는 작업을 하는 코드는 여분의 스레드를 사용하여 메인 스레드에서 분리해야 하고, 자연스럽게 메인 스레드와 다른 스레드가 통신하는 방법이 필요하게 됩니다.

다른 스레드에서 메인 스레드로 접근하기 위해 Looper와 Handler를 사용할 수 있으며, 안드로이드는 Java의 Thread를 좀 더 쉽게 사용할 수 있도록 래핑한 HandlerThread, 더 나아가 Thread나 Message Loop 등의 작동 원리를 크게 고려하지 않고도 사용이 가능한 AsyncTask 등의 클래스를 제공합니다. 이 글에서는 먼저 Thread-Looper-Handler의 개념을 이해하고, 나아가 HandlerThread와 AsyncTask에 대해 정리해보도록 하겠습니다.

Looper와 Handler의 사용 목적

왜 안드로이드는 메인 스레드에서만 UI 작업이 가능하도록 제한할까요? 메인 스레드가 아닌 스레드가 병렬적으로 실행되고 있을 때, 메인 스레드와 다른 스레드, 두 개 이상의 스레드가 동시에 같은 텍스트뷰에 setText()를 시도하는 경우를 생각하면 간단합니다.

둘 중 어느 스레드의 setText()가 적용될지 예측할 수 없고, 사용자는 둘 중 하나의 값만을 볼 수 있어 다른 한 스레드의 결과는 버려집니다. 이같이 두 개 이상의 스레드를 사용할 때의 동기화 이슈를 차단하기 위해서 Looper와 Handler를 사용하게 됩니다.

Looper와 Handler의 작동 원리

먼저 스레드와 Looper, Handler가 어떻게 작동하는지 알아볼까요? 메인 스레드는 내부적으로 Looper를 가지며 그 안에는 Message Queue가 포함됩니다. Message Queue는 스레드가 다른 스레드나 혹은 자기 자신으로부터 전달받은 Message를 기본적으로 선입선출 형식으로 보관하는 Queue입니다. Looper는 Message Queue에서 Message나 Runnable 객체를 차례로 꺼내 Handler가 처리하도록 전달합니다. Handler는 Looper로부터 받은 Message를 실행, 처리하거나 다른 스레드로부터 메시지를 받아서 Message Queue에 넣는 역할을 하는 스레드 간의 통신 장치입니다.

이제 Handler와 Looper, Message Queue에 대해 좀 더 자세히 살펴보겠습니다.

Handler

Handler는 스레드의 Message Queue와 연계하여 Message나 Runnable 객체를 받거나 처리하여 스레드 간의 통신을 할 수 있도록 합니다. Handler 객체는 하나의 스레드와, 해당 스레드의 Message Queue에 종속됩니다. 새로 Handler 객체를 만든 경우 이를 만든 스레드와 해당 스레드의 Message Queue에 바인드됩니다. 다른 스레드가 특정 스레드에게 메시지를 전달하려면 특정 스레드에 속한 Handler의 post나 sendMessage 등의 메서드를 호출하면 됩니다. 
앞서 Message Queue는 전달받은 Message를 선입선출 형식으로 보관한다고 설명했지만, 전달 시점에 다른 메서드를 사용하여 Queue의 맨 위로 보내거나, 원하는 만큼 Message나 Runnable 객체의 전송을 지연시킬 수도 있습니다. 자주 쓰이는 Handler의 메서드를 아래 표에 정리했습니다.

리턴값메서드명인자설명
voidhandleMessageMessage msgLooper가 Message Queue에서 꺼내준 Message나 Runnable 객체를 처리 
(상속 시 구현 필수)
final booleanpostRunnable rMessage Queue에 Runnable r을 전달
final booleansendMessageMessage msgMessage Queue에 Message msg를 전달
final booleanpostAtFrontOfQueueRunnable rMessage Queue의 맨 앞에 Runnable r을 전달
final booleansendMessageAtFrontOfQueueMessage msgMessage Queue의 맨 앞에 Message msg를 전달
final booleanpostDelayedRunnable r, long delayMillisdelayMillis만큼 지연 후Message Queue에 Runnable r을 전달
final booleansendMessageDelayedMessage msg, long delayMillisdelayMillis만큼 지연 후Message Queue에 Message msg를 전달

외부, 혹은 자기 스레드로부터 받은 메시지를 어떤 식으로 처리할 지는 handleMessage() 메서드를 구현하여 정합니다. sendMessage()나 post()로 특정 Handler에게 메시지를 전달할 수 있고, 재귀적인 호출도 가능하므로 딜레이를 이용한 타이머나 스케줄링 역할도 할 수 있어 편리합니다.

Looper Message Queue

Looper는 무한히 루프를 돌며 자신이 속한 스레드의 Message Queue에 들어온 Message나 Runnable 객체를 차례로 꺼내서 이를 처리할 Handler에 전달하는 역할을 합니다. 메인 스레드는 Looper가 기본적으로 생성돼 있지만, 새로 생성한 스레드는 기본적으로 Looper를 가지고 있지 않고, 단지 run 메서드만 실행한 후 종료하기 때문에 메시지를 받을 수 없습니다. 따라서 기본 스레드에서 메시지를 전달받으려면 prepare() 메서드를 통해 Looper를 생성하고, loop() 메서드를 통해 Looper가 무한히 루프를 돌며 Message Queue에 쌓인 Message나 Runnable 객체를 꺼내 Handler에 전달하도록 합니다. 이렇게 활성화된 Looper는 quit()이나 quitSafely() 메서드로 중단할 수 있습니다. quit() 메서드가 호출되면 Looper는 즉시 종료되고, quitSafely() 메서드가 호출되면 현재 Message Queue에 쌓인 메시지들을 처리한 후 종료됩니다.

Message Runnable

Message란 스레드 간 통신할 내용을 담는 객체이자 Queue에 들어갈 일감의 단위로 Handler를 통해 보낼 수 있습니다. 일반적으로 Message가 필요할 때 새 Message 객체를 생성하면 성능 이슈가 생길 수 있으므로 안드로이드가 시스템에 만들어 둔 Message Pool의 객체를 재사용합니다. obtain() 메서드는 빈 Message 객체를, obtain(Handler h, int what …)은 목적 handler와 다른 인자들을 담은 Message 객체를 리턴합니다.
Runnable을 설명하려면 스레드를 만드는 두 가지 방법부터 말씀드려야 합니다. 새 스레드는 Thread() 생성자로 만들어서 내부적으로 run()을 구현하던지, Thread(Runnable runnable) 생성자로 만들어서 Runnable 인터페이스를 구현한 객체를 생성하여 전달하던지 둘 중 하나의 방법으로 생성하게 됩니다. 후자에서 사용하는 것이 Runnable로 스레드의 run() 메서드를 분리한 것입니다. 따라서 Runnable 인터페이스는 run() 추상 메서드를 가지고 있으므로 상속받은 클래스는 run()코드를 반드시 구현해야 합니다.
앞서 언급한대로 Message가 int나 Object같이 스레드 간 통신할 내용을 담는다면, Runnable은 실행할 run() 메서드와 그 내부에서 실행될 코드를 담는다는 차이점이 있습니다.

HandlerThread

Looper에서 언급했듯이 안드로이드의 스레드는 Java의 스레드를 사용하기 때문에 안드로이드에서 도입한 Looper를 기본으로 가지지 않는다는 불편함이 있습니다. 이 같은 불편함을 개선하기 위해 생성할 때 Looper를 자동으로 보유한 클래스를 제공하는데, 이것이 바로 HandlerThread입니다.
HandlerThread는 일반적인 스레드를 확장한 클래스로 내부에 반복해서 루프를 도는 Looper를 가집니다. 자동으로 Looper 내부의 Message Queue도 생성되므로 이를 통해 스레드로 Message나 Runnable을 전달받을 수 있습니다.

AsyncTask

AsyncTask는 스레드나 메시지 루프 등의 작동 원리를 몰라도 하나의 클래스에서 UI작업과 backgrond 작업을 쉽게 할 수 있도록 안드로이드에서 제공하는 클래스입니다. 캡슐화가 잘 되어 있기 때문에 사용시 코드 가독성이 증대되는 장점이 있으며, 태스크 스케쥴을 관리할 수 있는 콜백 메서드를 제공하고, 필요할 때 쉽게 UI 갱신도 가능하며 작업 취소도 쉽습니다. 따라서 리스트에 보여주기 위한 데이터 다운로드 등 UI와 관련된 독립된 작업을 실행할 경우 AsyncTask로 간단하게 구현할 수 있습니다.

그림: AsyncTask의 구조

그러나 AsyncTask를 사용해서 스케줄링 할 수 있는 작업 수의 제한이 있고, 몇 초 정도의 짧은 작업에서만 이상적으로 동작한다는 한계가 있습니다. 또한, 안드로이드의 버전 별로 병렬 처리 동작이 다르므로 허니콤 이후 버전에서 멀티 스레드로 병렬적인 동작을 원한다면 AsyncTask를 실행할 때 AsyncTask.THREAD_POOL_EXECUTOR 스케줄러를 지정해야 합니다. 
한편 앞서 살펴본 Handler와 Looper를 사용한다면 작동 원리를 고려해야 하며 구현을 직접 해야 하고 코드가 복잡해져서 가독성을 저해한다는 단점이 있지만 그만큼 개발 범위가 자유롭습니다. 또한 UI 스레드에서만 작업하지 않아도 되므로 보다 많은 자율성을 가지고 코드를 제어하기를 원한다면 Handler나 HandlerThread 사용을 고려해 보세요.

출처 - http://aroundck.tistory.com/2477

 android, Parcelable vs. Serializable

 

[android] Parcelable vs Serializable


Serializable 은 Java 만 아는 사람이라면 쉽게 알 수 있는 serialization 방법.

그냥 Serializable 을 implementation 만 해주면, serialize 가 필요한 순간에 알아서 serialze 해주는 편리한marker interface.


그러나, mobile 시대가 강림하면서 등장한 유망한 어린이(?) 가 있으니 그는 바로 Parcelable.

이 녀석은 IPC ( Inter Process Communication ) 에 최적화된 녀석으로.

Serialize 보다 속도가 빠르다.

물론, 해야 하는 일은 Serialize 보다 훨씬 많다.

직접 serialize 되어야 할 녀석들을 선별해서 그것을 쓰고 읽는 작업을 해주어야 한다.


그럼 왜 serialization 이 parcelable 보다 속도가 느릴까?

그 이유는, serialization 은 reflection 방법을 사용하여 serialization 을 하는데,

parcelable 은 프로그래머가 직접 바로 setting 을 해주기 때문에 빠른 것이다.

( reflection 이 성능이슈를 야기할 수 있다는 것은 이미 알고 있을꺼라 생각한다.. )


다행스럽게도 둘의 성능차이가 얼마나 날까 테스트 결과를 찾아봤는데

이런 결과를 볼 수 있었다.


[android] Parcelable vs Serializable이미지 출처 : http://www.developerphil.com/parcelable-vs-serializable/

결론적으로 보면,

Serialization 도 그렇게 느리지는 않지만, Parcelable 이 훨씬 빠르다.

정말 많은 뭉태기의 property 들이 한 클래스에 있는 경우는 드물겠지만,

그런 경우라면 Parcelable 의 성능이 훨씬 빠르겠고..

IPC 가 많이 발생하는 경우라면, 가랑비에 옷 젖는 줄 모른다고, 작은 성능 차이가 결국 최적화에 엄청난 영향을 미칠 수 있다. 결국 정말 특별한 이유가 없다면, 사실 귀찮더라도 Serializable 보다는 Parcelable 을 사용하는 것이 추천된다.



  • 자바 서비스 프레임워크
    : 네이티브 서비스 프레임워크에서 제공하는 4가지 핵심 기능을 동일하게 제공하지만 시스템 내부에서 서비스가 동작하는 메커니즘이나 서비스 작성 방법에 있어서는 차이점이 있다.

    : 안드로이드 서비스 프레임워크가 자바 레이어와 C++ 레이어별로 존재하며 JNI를 통해 서로 연결돼 있음, JNI를 통해 네티이브 서비스 프레임워크를 재사용함으로써 자바 레이어의 서비스 사용자가 자바로 작성된 서비스뿐만 아니라 C++로 작성된 서비스도 이용할 수 있게 된다.


    : 자바 서비스 프레임워크는 네이티브 서비스 프레임워크와 다음과 같은 차이점이 있다.
     1. 서비스 생성: 자바 서비스 프레임워크에서 자바 서비스를 개발하는 방법은 두 가지다. 첫 번째 방법은 Binder 클래스를 상속받아 개발하는 것으로, 서비스를 정밀하게 제어해야 할 때 적절한 방식으로 자바 시스템 서비스를 작성할 때도 쓰이는 방법이다. 다행인 점은 안드로이드 개발자 도구에서 서비스 인터페이스와 서비스 생성코드를 자동으로 생성해 주는 AIDL 언어와 컴퍼일러를 제공하고 있어 네이티브 시스템 서비스를 제작하는 것보다 쉽게 자바 시스템 서비스를 작성할 수 있다.
    두 번째 방법은 Service 클래스를 상속받아 개발하는 것인데 일반적으로 특정 작업을 주기적으로 백그라운드에서 수행하는 프로세스를 구현하는 데 사용된다.
     2. 바인더 IPC 처리: 자바 서비스 프레임워크에서는 바인더 IPC를 지원하기 위해 JNI를 통해 연결된 네이티브 서비스 프레임워크의 구성요소를 재사용한다.

     ■ 자바 서비스 관리
     1. 자바 시스템 서비스는 네이티브 시스템 서비스와 마찬가지로 컨텍스트 매니저에 서비스를 등록한 후 서비스 매니저를 통해 서비스를 사용할 수 있다.
     2. 액티비티 매니저 서비스에서 관리.

    - 레이어


     : 각 레이어별로 네이티브 서비스 프레임워크와 차이점
    1. 서비스 사용자의 서비스 레이어에 매니저(Manager) 클래스가 위치
    2. RPC 레이어에 AIDL 도구로 자동 생성된 스텁(Stub)과 프록시 클래스(Proxy)가 위치
    3. IPC 레이어에 위치한 구성요소가 JNI를 통해 네이티브 서비스 프레임워크의 구성요소와 연결 


    -클래스별 상호작용



    - 구성요소 간의 상호작용


    (1) 서비스 등록 요청(서비스)
     : 네이티브 서비스 프레임워크에서 서비스를 시스템에 등록할 때는 네이티브 서비스 매니저인 BpServiceManager를 통해 서비스 등록 과정을 처리했지만 자바 서비스 프레임워크는 자바 서비스 매니저인 ServiceManager 클래스를 이용해서 이 과정을 처리한다. FooService 서비스는 자신을 시스템에 등록하기 위해 ServiceManager의 addService() 매서드를 호출한다. ServiceManager 내부에는 BinderProxy가 있으며, BinderProxy는 컨텍스트 매니저를 가리키는 BpBinder와 JNI를 통해 연결돼 있다.

    (2) 서비스 등록(서비스 매니저)
     : ServiceManagerProxy 서비스 프록시는 addService() 매서드의 호출 정보를 RPC 데이터로 변환한다. 이때 바인더 RPC 데이터는 Parcel 클래스에 저장되어 BinderProxy에 전달되고, JNI를 통해 BpBinder에 전달된다. 그러고 나서 바인더 IPC를 통해 컨텍스트 매니저에 전달되어 FooService 서비스가 시스템에 등록된다.

    (3) 서비스 검색 요청(서비스 사용자)
     : FooService 서비스를 사용하기 위해 네이티브 서비스 사용자는 BpServiceManager를 통해 서비스를 검색했지만 자바 서비스 사용자는 SDK에서 제공하는 getSystemService() 메서드를 호출해서 서비스를 검색한다.

    ■ Parcel



  • 자바 서비스 매니저


    - ServiceManager.java


  • 코어플랫폼 서비스
     : SystemServer 시스템 프로세스에서 일괄적으로 실행 
     : 애플리케이션이 직접 사용 하진 않지만, 프레임워크의 동작에 관여하는 서비스

     : Activity Manager Service, Window Manager Service, Package Manager Service 등

    - ActivityManagerService
     : 자바 시스템 서비스의 일종인 코어 플랫폼 서비스로서 안드로이드 애플리케이션 컴포넌트인 액티비티, 서비스, 브로드캐스트 리서버 등을 생성하고, 이들의 생명주기를 관리하는 역할








'Programing > Android' 카테고리의 다른 글

Handler, Looper  (0) 2016.04.19
Parcelable vs. Serializable  (0) 2016.03.22
안드로이드 - 네이티브 서비스 프레임워크  (0) 2016.01.13
안드로이드 - 바인더  (0) 2016.01.08
안드로이드 - 서비스  (0) 2016.01.08
  • 서비스 프레임워크 


    : 안드로이드 플랫폼에서 동작하는 서비스를 개발하기 위한 클래스의 집합
    : 서비스의 설계와 구현을 재사용 가능한 형태로 제공

     서비스 인터페이스 : 서비스 인터페이스는 서비스가 제공하는 기능을 함수 형태로 선언하여 이를 상속받은 서비스와 서비스 프록시가 모두 동일한 인터페이스로 서비스를 제공하고 사용할 수 있는 구조를 제공한다.
     서비스 생성 : 서비스 생성 기능은 서비스와 서비스 프록시의 생성을 지원한다. 서비스에서는 서비스 인터페이스에 정의된 함수를 구현(서비스 스텁 함수)하고 서비스 프록시에서는 서비스 스텁 함수를 원격 호출(서비스 프록시 함수)할 수 있게 구현해준다. 서비스 프레임워크에서는 서비스 프록시가 서비스를 요청할 수 있게 서비스의 위치 정보(서비스 핸들)를 제공하고, 서비스가 서비스 요청을 수신할 수 있는 방법을 제공한다.
     바인더 IPC 처리 : 서비스 프레임워크는 서비스와 서비스 사용자 사이에 바인더 IPC를 지원하기 위해 바인더 IPC 데이터를 생성하고 바인더 드라이버와 통신할 수 있는 기능을 제공한다.
     서비스 매니저 : 서비스 매니저는 시스템에 서비스를 등록하고 검색할 수 있는 기능을 제공한다.
     

  • 네이티브 서비스 프레임워크
    : C++로 작성되어 있으며, library layer에서 동작


    - 레이어
     

     1. 서비스 사용자가 foo() 함수를 호출하면, BpFooService의 foo() 프록시 함수가 호출 된다.
     2. BpFooService의 foo() 프록시 함수는 TRANSACTION_FOO RPC 코드와 인자값을 RPC 데이터로 변환한 후, BpBinder 클래스의 transact() 함수를 호출해서 RPC 코드와 데이터를 전달한다.
     3. BpBinder의 transact() 함수는 전달받은 RPC 코드와 데이터에 FooService 서비스의 서비스 핸들 정보를 추가한 후 IPCThreadState 클래스의 transact() 함수에 인자로 전달한다.
     4. IPCThreadState 클래스의 transact() 함수는 전달받은 데이터에 BC_TRANSACTION 바인더 프로토콜을 추가하여 바인더 IPC 데이터를 생성하고 이것을 바인더 드라이버에 전달한다.

     4. 바인더 드라이버는 IPCThreadState에게 바인더 IPC 데이터 정보를 전달한다. 그러면 IPCThreadState의 executeCommand() 함수에서 데이터를 분석하여 BR_TRANSACTION 바인더 프로토콜인 경우에 BBinder 클래스의 transact() 함수를 호출한다. 이때 transact() 함수의 인자로 서비스 클라이언트로부터 수신된 RPC 코드와 데이터가 전달된다.
     3. BBinder는 RPC 코드를 분석하여 기본적으로 제공하는 서비스 함수가 아닌 경우에 onTransact() 함수를 호출한다. 그런데 BnFooService가 BBinder를 상속하여 onTransact() 함수를 재정의했으므로 BnFooService 서비스 스텁의 onTransact() 함수가 호출된다. BBinder로 부터 전달받은 데이터는 다시 onTransact()의 인자로 전달한다.
     2. BnFooService의 onTransact()에서는 전달받은 RPC 데이터를 분석하여 TRANSACTION_FOO RPC 코드가 의미하는 FooService의 foo() 스텁 함수를 호출한다. 일반적으로 스텁 함수 호출시 RPC 데이터에 대한 언마샬링이 수행되어 인자로 전달되지만, foo() 스텁 함수는 인자가 없으므로 언마샬링이 수행되지 않는다.
     1. FooService의 foo() 서비스 스텁 함수가 실행된다.


    - 프록시


    - 스텁


    - 바인더 연결


  • 클래스 구조


    -
     IBinder, BBinder, BpBinder 
     : IBinder 클래스는 안드로이드 바인더를 추상화한 것이며 자식 클래스로 BBinder, BpBinder 클래스가 있다.
      BBinder 클래스는 RPC 코드와 데이터를 수신하는 역할과 바인더 드라이버 내부에 바인더 노드를 생성할 때 이용하는 바인더 객체로서의 역할을 담당.
      BpBinder 클래스는 목적지 서비스의 핸들 정보를 저장하고 바인더 드라이버가 서비스 서버의 바인더 노드를 찾을 때 이용하는 바인더 객체로서의 역할을 담당.  
    - IInterface, BnInterface, BpInterface
     : IInterface 클래스는 서비스나 서비스 프록시 클래스를 IBinder 타입으로 형변환하는 기능을 제공한다. 실제로 형변환은 BnInterface 클래스와 BpInterface 클래스에서 일어나며, BnInterface는 서비스 클래스를 BpInterface는 서비스 프록시 클래스를 IBinder 타입으로 형변환한다. 형변환이 필요한 이유는 바인더 객체를 바인더 드라이버를 통해 전송해야 하기 때문이다. 예를 들어, 서비스를 시스템에 등록하는 경우 서비스 클래스를 IBinder 타입으로 형변환해서 컨텍스트 매니저에 전달해야한다.
    - ProcessState, IPCThreadState
     : ProcessState  클래스는 바인더 드라이버를 관리하며 IPCThreadState 클래스는 서비스 클라이언트 및 서비스 서버와 바인더 드라이버 간의 바인더 IPC를 위한 통신을 지원한다.
    - Parcel
     : Parcel 클래스는 서비스와 서비스 프록시 사이에서 바인더 IPC가 진행되는 동안 바인더 IPC 데이터를 저장하는 역할을 담당한다. Parcel 클래스가 처리할 수 있는 데이터는 C언어의 기본 자료형 및 기본 자료형의 배열, 바인더 객체, 파일 디스크립터 등이 있다.
    - 서비스 레이어
     : IInterface, BnInterface, BpInterface, BpRefBase, 서비스 인터페이스, 서비스 클래스
    - RPC 레이어
     : 서비스 프록시 클래스, 서비스 스텁 클래스
    - IPC 레이어
     : BBinder, BpBinder, IPCThreadState, ProcessState, Parcel

  • 네이티브 서비스 매니저
    : 안드로이드 플랫폼에는 오디오 디바이스를 관리하는 Audio Flinger, 화면으로 보이는 프레임 버퍼 디바이스를 관리하는 Surface Flinger, 카메라 디바이스를 관리하는 카메라 서비스 등 각종 서비스가 있고, 이러한 서비스의 정보와 목록을 컨텍스트 매니저가 관리, 서비스는 자신의 이름으로 컨텍스트 매니저에 서비스 등록을 요청하고, 서비스 사용자는 접근하고자 하는 서비스의 이름으로 컨텍스트 매니저로부터 서비스의 정보를 획득.
    : 서비스 프레임워크에서는 서비스 사용자가 Audio Flinger, Surface Flinger, 카메라 서비스와 같은 각 서비스에서 제공하는 기능을 사용할 수 있게 바인더 RPC를 처리해 주는 서비스 프록시(Service Proxy)를 제공, 서비스 사용자는 서비스 프록시를 통해 해당 서비스의 기능을 사용하며, 서비스 프록시와 서비스 간의 복잡한 바인더 RPC는 하위 수준의 서비스 프레임워크에서 이뤄지므로 상위 수준의 서비스 사용자는 마치 동일한 프로세스에서 서비스를 이용하는 것처럼 느끼게 된다. 즉 서비스 프록시를 서비스라 생각하게 되는 것
    : 서비스 매니저는 컨텍스트 매니저의 서비스 프록시에 해당
     


    : 네이티브 서비스 매니저는 (2)에 해당한다.
    : 자바 시스템 서비스는 (3)의 자바 레이어의 서비스 매니저를 통해 서비스를 등록하고,
    네이티브 시스템 서비스는 (2)의 C/C++ 레이어의 서비스 매니저를 통해 서비스를 등록한다.
    (3)의 자바 레이어의 서비스 매니저는 JNI를 통해 (2)의 C/C++ 레이어의 서비스 매니저와 연결되고, C/C++ 레이어의 서비스 매니저는 바인더 드라이버를 통해 (1)의 컨텍스트 매니저와 바인더 RPC를 수행한다.

    - 서비스 매니저의 클래스 계층 구조와 바인더 RPC 과정


    - 서비스 매니저의 동작
    1. 서비스 매니저 초기화
     

    2. 서비스 등록
     
    3. 서비스 획득
     

    - 바인더 RPC 데이터와 코드, 바인더 IPC 데이터의 처리 과정



'Programing > Android' 카테고리의 다른 글

Parcelable vs. Serializable  (0) 2016.03.22
안드로이드 - 자바 시스템 프레임워크  (0) 2016.01.26
안드로이드 - 바인더  (0) 2016.01.08
안드로이드 - 서비스  (0) 2016.01.08
안드로이드 - Zygote  (0) 2016.01.06
  • 바인더?
    : 원래 IPC(Inter Process Communication) 도구이지만 안드로이드에서는 다른 프로세스에 있는 함수를 마치 현재 프로세스에 존재하는 함수처럼 사용할 수 있게 해주는 RPC(Remote Procedure Call)를 지원하는 데 주로 이용
    - 안드로이드에서 바인더 드라이버를 추가해서 프로세스 간 통신을 수행하는 이유? 
     : 리눅스의 뛰어난 메모리 관리 기법을 그대로 채용함으로써 커널 공간을 통한 데이터 전달시 데이터의 신뢰성을 확보
     : 사용자 공간에서 접근할 수 없는 공간인 커널 공간을 이용해 데이터를 주고 받기 때문에 IPC 간의 보안 문제도 동시에 해결

      


  • 리눅스 메모리 공간과 바인더 드라이버
    : 안드로이드의 프로세스는 리눅스와 마찬가지로 프로세스만의 고유한 가상 주소 공간에서 실행
    : 총 4GB에 달하는 가상 주소 공간은 3GB의 사용자 공간과 1GB의 커널 공간으로 나뉜다(커널 설정으로 변경 가능함)
    : 사용자 코드와 관련 라이브러리는 사용자 공간의 코드 영역, 데이터 영역, 스택 영역에서 동작하고, 커널 공간에서 동작해야 할 코드는 커널 공간의 각 영역에서 동작
    : 서로 다른 프로세스들은 커널 공간에서 실행하는 태스크와 데이터, 코드는 서로 공유
    : 바인더 드라이버에 존재하는 다양한 구조체는 대부분 레드 블랙 트리로 관리


  • 안드로이드 바인더 모델
    : 핸들은 서비스를 구별하는 번호, 어떤 서비스에 바인더 IPC 데이터를 전달해야 하는지를 결정
    : RPC 코드 RPC 데이터는 서비스에 호출할 함수와 함수의 인자
    : 바인더 프로토콜은 IPC 데이터의 처리 방법



    - 바인더 IPC 데이터의 전달
     : 바인더를 통해 RPC를 시도하는 응용 프로그램은 open() 시스템 콜을 통해 바인더 드라이버의 파일 디스크립터를 얻는다.
     : mmap() 시스템콜을 통해 커널 내에서 IPC 데이터를 수신하기 위한 공유 공간을 확보한다.
     : ioctl() 함수의 인자로 바인더 드라이브에 IPC 데이터를 전달한다.



    - 바인더 IPC 데이터의 흐름
     ■ 서비스 계층: 특정 기능을 수행하는 서비스의 함수가 존재하는 계층이다. 서비스 클라이언트는 이 계층에서 사용하고자 하는 서비스의 함수를 가상으로 호출하고, 서비스 서버는 서비스 클라이언트가 요청한 서비스의 함수를 실제로 호출한다.
     ■ RPC 계층: 서비스 클라이언트는 이 계층에서 서비스의 함수를 호출하기 위한 RPC 코드와 RPC 데이터를 생성한다. 서비스 서버는 전달받은 RPC 코드를 토대로 함수를 찾고 RPC 데이터를 전달한다.
     ■ IPC 계층: RPC 계층에서 만든 RPC 코드와 RPC 데이터를 바인더 드라이버에 전달하기위한 바인더 IPC 데이터로 캡슐화하는 역할을 한다. 실제로 서비스 클라이언트는 서비스 서버에 존재하는 서비스의 함수를 사용하기 위해 각 함수에 해당하는 식별자를 바인더 IPC 데이터에 담아 전달하는데, 이를 RPC 코드라 하며 함수의 인자 역시 IPC 데이터에 담아 전달하는데, 이것은 RPC 데이터라고 한다.
     ■ 바인더 드라이버 계층: IPC 계층으로부터 전달받은 바인더 IPC 데이터를 통해 서비스를 가진 서비스서버를 찾은 후 IPC 데이터를 전달한다.


    - 바인더 어드레싱
     : 바인더 드라이버는 IPC 데이터의 핸들을 가지고 서비스 서버를 찾는데, 이러한 과정을 바인더 어드레싱(Binder Addressing)이라고 정의
     : 다양한 서비스를 모두 목록화해서 관리하는 컨텍스트 매니저라는 특별한 프로세스가 서비스마다 핸들(바인더 IPC의 목적지 주소로 사용)라는 번호 값을 할당하고, 서비스 추가/검색 등의 관리 기능을 수행

     ■ 서비스 등록
      : 바인더 어드레싱을 위해 서비스 서버는 자신이 가진 서비스에 대한 접근 정보를 컨텍스트 매니저에 등록해야 한다.
      : 안드로이드 부팅 단계에서 끝나고, 등록이 끝나면 컨텍스트 매니저의 서비스 목록, 바인더 드라이버의 바인더 노드, 그리고 서비스 서버들의 서비스가 연결되어 다른 프로세스가 사용가능한 상태가 된다.
      : 서비스 서버와 컨텍스트 매니저 사이의 IPC

     
     ■ 서비스 검색
      : 서비스 클라이언트와 컨텍스트 매니저 사이의 IPC


     ■ 서비스 사용
      : 서비스 클라이언트와 서비스 서버 사이의 IPC


    mmap
     
      : 일반적으로 커널 공간에서 사용자 공간으로 데이터를 전달하기 위해서는 copy_to_user() 함수를 이용해서 사용자 공간으로 데이터를 복사한다.
      : but, 대용량의 데이터를 응용 프로그램과 주고 받아야 하는 상황에서 read, write, ioctl 같은 시스템 콜 함수를 쓴다면 매우 비효율적이며, 커널 공간이 부족할수 있다. -> 문제점을 해결하기 위해 mmap을 사용, 응용 프로그램이 커널의 물리 메모리에 직접 접근 가능하도록 해 준다.
      : 바인더를 이용하는 프로세스는 바인더 드라이버의 mmap() 함수를 통해 사용자 공간과 매핑된 바인더 mmap 영역을 만든다. 그리고 바인더 드라이버는 커널 공간의 데이터 수신영역에 데이터를 저장만하고, 사용자 공간에 mmap 된 영역의 정보만 알려준다. 따라서 프로세스는 사용자 공간의 mmap 된 영역의 주소만 알고 있어도 커널 공간에 존재하는 데이터를 참조 할 수 있다.
      : 이 함수의 주요 목적은 사용자 프로세스가 전달한 크기만큼 커널 공간에 IPC 데이터 수신 버퍼를 확보하는 것이다.

  • 정리
     : 바인더는 안드로이드의 서비스를 보유한 서비스 서버, 서비스를 사용하고자 하는 서비스 클라이언트, 서비스의 위치를 알려주는 컨텍스트 매니저, 그리고 이들 모두를 중재하는 바인더 드라이버로 구성된다.



  • 서비스?
    : UI 없이 주기적으로 특정한 일을 수행하는 백그라운드 프로세스

    - 서비스 분류


  • 안드로이드 애플리케이션 서비스
    : 안드로이드 SDK의 Service 클래스를 확장한 클래스의 인스턴스로 UI 없이 주기적으로 특정한 일을 수행하는 백그라운드 프로세스
    : 애플리케이션단에서 서비스 시작, 종료, 바인딩을 통한 서비스 원격 제어 가능
     

    - 애플리케이션 서비스 분류


  • 안드로이드 시스템 서비스
    : init 프로세스에 의해 안드로이드의 부팅 과정에서 미리 실행
    : getSystemService()를 이용해서 바로 이용 가능
    : Media Server, System Server 두 시스템 프로세스에 의해 실행

    - 시스템 서비스 분류


     ■ 네이티브 서비스

      : C++로 작성
      : 여러 안드로이드 애플리케이션의 오디오 데이터를 믹싱해서 오디오 출력 장치로 내보내는 역할, 안드로이드 장치에서 모든 오디오 데이터는 Audio Flinger를 거쳐 출력.
      : Surface Flinger는 다양한 애플리케이션에서 사용중인 Surface를 조합해 프레임 버퍼 장치로 렌더링해주는 서비스 


     ■ 자바 시스템 서비스
      : 안드로이드 부팅 시 SystemServer라는 시스템 프로세스에 의해 일괄적으로 실행
      : 안드로이드 애플리케이션과 직접 상호작용은 하지 않지만 안드로이드 프레임워크가 동작하는 데 필수적인 코어 플랫폼 서비스
      : 저수준 하드웨어 제어를 위한 API를 제공하는 하드웨어 서비스

    - Layer Interaction
     : There are 3 main flavors of Android layer cake
     1. App -> Runtime Service -> lib
      
     2. App -> Runtime Service -> Native Service -> lib
      
     3. App -> 
    Runtime Service -> Native Deamon -> lib
      

    - Media Server / System Server

      ■ Media Server
      
      ■ System Server
      
      ■ Context Manager
        : 서비스 관련 요청을 수행하기 위해서는 IPC 데이터를 수신 대기하는 상태에 들어 있어야 하기 때문에 다른 서비스 서버나 서비스 클리이언트 이전에 미리 실행돼야한다.
        : init.rc 내용을 살펴보면 서비스 서버인 미디어 서버 프로세스나 시스템 서버 프로세스가 실행되기 이전에 실행(servicemanager) 됨


      

  • 안드로이드 시스템 전체 요약
    - 용어 정리
      ■ 서비스 서버 : 시스템 서비스를 실행하는 프로세스로서 앞에서 설명한 시스템 서버나 미디어 서버
      ■ 서비스 클라이언트 : 시스템 서비스를 사용하는 프로세스
      ■ 컨텍스트 매니저 : 시스템 서비스를 관리하는 안드로이드 시스템 프로세스로서 시스템에 설치돼 있는 각종 시스템 서비스의 위치 정보인 핸들을 관리. 이러한 핸들은 바인더 IPC의 목적지 주소를 지정하는 데 사용한다.
      ■ 서비스 프레임워크 : 앞에서 언급한 서비스 매니저를 포함해서 서비스 사용자와 시스템 서비스간의 RPC 동작에 필요한 공통적인 클래스가 정의
      ■ 서비스 인터페이스 : 서비스 사용자와 시스템 서비스 간에 미리 정해진 인터페이스로서 시스템 서비스는 해당 인터페이스에 맞게 스텁 함수를 구현해서 해당 서비스를 제공해야 하고, 반대로 서비스 사용자 역시 해당 인터페이스에 맞게 서비스를 호출해야 한다.
      ■ 서비스 사용자 : 서비스 클라이언트 프로세스 내에서 실제 서비스를 이용하는 모듈이다.
      ■ 서비스 : 서비스 인터페이스에 정의된 기능을 서비스 스텁 함수로 구현해서 실제 서비스의 기능을 제공하는 모듈을 의미한다.
      ■ 서비스 프록시 : RPC 수행 시 데이터 마샬링을 수행하는 객체이며 서비스 인터페이스별로 존재한다. 서비스 인터페이스에 정의된 함수별로 각각 데이터 마샬링을 수행하는 서비스 프록시 함수를 제공한다.
      ■ 서비스 스텁 : RPC 수행 시 데이터 언먀실링을 수행하는 객체이며, 이 객체 역시 서비스 인터페이스별로 존재한다. 수신된 데이터를 언마샬링해서 연관된 서비스 스텁 함수를 호출한다.
      ■ 바인더 드라이버 : 바인더는 안드로이드에서 IPC를 지원하는 데 사용되는 메커니즘으로 안드로이드 리눅스 커널의 디바이스 드라이버 형태로 포함돼 있다.
      ■ 바인더 IPC : 안드로이드에서 바인더 드라이버를 통한 프로세스간의 데이터 전달 방식을 말한다.
      ■ 바인더 IPC 데이터 : 서비스 프레임워크와 바인더 드라이버 사이에 사용되는 데이터 포맷
      ■ 바인더 RPC : 서비스 사용자가 서비스에서 제공하는 특정 서비스 인터페이스 기반의 함수를 마치 자신의 로컬 함수 호출하듯이 원격으로 처리하는 동작을 말한다. 바인더 RPC는 내부적으로는 바인더 IPC 메커니즘 기반으로 동작한다.
      ■ 바인더 RPC 데이터 : 서비스 사용자와 서비스 간의 바인더 RPC를 수행하는 데 사용되는 데이터

    - 서비스 동작 구조



     : 서비스 사용자는 foo() 프록시 함수를 호출해서 Foo 서비스를 이용하기 위한 인자로 구성된 바인더 RPC 데이터를 전달
     : 바인더 RPC 데이터는 마샬링을 거쳐 서비스 프레임워크를 통해 바인더 IPC 데이터로 생성된 다음, 바인더 드라이브를 통해 서비스 서버 측에 전송
     : 서비스 서버 측에서 수신된 바인더 IPC 데이터는 서비스 프레임워크를 거치면서 언마샬링된 다음, 서비스 스텁의 OnTransact() 함수에 전송
     : 서비스 스텁은 해당 바인더 IPC 데이터 안에 포함된 RPC 코드를 통해 Foo 서비스의 foo() 서비스 스텁 함수에 대한 바인더 RPC임을 판단
     : 수신된 바인더 IPC 데이터에 포함된 바인더 RPC 데이터를 인자로 해서 foo() 서비스 스텁 함수를 호출




'Programing > Android' 카테고리의 다른 글

안드로이드 - 네이티브 서비스 프레임워크  (0) 2016.01.13
안드로이드 - 바인더  (0) 2016.01.08
안드로이드 - Zygote  (0) 2016.01.06
안드로이드 - JNI  (0) 2015.12.23
안드로이드 - Init 프로세스  (0) 2015.12.21
  • Zygote?
    - '분할 전의 세포나 수정란', 개체가 생성되기 이전의 불완전한 상태
    달빅(Dalvik) 초기화 수행
    - 애플리케이션 실행 속도 향상
    - System Server 를 실행


     안드로이드 애플리케이션은 자바로 작성돼 있어 리눅스 상에서 네이티브 프로세스로 실행될 수 없으며 달빅 가상 머신에서 동작한다. 각 안드로이드 애플리케이션은 독립적인 가상 머신 위에서 동작하는데, 실행될 때마다 자신이 동작할 가상 머신을 초기화하고 실행하는 과정에는 많은 시간이 소요되며 애플리케이션의 실행을 느리게 하는 요인이 된다. 때문에 안드로이드에서 Zygote 프로세스는 애플리케이션이 실행되기 전에 실행된 가상 머신의 코드 및 메모리 정보를 공유함으로써 애플리케이션이 실행되는 시간을 단축시킬 수 있다. 여기에 더해 안드로이드 프레임워크에서 동작하는 애플리케이션이 사용할 클래스와 자원을 미리 메모리에 로딩해 두고 이러한 자원에 대한 연결 정보를 구성한다. 새로 실행되는 안드로이드 애플리케이션은 필요한 자원들에 대한 연결정보를 매번 새롭게 구성하지 않고 그대로 사용하기 때문에 빠르게 실행된다.

  • Zygote를 통한 프로세스의 생성



     : 부모 프로세스 A는 fork() 시스템 콜을 호출하여 새로운 자식 프로세스 A'를 생성 - 새로 생성된 프로세스 A'는 부모 프로세스인 프로세스 A의 메모리 구성 정보 및 공유 라이브러리에 대한 링크 정보를 공유한 상태
     : 자식 프로세스 A'는 exec('B') 시스템 콜을 호출해 새로운 프로세스 B의 코드를 메모리로 로딩한다. 이때 부모 프로세스 A의 메모리 정보는 지워지고 로딩된 B를 실행하는 데 필요한 메모리를 새롭게 구성한 후 프로세스 B가 사용할 공유 라이브러리에 대한 링크 정보를 새로 구성
     : 만약 새로운 프로세스 B가 사용할 공유 라이브러리가 메모리에 이미 로딩돼 있는 상태라면 이에 대한 링크 정보만 새롭게 구성하지만 그렇지 않은 경우에는 스토리지에서 해당 라이브러리를 메모리로 로딩하는 과정이 추가로 필요하다. 이러한 과정이 새로운 프로레스를 실행할 때 마다 일어난다.
     => COW(Copy On Write)를 통해 기존에 이미 메모리 상에서 동작중인 프로세스의 재사용성을 극대화하고 공유 라이브러리를 통해 메모리 사용량(foot print)을 최소화
    - COW(Copy On Write)?
     프로세스를 생성할 때 새로 생성된 프로세스는 부모 프로세스와 메모리 공간을 공유한다. 즉, 자식 프로세스는 부모 프로세스가 생성한 메모리 공간에 관한 정보를 모두 복사하여 그대로 사용하는데, COW는 이러한 메모리 공간을 복사하는 시점에 대한 것이다. 메모리 복사를 하는 것은 오버헤드가 매우 크기 때문에 생성된 자식 프로세스가 부모의 메모리 공간을 참조만 할 경우에는 이를 복사하지 않고 부모의 메모리 공간을 공유하게 된다. 공유하는 메모리 정보를 자식 프로세스가 수정하는 시점에서 부모 프로세스의 메모리 정보를 자신의 메모리 공간으로 복사하는 것이 바로 COW 기법이다.
     만약 fork()를 호출한 이후에 exec()가 바로 실행되면 새로 생성되는 프로세스의 메모리 공간은 부모 프로세스의 메모리 공간과 내용이 다르며, 이 때문에 부모 프로세스의 메모리 공간을 복사하는 것은 무의미하여, 오히려 새로운 프로세스를 실행하는 데 있어 큰 오버헤드를 초래할 뿐이다.



    : Zygote 프로세스는 fork() 시스템 콜을 호출해 자식 프로세스인 Zygote' 프로세스를 생성
    : 생성된 Zygote' 프로세스는 부모인 Zygote 프로세스의 코드 영역과 링크 정보를 공유
    : 새로운 안드로이드 애플리케이션 A는 fork()를 통해 생성된 프로세스의 코드 영역을 새롭게 로딩하는 것이 아니라, 복제된 달빅 가상 머신 위에 동적으로 로딩.
    : Zygote'프로세스는 애플리케이션 A 클래스의 메서드로 실행 흐름을 넘겨 안드로이드 애플리케이션이 동작, 새로 생성된 애플리케이션 A는 기존의 Zygote 프로세스가 구성해 놓은 라이브러리 및 리소스에 대한 링크 정보를 그대로 사용하기에 빠르게 실행

  • app_process로부터 ZygoteInit class 실행
    - app_process의 역할? 
     : Zygote는 자바로 작성돼 있으므로 다른 네이티브 서비스나 데몬과 같이 init 프로세스에서 바로 실행할 수 없으므로 자바로 작성돼 있는 Zygote 클래스가 동작하려면 달빅 가상 머신이 생성돼야 하고, 생성된 가상 머신 위에서 ZygoteInit 클래스를 로딩하고 실행해야 한다.


    - AppRuntime 객체 생성 및 실행
    - 달빅 가상 머신의 생성
    - ZygoteInit 클래스의 실행

  • ZygoteInit 클래스의 기능

    - dev/socket/zygote 소켓 바인딩
    - 애플리케이션 프레임워크에 속한 클래스와 플랫폼 자원의 로딩
    - SystemServer 실행
      : zygote에서 달빅 가상 머신 구동 -> 시스템 서버라는 자바 서비스를 실행하기 위해 새로운 달빅 가상 머신 인스턴스 생성
      : Audio Flinger, Surface Flinger 네이티브 서비스 실행, 필요한 서비스를 실행되고 나면 안드로이드 프레임워크의 서비스를 시작

    - 새로운 안드로이드 애플리케이션 실행



'Programing > Android' 카테고리의 다른 글

안드로이드 - 바인더  (0) 2016.01.08
안드로이드 - 서비스  (0) 2016.01.08
안드로이드 - JNI  (0) 2015.12.23
안드로이드 - Init 프로세스  (0) 2015.12.21
안드로이드 - 커널  (0) 2015.12.21
  • JNI? Java Native Interface로 안드로이드 프레임워크에서 C/C++과 자바 레이어가 유기적으로 동작하게 만들려면 자바 레이어(상위)와 C/C++ 레이어(하위)를 상호 연결해 주는 매개체가 필요하다. 그림 4-1의 좌측과 같이 자바와 C/C++ 모듈 간의 인터페이스를 가능하게 해주는 것이 바로 JNI(Java Native Interface)이다.






    : JNI는 일반적으로 다음과 같은 경우에 주로 활용한다.
    : 안드로이드 SDK를 토대로 만든 안드로이드 애플리케이션은 달빅 가상 머신(Dalvik Virtual Machine) 위에서 동작하는 자바 기반의 프로그램이다. 때문에 C/C++로 생성한 애플리케이션에 비해 느린 실행 속도 등 자바가 지닌 여러 한계를 그대로 가지고 있다. 가령, 그래픽픽 처리나 시그널 프로세싱처럼 CPU의 처리 속도가 중요한 부분에서는 자바보다 C/C++ 같은 네이티브 코드로 작성한 모듈이 훨씬 더 나은 성능을 낼 것이다.
    : SDK(Software Development Kit), NDK(Native Development Kit)

    - 빠른 처리 속도를 요구하는 루틴 작성
     : 대개 자바는 네티이브 코드(C/C++등)에 비해 느리다. 따라서 빠른 처리 속도를 요하는 부분은 C/C++로 작성하고 이를 JNI를 통해 자바에서 호출하는 방법으로 속도 향상을 꾀할 수 있다.

    - 하드웨어 제어
     : 하드웨어 제어 코드를 C로 작성한 다음 JNI를 통해 자바 레이어와 연결하면 자바에서도 하드웨어 제어가 가능하다.

    - 기존 C/C++ 프로그램의 재사용
     : 이미 기존 코드가 대부분 C/C++로 작성돼 있다면 굳이 자바로 동일한 코드를 다시 작성하기보다는 JNI를 통해 기존 코드를 활용할 수 있다.

  • 자바에서 C 라이브러리 함수 호출
    ① 자바 코드 작성
     : 자바 클래스에 네이티브 메서드 선언
     : System.loadLibrary() 메서드를 호출해서 C 라이브러리 로딩
     

    ② 자바 코드 컴파일
    ③ C 헤더 파일 생성
     : 자바 가상 머신에서 함수 매핑 테이블이 필요
     : javah라는 툴을 이용하여 자바 네이티브 메서드와 연결될 수 있는 C 함수의 원형 생성(JNI 네이티브 함수 원형이 포함된 헤더 파일을 생성)
     

      

    ④ C 코드 작성
     : JNI 네이티브 함수 구현

    ⑤ C 공유 라이브러리 생성
     : C 공유 라이브러리 빌드

     자바 프로그램 실행
     : JNI를 통한 네이티브 함수 호출
       


  • C 프로그램에서 자바 클래스 실행하기
    C/C++에서 Java의 클래스를 이용하기 위해서는 Reflection 기술을 이용해야 한다.
     자바 가상 머신에 전달할 옵션값을 생성
     자바 가상 머신 생성
     실행할 클래스 검색 후 로드
    ④ 해당 메서드 ID 획득
    ⑤ 클래스 메서드의 인자로 넘겨줄 객체 생성
    ⑥ 메서드 호출
    ⑦ 자바 가상 머신 소멸


  • 안드로이드 NDK
    : Native Development Kit로 JNI를 활용한 작업을 쉽게 할 수 있도록 구글에서 제공하는 개발 
    도구

    : C/C++ 소스를 네이티브 라이브러리로 빌드하기 위한 도구(컴파일러, 링커 등)
    : 빌드된 네이티브 라이브러리를 안드로이드 패키지 파일(.apk)에 삽입
    : 네이티브 라이브러리 작성 시 안드로이드 플랫폼에서 지원 가능한 시스템 헤더 파일 및 라이브러리
    : NDK 개발 관련 문서, 예제, 튜토리얼
    : 안드로이드에서 동작하는 네이티브 라이브러리는 리눅스용 공유 라이브러리(*.so)로 만들어야 한다. 대다수의 개발자가 윈도 환경에서 안드로이드를 개발하고 있으므로 윈도 환경에서 리눅스 기반의 라이브러리를 빌드하기 위해 Cygwin 필요



'Programing > Android' 카테고리의 다른 글

안드로이드 - 서비스  (0) 2016.01.08
안드로이드 - Zygote  (0) 2016.01.06
안드로이드 - Init 프로세스  (0) 2015.12.21
안드로이드 - 커널  (0) 2015.12.21
안드로이드 - 뷰  (0) 2015.12.21



- 리눅스와 마찬가지로 안드로이드에서는 커널 부팅이 완료되면 최초의 사용자 프로세스인 init 프로세스를 실행 한다.



 리눅스의 프로세스들은 서로 정보를 교환하기 위해 메시지를 주고 받는데, 이러한 메시지를 시그널이라고 한다. 그리고 각 프로세스는 다른 프로세스에서 발생하는 시그널을 처리하기 위한 루틴을 등록하는데 이를 시그널 핸들러라고 한다. 시그널에는 프로세스의 실행 상태가 변경되거나 종료됐을때 발생하는 시그널이 있으며, 모든 프로세스의 부모인 init 프로세스는 자신이 생성한 프로세스가 종료됐을 때 발생하는 SIGCHLD 시그널을 처리할 핸들러를 등록한다. 시그널에 대한 실제 처리는 init 프로세스 동작 과정의 마지막 단계인 이벤트 처리 루프에서 수행된다.

- 안드로이드 init 프로세스는 다음과 같이 크게 4가지 기능을 수행한다.


① init.rc 파일 분석 및 실행
 : init 프로세스가 해야 할 일을 기술한 init.rc 파일을 분석해서 해당 파일에 담긴 내용에 따른 기능을 수행 한다. 



Figure 1. Android root file system

 - 액션 리스트
  : 'on init' 섹션에서는 환경변수를 등록하고, 시스템 동작 시 필요한 파일 및 디렉터리 생성하고 퍼미션을 조작, 시스템 동작과 관련된 디렉터리 /system, /data를 마운트
  : 'on boot' 섹션에서는 애플리케이션 종료 조건 설정, 애플리케이션 구동에 필요한 디렉터리 및 파일 퍼미션 설정 등
 - 서비스 리스트
  : init.rc 파일에서 'service' 섹션은 init 프로세스가 실행시키는 프로세스를 기술
 - init.rc 파싱 코드 분석
 - 액션리스트 및 서비스 리스트의 실행

② 디바이스 드라이버 노드 생성
 : 응용 프로그램이 디바이스 드라이버에 접근할 때 사용하기 위한 디바이스 노드 파일을 생성 
 init 프로세스는 시그널 핸들러를 등록한 후 부팅에 필요한 디렉터리를 생성하고 마운트한다. 안드로이드 빌드를 통해 생성되는 루트 파일 시스템은 /dev, /proc, /sys와 같은 디렉터리가 존재 하지 않는다. 이러한 디렉터리는 시스템의 운용 중에만 필요한 디렉터리로 init 프로세스가 동작 중에 생성하고 시스템이 종료되면 다시 사라진다.
 : 리눅스 커널 2.6 미만에서는 디바이스 노드 파일을 사용자가 직접 만들어야 했다. 이때 노드 파일에 필요한 메이저 번호와 마이너 번호를 겹치지 않게 만든 다음 mknod 유틸리티를 통해 생성했다. 하지만 사용자가 일일이 메이저 번호와 마이너 번호를 알아야 했고 번호 간의 충돌을 주의해야 하는 등의 불편함 때문에 커널 2.6x부터는 udev(userspace device)라는 유틸리티 등장. udev는 데몬 프로세스로 동작하면서 디바이스 드라이버가 로딩될 때 메이저 번호와 마이너 번호, 디바이스 타입을 파악해서 "/dev" 디렉터리에 자동으로 디바이스 노드 파일을 생성하는 역할을 한다. 


 

 - 정적 디바이스 노드 생성(콜드플러그)
 - 동적 디바이스 감지(핫플러그)


자식 프로세스 종료 처리
 : 리눅스상에서 동작하는 모든 프로세스는 init 프로세스에서 생성되어 실행된다.
 리눅스 커널이 부팅하고 나면 사용자 영역에서 init 프로세스가 최로로 실행된 다음 시스템 동작에 필요한 다른 프로세스들을 순차적으로 실행시킨다. 시스템 부팅이 완료된 이후, init 프로세스는 백그라운드 프로세스로 동작하면서 다른 프로세스를 감시한다. 만약 감시중인 프로세스가 종료되어 좀비 상
태가 되면 해당 프로세스가 가진 자원이 정상적으로 반환되게 하는 역할을 수행한다. 안드로이드 플랫폼의 init 프로세스는 일반적인 리눅스 상의 init 프로세스가 수행하는 기능 외에도 몇 가지 추가적인 기능을 수행한다. 




 - 프로세스 종료와 재시작

④ 프로퍼티 서비스
 : 시스템 동작에 필요한 환경 변수를 저장하는 프로퍼티 서비스를 제공한다.

 

 - 프로퍼티 초기화
 - 프로퍼티 변경 요청 처리

POLL 서버(메인 루프)


'Programing > Android' 카테고리의 다른 글

안드로이드 - Zygote  (0) 2016.01.06
안드로이드 - JNI  (0) 2015.12.23
안드로이드 - 커널  (0) 2015.12.21
안드로이드 - 뷰  (0) 2015.12.21
안드로이드 - 4대 컴포넌트  (0) 2015.12.21

+ Recent posts