안드로이드와 apk

IMKYU·2024년 11월 24일

안드로이드는 리눅스 커널 기반으로 구글에서 제작하고 있는 오픈소스 모바일 운영체제이다. 그리고 구글은 안드로이드의 소스코드를 공개하고 있다.(칩셋 업체의 Board Support Pachage 부분은 미공개) 개방성과 범용성이 뛰어나 여러 플랫폼으로 이식 및 개발이 가능하다.

AOSP vs Android

  • AOSP
    • 구글이 주도하는 오픈 소스 프로젝트이다.
    • 제조사나 개발자들이 자신들의 장치에 맞게 안드로이드를 수정, 개발 할 수 있다.
    • AOSP는 안드로이드의 골격을 구성하는 오픈소스 프로젝트이다.
    • 안드로이드 os의 핵심 코드 베이스를 의미하고 개발자들이 이 코드를 기반으로 다양한 안드로이드 기반 시스템을 개발할 수 있게 해준다.
    • 핵심 기능 외는 구글의 서비스와 애플리케이션은 포함되지 않음.(GApps)
  • Android
    • 구글이 개발하고 유지하는 모바일 운영 체제이다.
    • 안드로이드는 AOSP를 기반으로 한다.
    • 구글 서비스와 애플리케이션이 포함되어있다.
    • 안드로이드는 제조사가 직접 수정하지 않고도 사용할 수 있는 완성된 운영 체제를 제공한다.
    • AOSP보다 더 넓은 범위의 기능을 사용자에게 제공한다.

가장 큰 차이점은 GAPPS의 유무이다.

AOSP를 구현하는 기기는 두가지 호환성 수준, AOSP 호환성과 안드로이드 호환성이 있다.

AOSP 호환 기기는 호환성 정의 문서(CDD)의 요구 사항 목록을 준수해야한다. 안드로이드 호환 기기는 CDD

및 공급업체 소프웨어 요구사항(VSR)의 요구사항 목록을 준수하고 공급업체 테스트 모음(VTS)호환성 테스트 모음과 같은 테스트를 실행해야한다.

자세한 내용은 안드로이드 호환성 프로그램을 참고한다.

AOSP 아키텍처

AOSP용 소프트웨어 스택에는 다음과 같은 레이어가 포함됩니다.

안드로이드 앱(Android Apps)

안드로이드 API만 사용하여 만든 앱이다.

권한이 있는 앱(Privileged Apps)

안드로이드와 시스템 API를 조합하여 만든 앱이다. 이 앱은 기기에 권한이 있는 앱으로 사전 설치되어 있어야 한다.

기기 제조업체 앱(Device Manufacturer Apps)

안드로이드 API, 시스템 API, 안드로이드 프레임워크 구현에 관한 직접 액세스를 조합하여 만든 앱이다. 기기 제조 업체가 안드로이드 프레임워크 내에서 불안정한 API에 직접 액세스할 수도 있으므로 이러한 앱은 기기 에 사전 설치되어 있어야 하고 기기의 시스템 소프트웨어가 업데이트 될 때만 업데이트를 할 수 있다.

시스템 API(System API)

시스템 API는 파트너 및 OEM이 번들 애플리케이션에 포함하기 위해서만 사용할 수 있는 안드로이드 API를 나타낸다. 이러한 API는 소스코드에서 @SystemApi로 표시한다.

안드로이드 API(Android API)

안드로이드 API는 서드 파티 안드로이드 앱 개발자에게 공개적으로 제공되는 API이다. 자세한 내용은 안드로이드 API 레퍼런스 문서를 참고한다.

안드로이드 프레임워크(Android Framework)

앱이 기반하는 자바 클래스, 인터페이스, 기타 사전 컴파일된 코드 그룹이다. 프레임워크의 일부는 Android API를 사용하여 공개적으로 액세스할 수 있다. 그 외의 프레임워크 부분은 시스템 API 사용을 통해 OEM에만 제공한다. 안드로이드 프레임워크 코드는 앱의 프로세스 내에서 실행 된다.

  • Activity Manager : 애플리케이션 안의 액티비티들을 관리
  • Content Providers : 애플리케이션 간의 데이터 공유 관리
  • Telephony Manager : 음성통화 관리
  • Location Manager : GPS 또는 기지국 신호를 통해 위치 정보 관리
  • Resource Manager : 앱에서 사용하는 리소스들 관리
  • View System : UI에 쓰이는 안드로이드 뷰들을 관리
  • Notification Manager : 알림 관리

