다음을 통해 공유


다중 코어 디바이스 및 Xamarin.Android

Android는 여러 컴퓨터 아키텍처에서 실행할 수 있습니다. 이 문서에서는 Xamarin.Android 애플리케이션에 대해 사용할 수 있는 여러 CPU 아키텍처에 설명합니다. 이 문서에서는 또한 여러 CPU 아키텍처를 지원하도록 Android 애플리케이션을 패키징하는 방법도 설명합니다. ABI(애플리케이션 이진 인터페이스)를 소개하고, Xamarin.Android 애플리케이션에서 사용할 ABI에 대한 지침을 제공합니다.

개요

Android는 여러 CPU 아키텍처를 지원하는 컴퓨터 코드가 포함된 단일 .apk 파일인 "패트 이진"의 생성을 지원합니다. 이는 애플리케이션 이진 인터페이스로 컴퓨터 코드의 각 조각을 연결하여 만들 수 있습니다. ABI는 특정 하드웨어 디바이스에서 실행될 컴퓨터 코드를 제어하는 데 사용됩니다. 예를 들어 x86 디바이스에서 실행되는 Android 애플리케이션의 경우 애플리케이션을 컴파일할 때 x86 ABI 지원을 포함해야 합니다.

특히 각 Android 애플리케이션은 EABI(포함된 애플리케이션 이진 인터페이스)를 하나 이상 지원하게 됩니다. EABI는 포함된 소프트웨어 프로그램과 관련된 규칙입니다. 일반적인 EABI는 다음과 같은 항목을 설명합니다.

  • CPU 명령 집합.

  • 런타임 시 메모리 저장 및 로드의 엔디언.

  • 개체 파일 및 프로그램 라이브러리의 이진 형식과 이러한 파일 및 라이브러리에서 허용 또는 지원되는 콘텐츠 형식

  • 애플리케이션 코드와 시스템 간에 데이터를 전달하는 데 사용되는 다양한 규칙(예: 함수가 호출될 때 레지스터 및/또는 스택이 사용되는 방법, 맞춤 제약 조건 등)

  • 열거형 형식, 구조체, 필드 및 배열에 대한 맞춤 및 크기 제약 조건

  • 런타임 시 머신 코드에 사용할 수 있는 함수 기호 목록(일반적으로 구체적으로 선택된 라이브러리 집합에서 가져옴)

armeabi 및 스레드 보안

애플리케이션 이진 인터페이스는 아래에서 자세히 살펴보겠지만, Xamarin.Android에서 사용하는 armeabi 런타임은 스레드로부터 안전하지 않다는 것을 유념하시기 바랍니다. armeabi 지원이 포함된 애플리케이션이 armeabi-v7a 디바이스에 배포될 경우 이상하고 말로 설명할 수 없는 예외가 많이 발생합니다.

Android 4.0.0, 4.0.1, 4.0.2 및 4.0.3의 버그로 인해 armeabi-v7a 디렉터리가 있고 디바이스가 armeabi-v7a 디바이스이더라도 네이티브 라이브러리는 armeabi 디렉터리에서 선택됩니다.

참고 항목

Xamarin.Android는 .so가 올바른 순서로 APK에 추가되도록 합니다. 이 버그는 Xamarin.Android의 사용자에게 문제가 되지 않습니다.

ABI 설명

Android에서 지원하는 각 ABI는 고유한 이름으로 식별됩니다.

armeabi

이는 하나 이상의 ARMv5TE 명령 집합을 지원하는 ARM 기반 CPU의 EABI 이름입니다. Android는 little-endian ARM GNU/Linux ABI를 따릅니다. 이 ABI는 하드웨어 기반 부동 소수점 계산을 지원하지 않습니다. 모든 FP 작업은 컴파일러의 libgcc.a 정적 라이브러리에서 제공하는 소프트웨어 도우미 함수에 의해 수행됩니다. armeabi는 SMP 디바이스를 지원하지 않습니다.

Important

