Post

애플리케이션 기본 항목. 앱의 기본 동작 원리

https://developer.android.com/guide/components/fundamentals.html

안드로이드의 메모리 관리 관점에서 프로세스 / 어플리케이션 관리

Android 앱은 일단 기기에 설치되고 나면 각자 자체적인 보안 샌드박스 안에 존재합니다.

  • Android 운영 체제는 멀티유저 Linux 시스템으로, 여기서 각 앱은 각기 다른 사용자와 같습니다.
  • 앱을 설치하면서 앱에 UID, GID(e.g., app_15)를 할당하고 이 권한으로 실행되기 때문에 각각의 앱이 서로 액세스할 수 없다.(이 ID는 시스템만 사용할 수 있으며 앱에서는 인식하지 못함)
  • 시스템은 앱 안의 모든 파일에 대해 권한을 설정하여 해당 앱에 할당된 UID/GID만 이에 액세스할 수 있도록 합니다.
  • 각 프로세스가 자체적인 Virtual Machine을 가지고 있기 때문에, 어떤 한 앱의 코드는 다른 앱과는 격리된 상태로 실행됩니다.
  • 기본적으로 모든 앱이 앱 자체의 Linux 프로세스에서 실행됩니다. Android는 앱의 구성 요소 중 어느 것이라도 실행해야 하는 경우 프로세스를 시작하고, 이것이 더 이상 필요 없어지거나 시스템이 다른 앱을 위해 메모리를 회복해야 하는 경우 해당 프로세스를 종료합니다.

앱이 데이터를 공유하거나, 시스템 서비스에 액세스 하기 위해서는 보통 다음 두 가지 방법을 사용해야 한다.

  • 두 개의 앱이 같은 UID를 사용하도록 설정. 이 경우 두 앱은 같은 파일에 액세스 할 수 있다. 같은 UID를 가진 앱이 같은 프로세스에서 실행되도록 설정하고 같은 VM을 공유하도록 할 수도 있다. (단, 이 앱들이 모두 같은 인증서로 서명해야 함.)
  • 기본적으로 샌드박스라 앱 간의 데이터 교환은 Content Provider라는 인터페이스를 통해서만 가능하며, 연락처, SMS, SD카드 등등의 기기 데이터에 액세스할 권한은 유저가 명시적으로 동의해야 한다.

앱 구성 요소 ( 컴포넌트 )

다음 네 가지 유형이 있다.

  • Activities. - 사용자 인터페이스가 있는 단일 화면. 각자 서로와는 독립적인 형태.
  • Services. - 백그라운드에서 실행
  • Content providers. - 데이터 입출력
  • Broadcast receivers. - 주로 상태 표시줄 알림 Android 시스템 디자인의 독특한 점으로 어떤 앱이든 다른 앱의 구성 요소를 시작할 수 있다는 점을 들 수 있습니다. 예를 들어 사용자가 기기 카메라로 사진을 캡처하기를 바라는 경우, 그런 작업을 수행하는 또 다른 앱이 있을 가능성이 높습니다. 그러면 사진을 캡처하는 액티비티를 직접 개발하는 대신 그저 사진을 캡처하는 카메라 앱 안의 해당 액티비티를 시작하기만 하면 됩니다

시스템이 구성 요소를 시작하는 경우, 그 앱에 대한 프로세스를 시작하고(이미 실행 중이지 않은 경우), 해당 구성 요소에 필요한 클래스를 인스턴스화합니다. 예를 들어 여러분의 앱이 카메라 앱 내에서 사진을 캡처하는 액티비티를 시작한다고 하면, 해당 액티비티는 여러분 앱의 프로세스가 아니라 카메라 앱에 속한 프로세스에서 실행됩니다. 따라서 대부분의 다른 시스템에서와는 달리 Android 앱에는 단일한 진입 지점이 없습니다(예를 들어 main() 함수가 없음).

이러한 성질 때문에

  1. 각각의 액티비티가 독립적으로 바로 실행될 수 있다.
  2. 카메라 액티비티는 별도의 카메라 프로세스로 실행되어야 하는데, 각각의 앱이 다른 앱을 직접 활성화 할 수 는 없어 내 앱이 카메라 프로세스를 실행할 수는 없다. 따라서 시스템에 구성 요소를 시작해달라고 요청해야 하는데, 이 것이 Intent다.

컴포넌트 활성화 (Intent)

네 가지 구성 요소 중 세 가지—Activity, Service, Broadcast receiver—는 일명 Intent라고 하는 비동기식 메시지를 이용해 활성화할 수 있다. 인텐트를 이용해 다른 컴포넌트(앱 구성 요소)에 액션을 요청하게 되며 이 때 내 앱에 속해 있는 컴포넌트 뿐만 아니라 다른 앱에 속해있는 컴포넌트에도 요청할 수 있다. 액티비티를 시작하려면 startActivity()Intent를 전달하고, 서비스를 시작하려면 startService()에, 브로드캐스트를 시작하려면 sendBroadcast()에 전달하는 식으로 동작한다. 나머지 컴포넌트와 달리 Content provider에는 직접 Intent를 날리는게 아니라, ContentResolver를 사용해 한 계층 거쳐서 활성화한다. 이렇게 중간에 Resolver를 두고 Resolver와만 일처리를 하기 때문에 보안이 강화된다는 장점이 있다.