시스템 서비스(System Services)

시스템 서비스는 system_server, SurfaceFlinger, MediaService와 같은 집중된 모듈식 구성 요소이다. 안드로이드 프레임워크 API로 의해 노출된 기능은 시스템 서비스와 통신하여 기본 하드웨어에 액세스한다.

안드로이드 런타임(ART/Android Runtime)

AOSP에서 제공하는 자바 런타임 환경이다. ART는 앱의 바이트 코들르 기기의 런타임 환경에서 실행되는 프로세스별 명령을 변환한다.

  • JVM과 안드로이드

    • 안드로이드는 자바를 채택한 모바일 운영체제이다.
    • 자바를 사용한 바이트코드를 사용하기 위해서 JVM를 거쳐야 한다.
    • 하지만 JVM은 제한되지 않은 전원과 저장 공간을 가지고 있다는 것을 전제로 설계되었다.
    • 라이선스 문제가 있다.
    • 자세한 내용은 이 곳을 참고한다.
  • 달빅 가상 머신(Dalvik virtual machine)

    • 달빅은 안드로이드가 JVM 대신 사용한 가상 머신이다.
    • 달빅은 32비트만 지원한다.
    • 안드로이드 4.4 킷캣 이전 버전까지 달빅이 사용되었다.
    • 달빅은 안드로이드 앱을 실행하기 위해 자바 바이트 코드를 달빅 바이트 코드롤 변환되어 사용했다.
    • 자바 바이트 코드가 스택 기반으로 동작하지만 달빅 바이트 코드는 레지스터 기반으로 동작한다. 이러한 방식은 자바 바이트 코드보다 훨씬 효율적이고 공간을 적게 사용한다.
    • 달빅은 적은 메모리 환경에 최적화 되었다.
    • 전체 앱을 실행하기 전에 기계어로 컴파일 하는 대신 Just In Time 컴파일, JIT 전략을 사용했다. 달빅은 필요한 코드만 컴파일하고 런타임에 수행하기 때문에 많은 RAM을 절약할 수 있다.
    • 구글에서 오픈소스로 제공될 안드로이드에서 JVM을 사용할 경우 라이센스 관련한 문제가 발생할 수 있기 때문에 JVM을 사용하는 것은 적합하지 않았다.
      • 현 Oracle의 JVM의 특허를 피해 가기 위한 편법. 실제로도 이것 때문에 2010년부터 2021년까지 Oracle과 법정 싸움을 다툰 적이 있다.
    • 달빅은 자주 사용하는 코드(Hot Code)는 컴파일러를 사용하고 사용 빈도수가 적은 코드(Cold Code)는 인터프리터를 사용한다.
    • 달빅은 모든 것이 런타임에 발생하기 때문에 화면 전환이 많을수록 성능이 저하된다.
    • 달빅은 실행 직전에 실행 부분을 전체 RAM에 올려놔야 하기 때문에 다른 OS보다 RAM을 많이 사용한다.
    • 달빅은 초기 RAM 사용량은 낮지만 실행시간이 길어질수록 RAM 사용량이 점진적으로 증가한다.
    • 이러한 성능저하를 막기위해 자주 사용되는 컴파일된 코드 일부를 캐싱하여 다시 컴파일하지 않도록 했다.
  • 안드로이드 런타임(ART/Android Runtime)

    • 달빅의 JIT의 단점을 개선하기 위한 가상머신이다.

    • ART는 32비트 64비트 둘 다 지원한다.

    • ART는 JIT 컴파일와 인터프리터 대신 AOT/Ahead of Time 컴파일 전략을 사용한다.

    • ART는 런타임시 코드를 해석하는 대신 앱을 실행하기 전에 코드를 컴파일하여 스토리지에 저장하고 앱이 실행 중일 때 스토리지에서 램으로 불러온다.

    • 이 접근 방식은 기존 방식보다 런타임 성능 20배 더 빠르다.

    • ART는 dex 바이트 코드가 매번 해석되지 않기 때문에 달빅에 비해 배터리 성능을 크게 향상시켰다.

    • 달빅은 응용 프로그램의 시작 시간이 더 느리고 ART는 AOT 덕분에 네이티브 코드를 실행할 수 있어서 매우 빠르다.

    • ART는 달빅보다 가비지 컬렉션이 더 뛰어나다.

    • ART는 초기 RAM 사용량이 높다.

    • APK 설치하려면 해당 앱을 기계어로 변환하기 때문에 앱 설치 시간이 오래걸리고 설치 공간이 달빅에 비해 1.5~2배가 필요하다.

    • 시스템 업데이트가 되었다면 기존에 설치된 모든 앱을 다시 최적화/컴파일한다.
      - 안드로이드 시스템 라이브러리나 프레임워크가 변경되면 기존에 설치된 앱이 더 이상 호환되지 않을 수 있다.

  • 현재의 ART

    • 기존 ART의 문제를 해결하기 위해 구글에서는 AOT와 인터프리터, JIT를 함께 사용하는 방식으로 해결했다.(안드로이드 7.0 누가부터 추가됨)
    • 실행 순서는 다음과 같다.
      1. 처음 앱을 실행할 때는 .oat 바이너리도 없다. ART는 인터프리터를 사용하여 코드를 실행한다.
      2. HOT Code가 감지되면 JIT 컴파일러가 컴파일한다.
      3. JIT 컴파일된 코드와 컴파일 프로파일을 캐시에 저장한다. 이후 실행은 이 캐시를 사용한다.
      4. 기기가 휴면 상태(화면이 꺼지거나 충전 중)이면, HOT Code가 AOT 컴파일러와 컴파일 프로파일을 사용하여 다시 컴파일한다.
      5. 앱이 다시 실행하면, .oat 바이너리 코드가 더 나은 성능으로 실행한다. 만약 .oat 바이너리가 없다면 1로 다시 돌아간다.
    • 추가된 최적화 방법이 있는데 바로 유사한 장치 간에 컴파일 프로파일을 공유하는 것이다.
    • 프로파일은 ART 컴파일러가 설치 중에 중요한 경로를 기계어 코드로 사전 컴파일하는 데 사용하는 APK에 포함된 클래스 및 메서드 목록이다. 프로파일은 앱이 실행되는 동안 어떤 메서드와 클래스가 가장 자주 사용되는지, 그리고 어떤 종류의 코드가 최적화가 필요한지에 대한 정보를 포함합니다. 프로파일은 앱이 시작을 최적화하고, 버벅거림을 줄이고, 최종 사용자가 경험하는 성능을 개선할 수 있도록 해 주는 일종의 프로필 기반 최적화(PGO/Profile-Guided Optimization)이다.
    • 기기가 휴면 상태이고 와이파이 네트워트에 연결된 경우 구글 플레이 서비스를 통해 컴파일 프로파일 파일을 공유한다. 나중에 같은 기기를 가진 다른 사용자가 플레이스토에서 앱을 다운받으면 해당 기기는 이러한 프로파일을 받아드려 AOT가 가이드 컴파일을 수행하게되고 결과적으로 사용자들은 처음 사용부터 최적화 된 앱을 받게 된다.