Xamarin.Android의 armeabi 코드는 스레드로부터 안전하지 않으며 다중 CPU armeabi-v7a 디바이스에 사용해서는 안 됩니다(아래 설명 참조). 단일 코어 armeabi-v7a 디바이스에서 armeabi 코드를 사용하는 것은 안전합니다.

armeabi-v7a

이는 위에 설명된 armeabi EABI를 확장하는 또 다른 ARM 기반 CPU 명령 집합입니다. 이 armeabi-v7a EABI는 하드웨어 부동 소수점 연산 및 다중 CPU(SMP) 디바이스를 지원합니다. armeabi-v7a EABI를 사용하는 애플리케이션은 armeabi를 사용하는 애플리케이션보다 상당한 성능 개선 효과를 기대할 수 있습니다.

참고 항목

armeabi-v7a 기계어 코드는 ARMv5 디바이스에서 실행되지 않습니다.

arm64-v8a

이는 ARMv8 CPU 아키텍처에 기반을 둔 64비트 명령 집합입니다. 이 아키텍처는 Nexus 9에서 사용됩니다. Xamarin.Android 5.1이 이 아키텍처에 대한 지원을 도입했습니다. 자세한 내용은 64비트 런타임 지원을 확인하세요.

x86

이는 명령 집합을 지원하는 CPU의 ABI 이름이며, 일반적으로 x86 또는 IA-32라고 합니다. 이 ABI는 MMX, SSE, SSE2 및 SSE3 명령 집합을 포함한 Pentium Pro 명령 집합의 명령에 해당합니다. 다음과 같은 다른 선택적 IA-32 명령 집합은 포함하지 않습니다.

  • MOVBE 명령.
  • 보조 SSE3 확장(SSSE3).
  • SSE4 변형.

참고 항목

Google TV는 x86에서 실행되기는 하지만 Android의 NDK에서 지원되지 않습니다.

x86_64

이는 64비트 x86 명령 집합을 지원하는 CPU의 ABI입니다(x64 또는 AMD64라고도 함). Xamarin.Android 5.1이 이 아키텍처에 대한 지원을 도입했습니다. 자세한 내용은 64비트 런타임 지원을 확인하세요.

APK 파일 형식

Android 애플리케이션 패키지는 Android 애플리케이션에 필요한 모든 코드, 자산, 리소스 및 인증서를 저장하는 파일 형식입니다. .zip 파일 이지만 .apk 파일 이름 확장명을 사용합니다. 확장할 경우 Xamarin.Android에서 만든 .apk 콘텐츠를 아래 스크린샷에서 볼 수 있습니다.

.apk의 콘텐츠

.apk 파일의 콘텐츠에 대한 간단한 설명:

  • AndroidManifest.xml – 이진 XML 형식의 AndroidManifest.xml 파일입니다.

  • classes.dex – Android 런타임 VM에서 사용하는 파일 형식으로 dex 컴파일된 애플리케이션 코드가 포함됩니다.

  • resources.arsc – 이 파일에는 애플리케이션에 대해 미리 컴파일된 모든 리소스가 포함됩니다.

  • lib – 이 디렉터리에는 각 ABI에 대해 컴파일된 코드가 포함됩니다. 이전 섹션에서 설명된 각 ABI당 하나의 하위 폴더가 포함됩니다. 위의 스크린샷에서 해당 .apk에는 armeabi-v7ax86 모두를 위한 네이티브 라이브러리가 있습니다.

  • META-INF – 이 디렉터리(있는 경우)는 서명 정보, 패키지 및 확장 구성 데이터를 저장하는 데 사용됩니다.

  • res – 이 디렉터리에는 컴파일 resources.arsc 되지 않은 리소스가 있습니다.

참고 항목

libmonodroid.so 파일은 모든 Xamarin.Android 애플리케이션에 필요한 네이티브 라이브러리입니다.

Android 디바이스 ABI 지원

