File Descriptor (파일 디스크립터) [출처: http://dev.plusblog.co.kr/22]


1. 파일 디스크립터

- 시스템으로부터 할당 받은 파일을 대표하는 0이 아닌 정수 값

- 프로세스에서 열린 파일의 목록을 관리하는 테이블의 인덱스



흔히 유닉스 시스템에서 모든 것은 파일이라고 한다. 일반적인 정규파일(Regular File)에서부터 디렉토리(Directory), 소켓(Socket), 파이프(PIPE), 블록 디바이스, 캐릭터 디바이스 등등 모든 객체들은 파일로써 관리된다. 유닉스 시스템에서 프로세스가 이 파일들을 접근할 때에 파일 디스크립터(File Descriptor)라는 개념을 이용한다.


파일 디스크립터는 '0이 아닌 정수', 'Non-negative Integer' 값이다. 즉, 음수가 아닌 0과 양수인 정수 값을 갖는다. (unsigned int 값이라고 보면 된다.) 프로세스가 실행 중에 파일을 Open 하면 커널은 해당 프로세스의 파일 디스크립터 숫자 중에 사용하지 않는 가장 작은 값을 할당해 준다. 그 다음 프로세스가 열려있는 파일에 시스템 콜을 이용해서 접근 할 때, FD 값을 이용해 파일을 지칭 할 수 있다. 


프로그램이 프로세스로 메모리에서 실행을 시작 할 때, 기본적으로 할당되는 파일 디스크립터들이 있다. 바로 표준 입력(Standard Input), 표준 출력(Standard Output), 표준 에러(Standard Error)이다. 이 들에게 각각 0, 1, 2 라는 정수가 할당되며, POSIX 표준에서는 STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO로 참조된다. 이 매크로는 <unistd.h> 헤더 파일에서 찾아 볼 수 있다. 

0이 아닌 정수로 표현되는 파일 디스크립터는 0 ~ OPEN_MAX 까지의 값을 가질 수 있으며, OPEN_MAX 값은 플랫폼에 따라 다르다.






파일 디스크립터는 위 그림을 보면서 개념 정리를 하면 좋다. 파일 디스크립터가 단순히 숫자인 이유는 프로세스가 유지하고 있는 FD 테이블의 인덱스이기 때문이다. FD 3번이라는 의미는 FD 테이블의 3번 항목이 가리키는 파일이라는 의미이다. FD 테이블의 각 항목은 FD 플래그와 파일 테이블로의 포인터를 가지고 있다. 이 포인터를 이용하여 FD 를 통해 시스템의 파일을 참조 할 수 있는 것이다.

프로세스는 이런 FD 테이블과 파일 테이블의 정보를 직접 고칠 수 없으며, 반드시 커널을 통해서 수정을 해야 한다.

파일 디스크립터란 뭔가?! [출처: http://z-man.tistory.com/151]

파일 디스크립터는 파이프, FIFO, 소켓, 터미널, 디바이스, 일반파일 등 종류에 상관없이 모든 열려있는 파일을 참조할때 쓴다.

파일디스크립터 

목적 

POSIX 이름 

stdio 스트림 

 0

 표준 입력

 STDIN_FILENO

 stdin

 1

 표준 출력

 STDOUT_FILENO

 stdout

 2

 표준 에러

 STDERR_FILENO

 stderr

 

표에 있는 3가지 디스크립터는 프로그램이 시작할때 셸의 디스크립터의 복사본을 상속 받고, 셸은 보통 3가지 파일 디스크립터가 언제나 열린채로 동작 한다.

프로그램에서 파일 디스크립터를 참조할때는 번호(0,1,2)를 쓸 수도 있지만 가능하면 "UNISTD.H"에 정의된 POSIX 이름을 쓰는편이 좋다..

 

1
2
3
4
5
6
7
8
fd = open( pathname, flags, mode )
// pathname 이 가리키는 파일을 열고 열린 파일을 이후 호출에서 참조 할 때 쓸 파일 디스크립터를 리턴.
// flags는 파일을 읽기, 쓰기, 둘다를 위해 열지를 지정 한다.
numread = read( fd, buffer, count )
// fd가 가리키는 파일에서 최대 count 바이트를 읽어 buffer에 저장.
numwritten = write( fd, buffer, count )
// 버퍼에서 최대 count 바이트를 fd가 가리키는 열려 있는 파일에 쓴다.
status = close(fd) 모든 i/o 를 마친뒤 fd와 관련 커널 자원을 해제 한다.

fd는 해당 프로세스의 open file 을 관리하는 구조체 배열의 index.

그 구조체의 index 가 가리키는 객체가 dentry 라는 객체이고, 그 dentry 객체는 또다시 해당 파일을 나타내는 inode 객체를 가리키게 됩니다.

커널 구조체중 struct files_struct 보시면 struct file fd_array 라는 배열이 있다.
실제로 open()을 통해 얻는 fd 는 저 구조체의 index 를 나타냅니다.

일반적으로 0, 1, 2 index 는 std-in/std-out/error 와 관련된 fd 로 미리 할당이되고, 보통 open()을 하게 되면 fd 값은 3이 됩니다.

3 번 index 로 test.txt 를 찾는 방법은 
우선 fd_array[3] 이 pointing 하고 있는 file 구조체의 f_dentry 를 얻어오게됩니다. dentry 란 것은 directory entry 를 의미하는데, 리눅스에서 디렉토리에 접근을 빠르게 하기 위한 구조체로 사용하고 있습니다. open() 시스템 콜을 호출하게 되면, test.txt 가 존재하는 위치와 관련되어 dentry 구조체가 만들어집니다.

dentry 구조체는 관련된 inode 구조체를 가리키는 필드를 포함합니다.
따라서 open("test.txt',...) 함수로 호출된 파일은 test.txt 에 대한 dentry 생성, inode 생성(또는 읽음) 후에 해당 프로세스의 open 파일 관리 구조체인 files_struct 의 fd_array 의 비어있는 위치에 test.txt 의 dentry 를 포인팅하고 그 index 인 3을 넘겨주는 것입니다.

이후 사용자가 3번을 가지고 시스템 콜을 수행하게되면, 해당 프로세스의 files_struct 의 fd_array index 를 통해서 관련 inode에 접근할 수 있게 되는 것입니다.

 

파일 디스크립터와 열려 있는 파일의 관계

각 프로세스별로 커널은 open file descriptor table 을 갖고 있다. 테이블의 각 엔트리는 하나의 파일 디스크립터에 대한 동작 제어 플래그, 열린 파일을 가리키는 참조를 담고 있다.

open file description은 현재 파일의 offset, flag, 접근 모드, i/o 관련 설정, 파일의 i-node 객체를 가리키는 레퍼런스를 갖고 있다.

i-node는 파일 종류 (일반파일, 소켓, fifo)와 권한, lock 목록 포인터, 여러 파일 오퍼레이션과 다양한 파일 속성(크기, 타임스탬프등)을 갖고 있다.

만약 같은 open file description을 가리키는 2개의 fd는 offset값을 공유 한다.

'Major > Linux' 카테고리의 다른 글

리눅스 - Ext4 File System  (0) 2016.02.01
리눅스 - 가상 파일 시스템  (0) 2016.01.28
리눅스 - 파일 시스템  (0) 2016.01.28
리눅스 - System Call  (0) 2016.01.28
리눅스 - 기초  (0) 2016.01.28
  • 파일 시스템 (File System)
    : 저장장치 내에서 데이터를 읽고 쓰기 위해 미리 정해진 약속
    : 파일 저장 및 검색을 용이하도록 유지/관리하는 방법
    : 파일을 어떻게 관리할 것인가에 대한 메커니즘과 정책
    : 파일 + 디렉토리 구조
    : EXT2, EXT3, FAT, FAT32, NTFS, JFFS, JFFS, JFFS2, ISO 9660 ...
    : Journaling File System - 파일 시스템의 변화를 기록해 두었다가 시스템 결함으로 문제가 발생할 경우 파일 시스템 복구

       

    - 섹터에 대한 파일 매핑
     

    - 기능
     : 파일 생성, 제거, 수정
     : 타인과 파일 공동 사용
     : Backup & Recovery
     : 물리적 장치 이름 대신 기호화된 이름 사용- 장치와의 독립성 제공 : C:, D:, /, /home, /dev/sda1
     : 정보의 안전한 보관편리한 인터페이스
     : 타겟 저장장치에 따른 최적화된 접근, 할당 정책
     
  • 파일 (File)
    : 디스크와 같은 물리적인 저장 매체에 저장되는 데이터 집합
    : 데이터 정보에 대한 논리적인 저장 단위
    : 저장장치의 물리적 특성을 추상화한 논리적 저장 단위
    : 자료가 파일 안에 존재해야만 보조 저장장치에 기록될 수 있음

    - 속성(Attributes)

     : 이름, 식별자, 타입, 위치, 크기, 보호, 시간 등
     : 파일의 내용을 제외한 파일의 모든 정보는 보조 저장장치에 상주하는 디렉터리 구조 내에 유지
     : 1단계, 2단계 디렉터리 구조, 트리 구조 디렉터리, 일반 그래프 디렉터리 구조 등 다양한 디렉터리 구조가 존재
     

  • 할당 방법 (Allocation Methods)
    : 파일 시스템은 파일을 디스크 블록(block)이라는 논리적인 단위의 집합으로 관리
     -> 사용자가 파일을 디스크에 저장하기를 요청하면 파일은 블록단위로 분할되어 파일 시스템 정책에 따라 일정한 장소에 내용을 기록
     -> 블록의 크기는 1KB, 4KB, 16KB, 64KB 등
    : 디스크 할당의 주요 문제는 파일들을 어떻게 디스크 공간에 배치해야 디스크 공간을 효율적으로 사용할 수 있고, 파일들에 빨리 접근할 수 있는가
    : 디스크의 직접 접근 특성이 파일의 구현에 융통성을 허용

    - 디스크 블록 할당 방법
     ■ 연속 할당 (Contiguous Allocation)
      : 하나의 파일을 디스크 내의 연속된 블록에 순차적으로 할당하는 방법, 디스크 탐색 횟수를 최소화
      : 가용 공간을 선택하는 방법 - First-Fit, Best-Fit, Worst-Fit
      : 파일의 크기가 가변적으로 변화되는 경우 연속 할당을 사용할 경우 성능 저하 발생
      : 내부 단편화, 외부 단편화 발생
       

     ■ 불연속 할당 (Disc
    ontiguous Allocation)
      : 불연속적인 공간에 흩어진 디스크 블록에 나누어 저장

      □ 연결 할당(Linked Allocation)
       : 흩어진 블록들을 연결 리스트로 관리
       : 순차 접근인 경우 효과적이지만 직접 접근 시에는 매우 비효율적 -> 포인터 접근 시마다 디스크 읽기와 탐색 오버헤드 존재
       : FAT
       : 연속 할당의 문제점인 외부 단편화와 내부 단편화 문제를 해결

       

      □
     색인 할당(Indexed Allocation)
       : 디스크 블록에 대한 위치 정보를 가지고 있는 인덱스 블록 사용
        -> 블록이 할당될 때마다 해당 정보를 인덱스 블록에 기록
        -> 직접 접근 문제 해결. 인덱스 블록 유지 비용 발생
       : 파일이 커지면 하나의 인덱스 블록만으로 관리 불가능
        -> 여러 개의 인덱스 블록이 필요하면 이를 연결리스트로 관리
       : Linux는 inode 기법을 이용
       

  • 리눅스 파일 시스템 계층 분석

     

    - 리눅스 디스크 접근
      장치 파일은 /dev에 위치

      : 디스크가 설치되면 장치 파일을 이용하여 해당 디스크 접근

      -> /dev/sdb3 -> SCSI 타입의 두 번째 디스크의 세 번째 파티션

      -> /dev/sda1 -> SCSI 타입의 첫 번째 디스크의 첫 번째 파티션

     ■ 파티션 (partition)
      : 물리 장치의 논리적인 분리
      : 파일 시스템은 파티션마다 하나씩 만들어짐

      -> SCSI 타입의 하드 디스크 -> sda, sdb

      -> IDE 타입의 하드 디스크 -> hda, hdb


    - Mount
     : 파일 시스템을 트리 구조의 특정 노드에 mapping하는 역할
     : Root file system -> 시스템 부팅 시 root directory로 mount 됨
     : 각각의 파일 시스템은 마운트될 위치를 지정해 mount 명령으로 마운트시키거나 unmount 명령으로 언마운트(해체)할 수 있음
     ■ mount 과정
      ① 추가된 HDD가 정상적으로 인식되었는지 확인

       -> cat /var/log/dmesg | grep sdb
      ② 파티션 생성
       -> fdisk /dev/sdb
      ③ 파일 시스템 생성
       -> mkfs -t ext3 /dev/sdb1
      ④ 파일 시스템 마운트
       -> mkidr /home2  (Mount point 생성)
       -> mount -t ext3 /dev/sdb1 /home2 (새로 추가한 HDD를 /home2로 마운트)

    - 계층 개요
     


      ■ 가상 파일 시스템 (VFS : Virtual File System)
       : 표준 유닉스 파일 시스템이 제공하는 모든 시스템 콜을 처리하는 커널 소프트웨어 계층
       : 여러 종류의 파일 시스템에 대해 공통 인터페이스를 제공함


      ■ 디스크 파일 시스템 (Ext2,Ext3,Ext4 등)
       : 디스크나 입출력 장치에 정보를 저장하거나 입출력 및 검색 등을 하기 위한 계층

       : 장치에의 입출력이나 저장 형태 등, 장치에 의존적인 부분은 감추고 사용자에게 논리적이고 장치에 독립적인 쉬운 사용 인터페이스를 제공하기 위해 존재.


      ■ 페이지 캐시 (=Disk Cache)
       : 디스크의 정상적인 일부 데이터를 램이 보유하는 소프트웨어 메커니즘.
       : 
    Page라는 단위로 메모리에 일부 데이터를 저장.
       -> 한번 접근했던 데이터에 다시 접근할 때 디스크에 접근하지 않고 메모리에서 데이터를 읽음으로써 빠른 처리가 가능.

      ■ 일반 블록 계층 (Generic Block Layer)
       : 
    시스템 내 모든 블록 장치에 대한 요청을 다루는 커널 구성 요소
       : 
    일반 블록 계층은 각 하드웨어 블록 장치의 특징들을 숨겨서 블록 장치에 대한 추상적인 관점을 제공
       : 
    실제 입출력 연산을 위해 하위 구성 요소에 필요한 모든 정보를 준비하는 계층.

      ■ 
    I/O Scheduler Layer
       : 
    일반 블록 계층에서 넘어온 입출력 전송 요청을 커널 정책에 따라 정렬하는 계층
       : 
    I/O 스케줄러의 목적은 서로 가까운 I/O 요청을 그룹화 시켜서 디스크 탐색 오버헤드를 줄이는 것

      ■ (Block) Device Driver
       : I/O 스케줄러가 큐잉한 I/O 요청을 처리하는 계층. 요청을 해석하여 디스크 컨트롤러의 하드웨어 인터페이스에 적당한 명령을 보냄
       : 하드웨어(디스크) 인터럽가 발생했을 시 이를 처리할 수 있는 인터럽트 핸들러가 있음
     
      ∴ 각 계층 구조 동작

      



'Major > Linux' 카테고리의 다른 글

리눅스 - 가상 파일 시스템  (0) 2016.01.28
리눅스 - 파일 디스크립터  (7) 2016.01.28
리눅스 - System Call  (0) 2016.01.28
리눅스 - 기초  (0) 2016.01.28
내장형 시스템 - 하드웨어  (0) 2016.01.26
  • System Call?




    - System Call Number


    - System Call 처리 과정




  • System Call 구현
    : "두 개의 정수 값을 더하여 결과 값을 반환"하는 System Call 구현









'Major > Linux' 카테고리의 다른 글

리눅스 - 가상 파일 시스템  (0) 2016.01.28
리눅스 - 파일 디스크립터  (7) 2016.01.28
리눅스 - 파일 시스템  (0) 2016.01.28
리눅스 - 기초  (0) 2016.01.28
내장형 시스템 - 하드웨어  (0) 2016.01.26
  • 리눅스 커널 구조


    - 커널 구조에 따른 운영체제 구분
    ■ Monolithic 구조
      

     Micro-Kernel 구조
     

     

  • 리눅스 부팅 과정
      

  • Directory 구조
    : 리눅스 디렉토리 구조는 리눅스 커널의 소스 구조와는 다름
    - 리눅스 디렉토리 구조





    - 커널 소스 트리 구조



  • 리눅스 기본 명령어
    :파일 관련압축 관련프로세스/시스템 관련

    기능

    사용법 

    예시 

     파일 목록 출력

     ls [option]

     ls 
     ls -al

     현재 디렉토리에서 다른 디렉토리로 경로 변경

     cd 디렉토리 
     cd /디렉토리

     cd / ,cd .. 
     cd Downloads

     파일을 다른 파일명 또는 다른 디렉토리로 복사

     cp [option] source_file destination_file

     cp [option] source_file destination_directory

     cp -r Downloads backup

     파일을 다른 디렉토리로 이동하거나 다른 이름으로 변경

     mv [option] source_file destination_file

     mv [option] source_file destination_directory

     mv -i Downloads/helloworld.c backup

     파일 삭제

     rm [option] file

     rm [option] source_file destination_directory

     rm *
     rm -r backup, rm -i Downloads/helloworld.c

     새로운 디렉토리 생성

     mkdir [option] directory_name

     mkdir sub1 sub2 sub3

     디렉토리 삭제 rmdir [option] directory_name rmdir sub1
     현재 디렉토리명 표시 pwd [option]  
     텍스트 파일의 내용 출력 cat [option] file  cat etc/default/grub
     텍스트 파일의 내용을 화면에 한 페이지씩 출력 more [option] file  Space - 다음 페이지 출력, b - 이전 페이지로 이동
     q - 출력 중지 
     빈 파일을 생성하거나 파일의 수정 시간 변경 touch [option] file  touch test_file 
     리눅스 파일 권한 변경 chmod [options] mode[,mode] file1 [file2 ...]

     chmod 777 Downloads/helloworld.c
     chmod -R 707 /bin/su
     여러 파일이나 디렉토리를 묶거나 푼다.
     
     tar [option] file [directory]
        -c : 하나의 파일로 묶기
        -x : 묶인 파일 풀기
        -v : 파일을 묶거나 풀 때 진행 과정을 상세히 표시
        -t : 묶음 파일에 있는 내용 표시. 실제 묶음 파일을 풀지 않는다.
        -f : 묶음 파일명 .tar 명령어를 사용할 때 반드시 사용
        -z : gzip 관련하여 압축/복원을 동시에 수행 
     tar cvf test.tar test
     tar xvf test.tar (압축 기능은 없다)
     tar xvfz test.tar
     tar tf test.tar
     파일 압축/해제 유틸리티 – 압축 후 파일 확장자는 .gz가 붙는다 gzip [option] file
     gunzip [option] file
     gzip test.tar
     현재 진행 중인 프로세스에 대한 정보 출력 ps [option]   ps -efu
     현재 실행 중인 프로세서의 시스템 자원 사용 현황 표시 top [option] 
     실행 중인 프로세스를 종료 kill [option] process ID  kill -9 4647
     다른 사용자 계정으로 로그인 su - [login ID] [option]  su -
     su - swmem
     다른 계정의 권한이 요구될 때, 그 계정으로 직접 로그인하지 않고 해당 계정의 권한으로 작업을 수행  sudo command
     sudo -u user_name command
     sudo vi /etc/shadow
     시스템을 종료할 때 일반적으로 사용되는 명령
     시스템 리부팅
     shutdown [option] time [message]
     shutdown now
     reboot

  • Make Utility




'Major > Linux' 카테고리의 다른 글

리눅스 - 가상 파일 시스템  (0) 2016.01.28
리눅스 - 파일 디스크립터  (7) 2016.01.28
리눅스 - 파일 시스템  (0) 2016.01.28
리눅스 - System Call  (0) 2016.01.28
내장형 시스템 - 하드웨어  (0) 2016.01.26
  • Functional Diagram
  • 하드웨어 구조


    - 프로세서
     
     

      Embedded System에 적합한 프로세서 구조는? RISC
      : 로드-스토어(Load-Store) 아키텍처 프로세서는 보통 레지스터 안에 저장되어 있는 데이터를 이용하여 어떤 동작을 수행한다. 메모리에서 레지스터로 데이터를 읽어들일 때에는 로드 명령어를, 레지스터에서 메모리로 데이터를 저장할 때에는 스토어 명령어를 사용한다. 메모리를 액세스하기 위해서는 비용이 들기 때문에, 메모리를 여러 번 액세스하는 대신, 레지스터 안에 저장되어 있는 데이터를 여러 번 사용하는 식으로, 데이터 처리 동작과 메모리 액세스를 분리하는 것이 좋다.

      : CISC는 하드웨어의 복잡도에 초점을 맞추고 있고, RISC는 컴파일러의 복잡도에 초점을 맞추고 있다.

      
      : 이러한 설계 방식은 RISC 프로세서를 더욱 단순화시켜, 결론적으로 더 빠른 클럭으로 동작할 수 있게 되었다. 반면 전형적인 CISC 프로세서는 좀더 복잡하고, 좀더 낮은 클럭으로 동작한다. 하지만 지난 20년 동안, CISC가 RISC의 개념을 조금씩 적용함에 따라, RISC와 CISC 사이의 구분이 점점 모호해지고 있다.

      
     

    ■ 레지스터
      

      
     ■ 연산 장치 (ALU: Arithmetic & Logic Unit)
      
     
     ■ 제어 장치 (CU: Control Unit)
      

     ■ 버스 (Bus)

      

    - 메모리

      : 프로그램과 데이터를 저장하기 위한 공간
     
     


      



      ■ 주기억 장치
       : 프로그램이 실행되는 동안 프로그램과 데이터 저장
       : DRAM이 주로 사용

      ■ 보조 기억 장치
       : 주기억 장치보다 빈번하게 사용되지 않는 프로그램과 데이터 저장
       : HDD, SD, MMC

      ■ Cache
       : 주기억 장치의 접근 속도를 빠르게 하기 위해서 프로세서 주변에 배치된 소용량의 메모리
       : 프로세서가 읽고자 하는 명령이나 데이터를 최대한 빨리 프로세서에 전달하는데 목적
       : Data Inconsistency 발생 가능
       : SRAM이 주로 사용
       



      ■ Flash Memory


       



    - 입/출력 장치

      


     


      ■ Interrupt
      : Interrupt Latency? Interrupt가 발생했을 때부터 프로세서가 관련 ISR을 수행하기 시작할 때까지 걸린 시간
      : Interrupt Nesting? Interrupt는 비동기 이벤트이기 때문에 여러 개의 Interrupt가 동시에 발생할 수 있음, 모든 Interrupt에 대해 우선 순위를 정의해두고 높은 순위를 가지는 Interrupt를 낮은 순위의 Interrupt보다 우선적으로 처리

      
       


       


       



      ■ DMA (Direct Memory Access)

       : 같은 Bus를 사용할 경우 충돌 가능성

      



      ■ UART (A Universal Asynchronous Receiver/Transmitter)

      



      ■ GPIO (General Purpose I/O)
      



    - System Bus
      : Bus Handshaking
      : Wait Signals
      : Wait States
      ■ Architecture[폰-노이만(Von-Neumann) vs 하버드(Harvard Architecture)]
     

     



'Major > Linux' 카테고리의 다른 글

리눅스 - 가상 파일 시스템  (0) 2016.01.28
리눅스 - 파일 디스크립터  (7) 2016.01.28
리눅스 - 파일 시스템  (0) 2016.01.28
리눅스 - System Call  (0) 2016.01.28
리눅스 - 기초  (0) 2016.01.28
Bluetooth 4

BLE(Bluetooth Low Energy) 이해하기

 

주목!!! 저전력 블루투스인 BLE 모듈의 기초와 활용에 대한 오프라인 강의가 진행중입니다. BLE 모듈을 이용한 통신, 비컨 및 웨어러블 장치 만들기의 기본을 실습을 통해 배우실 수 있습니다. 오프라인 워크샵 페이지에서 확인하세요!!

 

BLE 블루투스 모듈을 이용해서 다양한 앱과 장치를 만들기 위해서는 먼저 BLE 의 구조와 컨셉, 스펙에 대해서 이해할 필요가 있습니다. 국내외의 자료 중 비교적 이해가 쉬운 자료들을 정리했습니다.

 

Bluetooth Low Energy(BLE)

BLE는 종종 Bluetooth Smart 로도 불리며 classic bluetooth의 경량화 버전을 목표로 블루투스 4.0의 일부로 발표되었습니다. Classic bluetooth와 겹치는 부분이 존재하지만 BLE는 완전히 다른 표준으로 블루투스 표준화 그룹인 Bluetooth SIG에 의해서 개발되기 전까지 Nokia의 사내 프로젝트(Wibree)로 시작하였습니다.

BLE 지원 플랫폼

iOS5+ (iOS7+ preferred)
Android 4.3+ (numerous bug fixes in 4.4+)
Apple OS X 10.6+
Windows 8 (XP, Vista and 7 only support Bluetooth 2.1)
GNU/Linux Vanilla BlueZ 4.93+

 

# GAP

GAP는 Generic Access Profile의 약자로 블루투스에서 게시(advertising)와 연결(connection)을 제어합니다. GAP은 특정 장치가 다른 장치들에게 어떻게 보여지도록 할 것인가와 어떻게 두 장치를 연결할 것인가를 결정합니다. GAP은 장치들이 맡을 수 있는 다양한 역할들에 대해 정의합니다. 그 중 가장 핵심이 되는 컨셉은 Central장치와 Peripheral 장치입니다.

Peripheral 장치는 주로 작고, 저전력으로 동작하고, 제한된 리소스를 가진 장치들로 보다 리소스가 풍부한 Central 장치에 연결되어 동작하도록 설계된 장치입니다. Heart Rate Monitor(심박측정기), BLE 근접센서 태그 등이 해당됩니다. 이하 글에서는 이해의 편의를 위해 Peripheral 장치를 [센서 장치]로 표현합니다.

Central 장치는 폰이나 태블릿과 같이 충분한 전원과 메모리 등의 리소스를 갖춘 장치입니다. 이하 글에서는 이해의 편의를 위해 [폰] 등으로 표현합니다.

 

# Advertising and Scan Response Data

GAP을 이용해서 게시(Advertising)를 할 때 Advertising Data Payload와 Scan Response Payload 를 포함할 수 있습니다. 
두 가지는 서로 구분되며 31바이트까지 데이터를 포함할 수 있습니다. 하지만 Advertising Data Payload 가 필수인데 반해 Scan Response Payload는 선택적입니다. Advertising Data Payload 는 Central 장치가 인식할 수 있도록 peripheral 장치(센서장치)에서 계속 송출되는 데이터입니다. Scan Response Payload 는 central 장치(폰)에서 장치 이름과 같이 추가적인 정보를 요구하기 위해 정의된 것으로 선택적으로 구현됩니다.

# Advertising Process

Advertising 과정이 어떻게 동작하는지는 아래 그림을 참고하세요.

microcontrollers_Advertising2

먼저 센서장치는 특정한 게시 주기(advertising interval)를 가지고, 이 주기마다 advertising packet을 전송합니다. 주기가 길어질수록 전력소모를 줄여주지만 Central 장치에서의 반응이 느려집니다. 만약 수신 장치(central 장치)에서 Scan Response Data 에 관심이 있다면 추가로 요청을 보낼 수 있고 peripheral 이 여기에 데이터와 함께 응답할 것입니다.

 

# Broadcasting, Beacon

Peripheral 장치는 31바이트 정도의 작은 데이터를 실어서 게시(advertising)를 함으로써 낮은 비용으로 주변의 central 장치에 자신의 존재를 알릴 수 있습니다. BLE에서는 이것을 Broadcasting 이라고 부릅니다. 그리고 오로지 advertising 역할만을 하는 Peripheral 장치가 바로 비컨(Beacon) 입니다. 애플의 iBeacon은 advertising packet 의 custom payload 내용을 특정한 형식으로 작성하도록 정의하고 있습니다.

일단 Central, Peripheral 두 장치가 연결되면 advertising 은 종료되어 외부 장치에서 scan 되지 않습니다. 이제 GATT 서비스와 특성(characteristic)을 사용하여 양방향으로 통신하게 됩니다.

 

# 주요 용어와 컨셉

자세한 설명이 이어지기 전에 곧 언급될 주요 용어들과 컨셉을 소개합니다.

GATT (Generic Attribute Profile) : GATT는 두 BLE 장치간에 Service, Characteristic 을 이용해서 데이터를 주고 받는 방법을 정의한 것입니다.
Attribute Protocol (ATT) : GATT는 ATT의 최상위 구현체이며 GATT/ATT로 참조되기도 합니다. 각각의 속성(Attribute)은 UUID를 가지며 128비트로 구성됩니다. ATT에 의해 부여된 속성은 특성(characteristic)과 서비스(Service)를 결정합니다.
Characteristic : 하나의 특성(characteristic)은 하나의 값과 n개의 디스크립터를 포함합니다.
Descriptor : 디스크립터는 특성의 값을 기술합니다.
Service : 하나의 서비스는 특성들의 집합입니다. 예를 들어 “Heart Rate Monitor”라고 불리는 서비스를 가지고 있다면 그 서비스는 “heart rate measurement”같은 특성을 포함합니다.

GATT-based profile의 리스트와 서비스는 bluetooth.org 에서 확인할 수 있습니다.

 

# 역할에 따른 구분 (복습)

Central / Peripheral

BLE 로 연결되기 위한 서로의 역할을 구분한 것입니다. central 은 scan, 게시검색(looking for advertisement)을 담당합니다. 그리고 peripheral 은 게시(advertisement)를 만듭니다. 예를들어 폰과 센서장치가 있다면 폰이 주변의 센서장치를 스캔하는 역할을 할 것이므로 central 이 됩니다. 반대로 센서장치가 peripheral 이 됩니다. 중요한 점은 peripheral 은 오로지 하나의 central 장치에만 연결될 수 있습니다. peripheral 이 central 에 연결되면 게시(advertising)를 중단하기 때문입니다. 따라서 다른 central 장치는 peripheral의 연결이 해제될 때 까지 찾을 수 없습니다.

GATT server(slave) / GATT client(master)

BLE 장치가 연결된 이후 어떻게 서로 통신하는지에 대해 정의합니다. 일반적으로 peripheral 장치(센서장치)가 GATT server 역할을 하며 ATT lookup data, service, characteristic 에 대한 정의를 가지고 있습니다. GATT client(폰, 태블릿 등)에서는 GATT server 로 데이터 요청을 보냅니다. 모든 동작(transaction)은 GATT client 에서 시작되어 GATT server로 부터 응답을 받게 됩니다.

두 장치가 연결될 때 peripheral(센서장치) 은 연결간격(connection interval)을 전달합니다. Central(폰)은 이 시간만큼 간격을 두고 새로운 데이터가 있는지 재연결을 시도할 수 있습니다. 하지만 이것은 필수 사항은 아닙니다.

 

# 전체 구조

BLE에서 사용하는 GATT 기반 동작구조는 프로파일(Profile), 서비스(Service), 특성(Characteristic) 에 기초합니다. 아래 이미지와 같은 수직 구조를 이룹니다.

microcontrollers_GattStructure

프로파일(Profile)

프로파일은 BLE peripheral(센서장치) 에 실제로 존재하는 것은 아닙니다. 이것은 Bluetooth SIG(블루투스 표준 개발그룹) 혹은 peripheral(센서장치) 디자이너에 의해서 만들어진, 미리 정의된 서비스의 묶음입니다. 

Heart Rate Profile (HRP)을 예로 들어보겠습니다. 이 프로파일은 Heart Rate Service(필수)와 Device Information Service(선택)를 결합한 것입니다. 이 두 서비스를 묶어서 Heart Rate Profile 이라고 정의했으며 논리적인 구분이라고 보시면 됩니다.

서비스(Service)

서비스는 데이터를 논리적인 단위로 나누는 역할을 하며 특성(characteristic)이라 불리는 데이터 단위를 하나 이상 포함하고 있습니다. 각 서비스는 UUID라 불리우는 16bit(for officially adopted BLE Services) 혹은 128bit(for custom services) 구분자를 가지고 있습니다. 표준 그룹에서 제정한 공식 서비스 리스트는 [링크]에서 확인할 수 있습니다.

이 중 Heart Rate Service 를 확인해보면 16-bit UUID – 0x180D 를 사용함을 알 수 있습니다. 그리고 이 서비스는 3개의 특성(Heart Rate Measurement, Body Sensor Location, Heart Rate Control Point) 을 가지고 있고 이 중 Heart Rate Measurement 만 필수임을 알 수 있습니다.

특성(Characteristic)

GATT 기반 동작구조에서 가장 하위 단위는 특성입니다. 특성은 단 하나의 데이터만을 포함합니다. 가속도 센서처럼 X, Y, Z 축 값이 한 쌍을 이루는 경우 일련된 값의 나열(배열)도 하나의 데이터로 간주합니다. 

서비스와 유사하게 특성도 16-bit 또는 128-bit UUID 를 가지고 있고 표준 특성 리스트를 제공합니다. 혹은 본인의 목적에 맞게 특성을 정의해도 됩니다. 

예를들어 Heart Rate Measurement 특성은 Heart Rate Service 의 필수 특성으로 UUID – 0x2A37 을 사용합니다. 이 특성은 데이터의 첫 8bit 중 첫 1bit 가 Heart Rate Measurement(HRM) 데이터 타입을 표시합니다. 데이터 타입이 0일 경우 이어지는 HRM 데이터는 UINT8 타입이고 1일 경우는 UINT16 입니다. 이와같이 BLE에서 특성은 peripheral(센서장치)와 데이터를 주고 받는데 핵심 역할을 합니다. 특성은 또한 Central(폰) 장치에서 peripheral(센서장치)로 데이터를 전송할 때도 사용됩니다.

 

간략하게 실제 폰에서의 동작과정을 요약하면 Central(폰) 장치는 아래와 같은 순서를 거쳐 데이터를 받아 처리합니다.

  • 먼저 폰은 주변의 BLE 장치를 스캔합니다. (GAP profile 이 정의하는 것이 이 과정. 주기적으로 advertising 이 되는 데이터가 어떻게 이루어져 있는지를 정의)
  • 폰은 스캔 결과에서 원하는 peripheral(센서장치)가 보이면 연결 (두 장치가 연결되면 센서장치는 advertising을 종료, Central(폰)은 GATT client 역할을 하고 GATT server에 연결하는 것)
  • 이제 이후부터는 안드로이드, iOS 프레임웍에서 GATT client를 운영하고 데이터 수신, 연결 상태의 변화 등 각종 이벤트가 발생 할 때 앱에 알려주게됩니다. (이 과정을 운용하기 위해 필요한 내용들이 GATT/ATT에 정의됨)
  • 먼저 연결된 장치의 GATT 정보와 Service  정보를 수신 (Service UUID 정보로 확인)
  • Characteristic 정보 수신 (UUID 값으로 실제 처리할 데이터를 추출)

 

 

 

참고 : android Bluetooth LE programming(BLE) , Adafruit(BLE Tutorial)

Bluetooth Core Specification
Bluetooth Developer Portal 
Officially Adopted BLE Profiles 
Officially Adopted BLE Services 
Officially Adopted BLE Characteristics 

Mobile Development Resources: Application Accelerator Kit (Sample BLE code for iOS, Android or Windows Phone)

출처 : http://www.hardcopyworld.com/ngine/aduino/index.php/archives/1132

'Others' 카테고리의 다른 글

OOP - S.O.L.I.D  (0) 2016.03.22
[현장] 전설의 개발자 제프 딘, 한국 개발자를 만나다  (0) 2016.03.20
코드 하이라이트 사용법  (0) 2015.10.26
  • 자바 서비스 프레임워크
    : 네이티브 서비스 프레임워크에서 제공하는 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

+ Recent posts