네이티브 데몬 및 라이브러리(System Services and Daemons)

이 레이어의 네이티브 데몬에는 inithealthdlogdstoraged가 포함된다. 이러한 데몬은 커널 또는 다른 인터페이스와 직접 상호작용하며 사용자 공간을 기반으로 하는 HAL 구현에 의존하지 않는다.

이 레이어의 네이티브 라이브러리에는 libclibloglibutilslibbinderlibselinux가 있다. 이러한 네이티브 라이브러리는 커널 또는 다른 인터페이스와 직접 상호작용하며 사용자 공간을 기반으로 하는 HAL 구현에 의존하지 않는다.

  • 더 쉬운 설명 일반적으로 사용하는 라이브러리 기능들이 모인 곳인데 좀 더 저수준에서 동작하는 라이브러리다. 왜냐면 안드로이드는 메인 메모리가 거의 없고 CPU 전원이 낮은 기기에서 실행돼야 하므로 CPU, GPU 집약적 작업을 위한 라이브러리들은 기기에 최적화된 네이티브 코드로 컴파일되야 한다. 오디오와 비디오 코덱을 포함하고 음악, 영상, 사진 등의 미디어 처리를 담당하는 Media Framework, 화면의 창 구성을 처리하는 Surface Manager를 비롯한 여러 매니저와 프레임워크가 있고 아래의 오픈소스 라이브러리들이 담겨져 있다.
    • SGL : 2D 그래픽 담당
    • OpenGL ES : 2D/3D 그래픽 담당. AR 앱을 만들 때 이 이름의 클래스를 다룬 적이 있다.
    • Free Type : 폰트 렌더링
    • WebKit : 웹 브라우저 엔진
    • libc : 시스템 C 라이브러리
    • SQLite : 모바일을 위한 경량화된 로컬 DB
    • Open SSL(Secure Socket Layer 프로토콜)