각 Android 디바이스는 최대 두 개의 ABI에서 네이티브 코드 실행을 지원합니다.

  • "기본" ABI – 시스템 이미지에 사용되는 컴퓨터 코드에 해당합니다.

  • "보조" ABI – 시스템 이미지에서도 지원되는 선택적 ABI입니다.

예를 들어 일반적인 ARMv5TE 디바이스는 armeabi의 주 ABI만 있지만, ARMv7 디바이스는 armeabi-v7a의 주 ABI와 armeabi의 보조 ABI를 지정합니다. 일반적인 x86 디바이스는 x86의 주 ABI만 지정합니다.

Android 네이티브 라이브러리 설치

패키지 설치 시 .apk 내 네이티브 라이브러리가 앱의 네이티브 라이브러리 디렉터리(일반적으로 /data/data/<package-name>/lib)로 추출되고, 그 이후에는 $APP/lib라 불립니다.

Android의 네이티브 라이브러리 설치 동작은 Android 버전에 따라 큰 차이가 있습니다.

네이티브 라이브러리 설치: Android 4.0 이전

Android 4.0 Ice Cream Sandwich 이전 버전은 .apk단일 ABI에서만 네이티브 라이브러리를 추출합니다. 이 버전의 Android 앱은 먼저 주 ABI의 모든 네이티브 라이브러리 추출을 시도하고, 이러한 라이브러리가 없을 경우 보조 ABI의 모든 네이티브 라이브러리를 추출합니다. "병합"은 수행되지 않습니다.

예를 들어 armeabi-v7a 디바이스에 애플리케이션이 설치된 상황을 생각해 보세요. armeabiarmeabi-v7a를 모두 지원하는 .apk,에는 다음과 같은 ABI lib 디렉터리와 파일이 포함되어 있습니다.

lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so

설치 후 네이티브 라이브러리 디렉터리에는 다음이 포함됩니다.

$APP/lib/libtwo.so # from the armeabi-v7a directory in the apk

즉, libone.so는 설치되지 않습니다. 그러면 문제가 발생합니다. 애플리케이션이 런타임에 로드할 libone.so가 없기 때문입니다. 이 동작은 예상하지 못한 것이지만 버그로 기록되었고 "예상대로 작동"으로 재분류되었습니다.

따라서 Android 4.0 이전 버전을 대상으로 하는 경우 애플리케이션이 지원할 ABI의 모든 네이티브 라이브러리를 제공해야 합니다. 즉, .apk는 다음을 포함해야 합니다.

lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libone.so
lib/armeabi-v7a/libtwo.so

네이티브 라이브러리 설치: Android 4.0 – Android 4.0.3

Android 4.0 Ice Cream Sandwich는 추출 논리를 변경합니다. 모든 네이티브 라이브러리를 열거하고, 파일의 기본 이름이 이미 추출되었는지, 다음 조건이 둘 다 충족되었는지 확인한 후 라이브러리를 추출합니다.

  • 아직 추출되지 않았습니다.

  • 네이티브 라이브러리의 ABI가 대상의 주 또는 보조 ABI와 일치합니다.

이러한 조건을 충족하면(즉, 다음과 같은 콘텐츠가 포함된 .apk가 있다면) "병합" 동작이 가능합니다.

lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so

그러면 설치 후 네이티브 라이브러리 디렉터리에 다음이 포함됩니다.

$APP/lib/libone.so
$APP/lib/libtwo.so

하지만 이 동작은 문제 24321: apk에 armeabi와 armeabi-v7a가 둘 다 포함된 경우 Galaxy Nexus 4.0.2가 armeabi 네이티브 코드를 사용함 문서에 설명된 대로 순서에 의존합니다.

네이티브 라이브러리는 "순서대로"(예를 들어 unzip에 나열된 대로) 처리되고, 처음 일치 항목이 추출됩니다. .apk에는 armeabiarmeabi-v7a 버전의 libtwo.so가 포함되어 있고 armeabi가 먼저 나열되므로 armeabi-v7a 버전이 아닌armeabi 버전이 추출됩니다.

