엄범


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 앱에는 단일한 진입 지점이 없습니다(예를 들어 ``c main()`` 함수가 없음).

이러한 성질 때문에

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


컴포넌트 활성화 (Intent)

네 가지 구성 요소 중 세 가지—Activity, Service, Broadcast receiver—는 일명 ``kt Intent``라고 하는 비동기식 메시지를 이용해 활성화할 수 있다. 인텐트를 이용해 다른 컴포넌트(앱 구성 요소)에 액션을 요청하게 되며 이 때 내 앱에 속해 있는 컴포넌트 뿐만 아니라 다른 앱에 속해있는 컴포넌트에도 요청할 수 있다.

액티비티를 시작하려면 ``kt startActivity()``에 `` Intent``를 전달하고,
서비스를 시작하려면 ``kt startService()``에,
브로드캐스트를 시작하려면 ``kt 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 )


컴포넌트 선언

이런 식으로 생겼다.
```xml
<?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에 이렇게 넣어줘야 시스템이 알 수 있어 실행될 수 있다.
  • ``xml <activity>`` 요소
  • ``xml <service>`` 요소
  • ``xml <receiver>`` 요소 - 이건 여기서 선언하지 않고 동적으로 생성한 다음 시스템에 등록해도 동작한다.
  • ``xml <provider>`` 요소

컴포넌트 기능 선언

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

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


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

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


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

예를 들어, ``kt ACTION_SEND`` 인텐트에 응답하는 인텐트 필터는 다음과 같다.

```xml

<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를 사용하는 경우 이와 같은 내용을 매니페스트 파일에 요구사항으로 선언하려면 다음과 같이 합니다.

```xml

<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 특성을 ``xml "false"``에 설정하고 런타임에 확인하여 해당 기기에 카메라가 있는지, 경우에 따라 모든 카메라 기능을 비활성화할 수 있는지 알아봅니다.


앱 리소스

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