하드웨어 추상화 계층(HAL/Hardware Abstraction Layer)

HAL은 하드웨어 공급업체에서 구현할 표준 인터페이스가 포함된 추상화 계층이다. HAL을 사용하면 안드로이드가 하위 수준의 드라이버 구현을 고려하지 않아도 된다. HAL을 사용하면 상위 수준 시스템에 영향을 주거나 수정하지 않고도 기능을 구현할 수 있다. 자세한 내용은 HAL 개요를 참고한다.

  • 더 쉬운 설명 HAL은 하드웨어와 소프트웨어의 차이를 추상화하여, 하드웨어에 대한 접근을 단순화한다. 예를 들어, 카메라, 화면, 오디오 등 다양한 하드웨어 장치에 대한 접근을 HAL을 통해 제공한다. HAL은 안드로이드 프레임워크 및 애플리케이션이 하드웨어에 직접 접근하지 않고도 하드웨어를 사용할 수 있도록 한다.

커널(Kernel)

커널은 모든 운영체제의 중심이며 기기의 기본 하드웨어와 통신한다. 하드웨어적인 설정을 리눅스 커널에서 관리한다. 가능한 경우 AOSP 커널은 하드웨어 제약이 없는 모듈과 공급업체별 모듈로 분할된다. 정의를 비롯하여 AOSP 커널 구성요소에 관한 자세한 내용은 커널 개요를 참고한다.

  • 커널이 담당하는 일
    • 메모리 관리
    • 보안 설정
    • 전원 관리
    • 다른 하드웨어 장치 드라이버 관리
    • 네트워크 시스템 관리

앱빌드

Gradle

안드로이드 스튜디오의 빌드 시스템은 Gradle이고 그 플러그인 Android Gradle Plugin(AGP)는 안드로이드 앱을 빌드하는 과정을 내부적으로 처리해준다.

  • Gradle은 CI/CD를 위해 아래 작업들을 자동화 시켜 주는 Groovy 기반의 오픈소스 빌드 도구
    • Compile - Java 파일의 소스 코드를 컴퓨터가 이해할 수 있도록 바이트 코드로 변환
    • Test - 유닛 테스트, UI 테스트
    • Packaging - 스프링 코드를 패키징 해 .jar 파일이나 .war 파일로 생성
    • Deploy & Run - 서버 실행
  • 빌드 도구
    • 소프트웨어 개발에 있어서 소스 코드를 실행 가능한 어플리케이션으로 만들어주는 도구
    • 빌드 과정을 자동화하여 관리하는 기능을 하기 때문에 빌드 관리도구 또는 빌드 자동화 도구라고 한다.

빌드 프로세스

빌드는 결국 프로젝트를 APK와 AAB로 변환하는 과정이다.

  • APK와 AAB의 차이점

    APK(Android Package)는 이미 완성된 안드로이드 앱 파일이고, AAB(Android App Bundle)는 APK를 완성해주는 요소를 담은 패키지다.

    기존처럼 모든 기기에 대응할 수 있는 하나의 APK를 전달하는 것이 아니라, 개발자가 스토에 AAB 패키지를 올려놓으면, 스토어가 사용자 기기에 어떤 내요잉 필요한지 확인하고 그에 맞춘 APK 파일을 만들어 배포한다.

    현재 구글 플레이스토에서 AAB가 의무화 되었다.