manifest 파일

Android 시스템은 각 앱의 컴포넌트에 대한 정보를 얻기 위해 각 앱의 AndroidManifest.xml 파일을 확인한다. 이 파일은 각 앱의 루트 디렉토리에 존재해야 하며, 다음과 같은 정보를 가지고 있다.

  • 앱이 가지고 있는 모든 컴포넌트에 대한 정보 ( 컴포넌트 선언 )
  • 앱이 요구하는 모든 사용자 권한 ( e.g., 인터넷 액세스, 연락처 액세스 )
  • 앱에서 사용하거나 필요로하는 하드웨어 및 소프트웨어 기능 선언( e.g., 카메라, 블루투스 )
  • 앱이 사용하는 API를 기반으로, 앱에서 요구하는 최소 API 레벨 선언.
  • 앱 동작을 위해 링크가 필요한 API 라이브러리 선언. 단, Android framework API는 제외. ( e.g., Google Maps library )
컴포넌트 선언

이런 식으로 생겼다.

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:icon="@drawable/app\_icon.png" ... >
<activity android:name="com.example.project.ExampleActivity"
android:label="@string/example\_label" ... >
</activity>
...
</application>
</manifest>

각 컴포넌트에 따른 XML 요소는 다음과 같다. manifest에 이렇게 넣어줘야 시스템이 알 수 있어 실행될 수 있다.

  • <activity> 요소
  • <service> 요소
  • <receiver> 요소 - 이건 여기서 선언하지 않고 동적으로 생성한 다음 시스템에 등록해도 동작한다.
  • <provider> 요소
컴포넌트 기능 선언

인텐트의 진정한 힘은 암시적 인텐트 의 개념에서 발휘됩니다. 암시적 인텐트는 단순하게 수행할 작업의 유형(및 선택 사항으로 해당 작업을 수행하고자 하는 데이터)을 설명할 뿐이며 시스템에 기기에서 작업을 수행할 수 있는 구성 요소를 찾아 시작하도록 해줍니다. 인텐트가 설명한 작업을 수행할 수 있는 구성 요소가 여러 개인 경우, 어느 것을 사용할지는 사용자가 선택합니다.

예를 들어 사진을 열 때 기본 갤러리를 사용할지, 구글 포토를 사용할지 등.

인텐트에 응답할 수 있는 구성 요소를 시스템이 식별하는 방법은 기기상의 다른 앱의 매니페스트 파일에 제공된 인텐트 필터 를 수신된 인텐트와 비교하는 것입니다.

인텐트 요청이 있을 때 마다 AndroidManifest.xml을 뒤진다.

앱의 매니페스트에서 액티비티를 선언하는 경우, 선택 사항으로 해당 액티비티의 기능을 선언하는 인텐트 필터를 포함시켜서 다른 앱으로부터의 인텐트에 응답 할 수 있도록 할 수 있습니다. 구성 요소에 대한 인텐트 필터를 선언하려면 <intent-filter> 요소를 해당 컴포넌트 선언의 하위 요소로 추가하면 됩니다. 예를 들어, ACTION_SEND 인텐트에 응답하는 인텐트 필터는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
<manifest ... >
...
<application ... >
<activity android:name="com.example.project.ComposeEmailActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<data android:type="\*/\*" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
앱 요구사항 선언

예를 들어, 앱에 카메라가 필요하고 Android 2.1(API 레벨 7)에 도입된 API를 사용하는 경우 이와 같은 내용을 매니페스트 파일에 요구사항으로 선언하려면 다음과 같이 합니다.

1
2
3
4
5
6
<manifest ... >
<uses-feature android:name="android.hardware.camera.any"
android:required="true" />
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
...
</manifest>

이제 카메라가 없고 Android 버전이 2.1 이하인 기기는 Google Play에서 앱을 설치할 수 없습니다.

그러나, 앱이 카메라를 사용하기는 하지만 꼭 필요한 것은 아니라고 선언할 수도 있습니다. 이 경우에는, 앱이 required 특성을 "false"에 설정하고 런타임에 확인하여 해당 기기에 카메라가 있는지, 경우에 따라 모든 카메라 기능을 비활성화할 수 있는지 알아봅니다.

앱 리소스

Android 프로젝트에 포함시키는 리소스마다 SDK 빌드 도구가 자동으로 고유한 정수 ID를 정의하므로, 이를 사용하여 앱 코드에서의 리소스나 XML로 정의된 다른 리소스에서 참조할 수 있습니다. 예를 들어 앱에 logo.png라는 이름의 이미지 파일이 들어 있다고 하면(res/drawable/ 디렉터리에 저장됨), SDK 도구가 R.drawable.logo라는 리소스 ID를 생성합니다. 이것을 사용하여 이미지를 참조하고 사용자 인터페이스에 삽입할 수 있습니다.

This post is licensed under CC BY 4.0 by the author.