Android 개발/트러블슈팅

Play가 16KB 페이지 크기를 요구합니다 — 네이티브 라이브러리 안 깨지게 맞춘 자리

stackD 2026. 7. 1. 18:00
반응형

 

릴리즈 빌드 올린 다음 날, Pixel 8 사용자 크래시 리포트가 쏟아졌습니다. logcat엔 cannot map segment, not page aligned. 4KB 환경에선 멀쩡하던 앱이 16KB 단말에서 그대로 죽어버린 현장이었어요.

 

Pixel 8에서만 SIGSEGV로 죽던 16KB 충돌의 정체

Pixel 8·9 같은 16KB 페이지 크기 단말에서 linker64cannot map segment from ... 메시지와 함께 앱을 끝내버립니다. 4KB 환경에선 멀쩡하니까 처음엔 기기 호환성 이슈로 오해하기 쉽던데요.

 

logcat에 page size 16384, not page aligned, dlopen failed 가 같이 찍히면 거의 정렬 문제입니다. 직접 NDK 코드를 빌드한 적이 없어도 광고·분석·결제 SDK 안에 박혀 있는 4KB 컴파일 .so 파일이 진짜 범인일 때가 많아요.

 

저도 "내 코드엔 C++ 한 줄 없는데?" 싶었는데, 막상 APK Analyzer 열어보니 외부 SDK의 .so 가 줄줄이 4KB 정렬이었습니다.

 

안드로이드 15 16KB 페이지 정렬 의무화와 Play Console 마감

Android 15(API 35) 이상을 targetSdk 로 하는 신규 앱·업데이트는 16KB 페이지 크기 단말에서 동작해야 하고, 미준수면 Play Console에서 업데이트 자체가 막힙니다. 기본 마감은 2025년 11월 1일, 1회 한정 연장 시한이었던 2026년 5월 31일도 이미 지났어요.

 

16KB 환경 자체는 앱 콜드 스타트가 평균 3% 정도 빨라지는 것으로 알려져 있어요. 다만 정렬 패딩 때문에 .so 파일 크기가 늘어서 APK가 수백 KB에서 수 MB까지 부풀어 오르는 맞바꿈이 따라옵니다.

 

3%가 어느 정도냐면, 콜드 스타트 1초짜리 앱이 970ms가 되는 정도라 체감은 크지 않아요. 그래도 Play의 의무화 칼날은 진짜라서 피해갈 길이 없습니다.

 

 

zipalign으로 16KB 페이지 정렬 확인하는 세 가지 방법

릴리즈 직전 점검 흐름은 이렇게 잡으시면 됩니다.

 

  1. zipalign -v -c -P 16 4 app-release.apk 로 검증. 끝에 Verification successful 이 안 뜨면 미정렬 .so 목록이 그대로 출력됩니다.
  2. 안드로이드 스튜디오(Android Studio)의 Build > Analyze APK 메뉴 → lib/ 폴더에서 .so 파일별 Alignment 값을 확인. 4096과 16384가 섞여 있으면 범인 후보입니다.
  3. adb shell getconf PAGE_SIZE 로 단말 페이지 크기를 직접 조회. 코드에 4096을 상수로 박아 둔 부분이 있다면 sysconf(_SC_PAGESIZE) 로 동적 조회하게 바꿔야 합니다.

 

1번 명령 한 줄이 가장 빠른 1차 필터예요. CI에 걸어두기도 좋습니다.

 

NDK r28 빌드와 외부 .so를 16KB로 맞추는 실전 순서

NDK r28부터는 기본값으로 16KB 정렬 빌드를 만들어 주고, AGP는 8.5.1 이상이 필요합니다. 그보다 낮은 NDK를 어쩔 수 없이 쓰는 경우엔 링커 플래그를 직접 박아야 해요.

 

target_link_options(myapp PRIVATE
    "-Wl,-z,max-page-size=16384"
    "-Wl,-z,common-page-size=16384"
)

 

외부 SDK도 같이 점검하셔야 되는데요, Firebase BoM 33.9.0 이상, AdMob은 16KB 명시 릴리즈 노트가 반영된 최신 GMA SDK 같은 메이저 라이브러리는 16KB 지원 버전이 이미 나와 있습니다. 플러터(Flutter)는 엔진 3.24, 리액트 네이티브(React Native)는 0.76이 최소선(권장 0.80.2)이고, 유니티(Unity)는 2022 LTS 또는 2023.x 패치 버전 쪽을 확인하셔야 합니다.

 

업데이트가 끊긴 상용 .so 때문에 막힐 때가 진짜 골치 아픈 대목인데요, patchelf --page-size 16384 로 강제 정렬이 가능하긴 합니다. 다만 코드 서명이나 무결성 체크가 깨질 위험이 있어서 최후의 수단으로만 두시는 게 안전합니다.

 

개인적으로는 patchelf 로 우회하기보다 SDK 공급사에 16KB 빌드 일정을 직접 문의하는 쪽이 훨씬 낫다고 봅니다. 한 번 강제 패치로 넘어가면 다음 릴리즈에서 또 같은 고민을 반복하게 되거든요.

 

 

16KB AVD 에뮬레이터로 릴리즈 전 충돌 잡기

안드로이드 스튜디오에서 AVD 만들 때 시스템 이미지 선택 화면에서 Show Package Details 를 켜고 16 KB Page Size 라벨이 붙은 Android 15.0 이미지를 고르시면 됩니다. 가상기기 한 대를 만들어 두면 평소 회귀 테스트에도 쭉 쓸 수 있어요.

 

CI에는 16KB 에뮬레이터 위에서 앱 콜드 스타트만 반복하는 스모크 잡 하나를 끼워두시는 게 좋습니다. 새로 들여온 의존성 한 줄이 4KB 정렬 .so 를 끌고 들어와도 PR 단계에서 잡혀요.

 

실 기기 토글 지원은 단계가 갈리는데요, Pixel 8은 개발자 옵션의 16KB 페이지 토글을 켜고 재부팅하면 바로 확인할 수 있어요. Pixel 9는 Android 15 QPR2 베타에서 한 차례 토글이 열렸다가 정식 펌웨어에서 빠졌고, Android 17 QPR1 베타에서 다시 돌아왔습니다. 어느 쪽이든 켠 다음 adb shell getconf PAGE_SIZE 가 16384를 찍는지만 확인하시면 됩니다.

 

저 같은 경우엔 사내 빌드 머신에 16KB AVD를 상시 띄워두고 머지 직전 한 번 더 부트만 시켜보고 있어요. 5분짜리 체크 한 번이 다음 날 크래시 리포트 폭탄을 막아주더라고요.

 

 

반응형
LIST