Application Reources

애플리케이션의 리소스 파일들은 AAPT(Android Asset Packging Tool)에 의해 해당 리소스 파일을 참조할 수 있는 ID가 부여되어 R.java 클래스 안에 담기게 된다.

AIDL(Android Interface Definition Language)

AIDL은 안드로이드 플랫폼에서 서로 다른 프로세스 간에 통신하기 위해 사용되는 인터페이스 정의 언어이다.

AIDL을 사용하여 서로 다른 앱 또는 프로세스 사이에서 데이터와 메소드를 주고받을 수 있다.

AIDL 언어는 자바 언어에 기반한다.

Application Source Code

개발자가 작성한 자바, 코틀리의 소스코드, R.java, Java Interfaces는 자바 컴파일러, 코틀린 컴파일러를 통해 자바 바이트코드인 .class파일로 변환된다.

Dex로 변환

변횐된 .class 파일과 서드 파티 라이브러리 파일을 .dex(Dalvik Executable)파일로 변환한다.

  • 서드 파티 라이브러리(3rd Party Libraries) 소프트웨어 개발에서 사용되는 외부 제공자가 제작한 코드의 모음이다. 이 라이브러리는 개발자가 직접 작성하는 코드 대신 사용하여 소프트웨어 개발을 더 빠르고 효율적으로 진행할 수 있도록 한다.
    • JAR(Java Archive) 자바 플랫폼에서 사용되는 일반적인 라이브러리 파일 형식이다. 안드로이드에서도 자바 코드를 포함한 라이브러리로 사용할 수 있다.
    • AAR(Android Archive) 안드로이드 플랫폼에서 사용되는 라이브러리 파일 형식이다. AAR 파일은 JAR파일을 확장하여 안드로이드 리소스까지 포함하고 있다.

.dex 파일로 변환은 안드로이드 앱의 최적화 및 보안 강화를 위한 중요한 단계이다.

Code shrinking(코드 수축) : 소스코드나 라이브러리의 코드에서 실제로 사용되지 않은 클래스들, 필드들, 메소드들, 속성드를 제거한다.

Resource shrinking(자원 수축) : 사용되지 않은 리소스들을 제거한다. Code shrinking이 진행된 후에 진행하는 것이 유리하다. Code shrinking이 끝난 후에 어떤 리소스들을 참조되며 사용할 지를 정확히 판단할 수 있다.

Obfuscation(난독화) : 난독화는 앱의 코드를 의도적으로 어렵게 만들어서 앱을 리버싱으로 부터 보호하고 코드의 가독성을 낮추는 작업이다. 다만 이런 난독화 과정을 거치고 나면 Crash가 나거나 우리가 알아볼 수 없게 된다. 그렇기 때문에 난독화 도구는 난독화를 수행할 때 매핑 파일을 생성해준다. R8 컴파일러는 mapping.txt 라는 파일을 생성한다.

MultiDex(멀티 덱스) : 안드로이드 앱이 커질수록 단일 .dex 파일에 모든 클래스를 포함하기 어려울 수 있다. 멀티 덱스 기능을 통해 여러 개의 .dex 파일을 사용할 수 있다. 여러 개로 나뉘어 앱 실행 시 필요한 부분만 로딩하여 메모리 절약을 할 수 있다.

Optimization(최적화) : 코드를 분석해서 최종 APK파일의 크기를 줄이는 최적화를 할 수 있다. ex) R8 컴파일러는 절대 수행 될 수 없는 else문을 스스로 제거해서 최적화를 진행해준다.

위 과정을 진행하게 도와주는 도구는 Proguard와 R8이 있다.

Proguard

Proguard는 .class파일을 dex파일로 변환하는 도구이다.

desugar는 자바 8이상의 기능을 지원하기 위해 이전 안드로이드 버전에서 사용할 수 없었던 새로운 자바 기능을 대체하거나 변환하는 과정이다.

이 과정의 가장 큰 단점이 더 긴 빌드 시간이다.

D8