$APP/lib/libone.so # armeabi
$APP/lib/libtwo.so # armeabi, NOT armeabi-v7a!

또한 Xamarin.Android는 (아래의 지원되는 ABI 선언 섹션에 설명된 대로) armeabiarmeabi-v7a ABI가 둘 다 지정되어 있더라도 다음에 다음과 같은 요소를 만듭니다. csproj:

<AndroidSupportedAbis>armeabi,armeabi-v7a</AndroidSupportedAbis>

따라서 armeabi-v7a libmonodroid.so가 있고 대상에 최적화되어 있더라도 .apk 내에서 armeabi libmonodroid.so가 먼저 발견되고, armeabi libmonodroid.so가 추출됩니다. 또한 armeabi는 SMP로부터 안전하지 않으므로 이로 인해 모호한 런타임 오류가 발생할 수도 있습니다.

네이티브 라이브러리 설치: Android 4.0.4 이상

Android 4.0.4는 추출 논리를 변경합니다. 모든 네이티브 라이브러리를 열거하고, 파일의 기본 이름을 읽은 후, 주 ABI 버전(있는 경우) 또는 보조 ABI(있는 경우)를 추출합니다. 따라서 다음과 같은 콘텐츠가 포함된 .apk가 있다면 "병합" 동작이 가능합니다.

lib/armeabi/libone.so
lib/armeabi/libtwo.so
lib/armeabi-v7a/libtwo.so

그러면 설치 후 네이티브 라이브러리 디렉터리에 다음이 포함됩니다.

$APP/lib/libone.so # from armeabi
$APP/lib/libtwo.so # from armeabi-v7a

Xamarin.Android 및 ABI

Xamarin.Android는 다음과 같은 64비트 아키텍처를 지원합니다.

  • arm64-v8a
  • x86_64

참고 항목

2018년 8월부터 새 앱은 API 레벨 26을 대상으로 해야 하고, 2019년 8월부터 앱은 32비트 버전 외에 ‘64비트 버전을 제공’해야 합니다.

Xamarin.Android는 다음 32비트 아키텍처를 지원합니다.

  • armeabi ^
  • armeabi-v7a
  • x86

참고 항목

^Xamarin.Android 9.2부터는 armeabi가 더이상 지원되지 않습니다.

Xamarin.Android는 현재 mips에 대한 지원을 제공하지 않습니다.

지원되는 ABI 선언

기본적으로 Xamarin.Android는 릴리스 빌드의 경우 armeabi-v7a로, 디버그 빌드의 경우 armeabi-v7ax86으로 지정됩니다. 다양한 ABI에 대한 지원은 Xamarin.Android 프로젝트의 프로젝트 옵션을 통해 설정할 수 있습니다. Visual Studio에서는 다음 스크린샷에서처럼 고급 탭에서 프로젝트 속성Android 옵션 페이지에서 이를 설정할 수 있습니다.

Android 옵션 고급 속성

Mac용 Visual Studio에서는 다음 스크린샷에서처럼 고급 탭에서 프로젝트 옵션Android 빌드 페이지에서 지원되는 아키텍처를 선택할 수 있습니다.

Android 빌드 지원 ABI

다음과 같이 추가적인 ABI 지원을 선언해야 하는 경우가 있습니다.

  • x86 디바이스에 애플리케이션 배포.

  • 스레드 보안을 위해 armeabi-v7a 디바이스에 애플리케이션 배포

요약

이 문서에서는 Xamarin.Android 애플리케이션을 실행할 수 있는 여러 CPU 아키텍처를 설명했습니다. 애플리케이션 이진 인터페이스와 Android에서 이를 사용하여 개별 CPU 아키텍처를 지원하는 방법을 소개했습니다. 그런 다음, Xamarin.Android 애플리케이션에서 ABI 지원을 지정하는 방법을 설명하고, armeabi 전용으로 고안된 armeabi-v7a 디바이스에서 Xamarin.Android 애플리케이션을 사용할 경우 발생하는 문제를 중점적으로 살펴보았습니다.