• 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