앞선 문제를 해결하기 위해 안드로이드 스튜디오 3.2에서 구글은 Dex 컴파일러를 D8이라는 새로운 컴파일러를 도입했다. 특징은 desugaring 변환을 제거하고 이를 .class2dex 컴파일의 일부로 만들어 빌드 시간을 더 빠르게 만드는 것이다.

R8

R8은 D8의 파생 버전이다. 둘이 같은 코드베이스를 공유한다. 또한 R8은 추가적인 문제를 해결한다. D8과 마찬가지로 R8은 오래된 달빅/ART에서 새로운 Java 기능을 사용할 수 있게 해준다. R8의 가장 큰 장점은 앱에서 특정 디바이스나 API 레벨을 지원하기 위해 필요한 opcodes만 남기고 .dex 코드를 최적화하는 것이다.

Apkbuilder

.apk로 패키징한다.

Jarsigner

Jarsigner는 Java 아카이브(JAR) 파일을 디지털 서명하는 데 사용되던 도구

debug 또는 release용 keystore로 signing한다.

zipalign(release mode)

Zipalign은 APK 파일을 최적화하여 메모리 사용을 개선하는 도구. APK 안의 파일을 4바이트 경계에 정렬하여 앱이 더 효율적으로 메모리에 로드되도록 돕는다.

zipalign tool을 이용해 align시킨다.

구조

  • META-INF
    • 인증 서명과 관련한 정보가 담겨있는 디렉터리
  • assets
    • 의미 그대로 앱 실행에 필요한 자원들이 저장되는 디렉터리.
    • res 디렉터리와 중복되는 것 같지만 용량이 큰 파일 위주로 저장된다.
  • res
    • 앱 실행에 필요한 자원이 모여있는 디렉터리
      • Drawable : 프로젝트에 활용될 이미지들
      • Layout : 안드로이드 화면을 담당하는 xml들의 집함
      • Values
        • dimens.xml : 텍스트 크기, 도형 크기 등 크기에 관련된 설정 파일
        • strings.xml : 문자열에 관련된 설정 파일
        • styles.xml : 색상, 액션바 유무, 배경 색 등 화면 디자인 관련 설정을 정의res
    • assets 디렉터리에 비해 용량이 작은 파일 위주로 저장된다.

!https://blog.kakaocdn.net/dn/kzwME/btrgijqGKkA/rDMrTKkCJapVFTz1EHkrl1/img.png

  • lib
    • 라이브러리 파일들이 저장되는 디렉터리
  • AndroidManifest.xml
    • 어플리케이션을 구성하는 컴포넌트 및 패키지명, 버전과 같은 앱의 정보가 저장되는 파일이다.
    • AndroidManifest.xml 의 주요 컴포넌트
      • Activity : Activity는 일반적으로 하나의 뷰를 말하며, 해당 Activity에 대한 속성을 정의함
      • Service : 백그라운드에서 실행되는 서비스
      • Broadcast Receiver : 안드로이드 내부 이벤트 핸들링을 위한 컴포넌트 ex) 문자수신, 베터리 부족
      • Content Provide : 어플리케이션간 데이터 공유를 위한 컴포넌트
  • class.dex
    • .class 파일을 달빅 바이트 코드로 변환시킨 소스 파일
  • resources.arsc
    • res의 정보가 기록되어 있다.
    • 컴파일된 리소스(문자열, 스타일 등)가 존재

요약

  • 안드로이드는 구글이 개발한 리눅스 기반 오픈소스 모바일 운영체제
  • AOSP는 안드로이드의 오픈소스 프로젝트로, 핵심 코드베이스를 제공
  • Android는 AOSP를 기반으로 하며 구글 서비스와 앱을 포함한 완성된 OS
  • DEX 파일은 안드로이드 앱의 실행 코드를 담고 있는 파일 형식
  • DEX 파일 구조는 헤더와 여러 섹션(string_ids, type_ids, proto_ids 등)으로 구성
  • 각 섹션은 특정 정보(문자열, 타입, 메소드 등)를 저장하고 관리
  • 헤더 정보를 통해 각 섹션의 위치와 크기를 파악할 수 있음
profile
아무것도 안 한 거랑 다를께 없잖아??

0개의 댓글