SYSONLINE
SDK36 · MIN 24
KOTLIN2.0
UTC07:37:12
UP00:01
MOD · ARTICLE · BUILD TOOLSS/N · AX-ANDROIPUBLISHED
Build ToolsSep 18, 202610 MIN

Your Kotlin App Ships Native Code You Never Wrote: The 16 KB Page Size Deadline

From February 1, 2027 Google Play will block updates that do not support 16 KB pages. The native code at risk usually sits inside an SDK you never compiled.

By Rocky Elsalaymeh · Founder & Principal Consultant, Strategia-X

The Requirement Hiding in Your Dependency Tree

"We are a Kotlin shop, we don't have native code." It is the most common answer to the 16 KB question, and it is usually wrong. Google's page size guide sets the rule: "all apps targeting Android 15 (API level 35) and higher must support 16 KB memory page sizes on 64-bit devices on Google Play." It also sets the consequence and the date: "Starting February 1, 2027, if your app updates don't support 16 KB memory page sizes, you won't be able to release these updates." That date has moved before. Google's May 2025 announcement named November 1, 2025 for new apps and updates, and a July 2025 post narrowed that to apps "that use native C/C++ code." What has not moved is the direction. The exemption is real but narrower than it sounds. The guide says: "If your app only uses code written in the Java programming language or in Kotlin, including all libraries or SDKs, then your app already supports 16 KB devices." The clause that matters is *including all libraries or SDKs*. Analytics, crash reporting, image and video codecs, on-device ML, maps, payments, anti-fraud and database engines routinely ship .so files inside their AARs. And the guide is blunt about what happens to them: "If your app uses any NDK libraries, either directly or indirectly through an SDK, then you will need to rebuild your app for it to work on these 16 KB devices." The first task is therefore not engineering. It is an inventory: open your release APK and look in lib/. Every .so in arm64-v8a and x86_64 is a dependency with a deadline.

Why Android Is Changing Its Page Size

A page is, in Google's words, "the granularity at which an operating system manages memory," and "the Android OS and applications have historically been built and optimized to run with a 4 KB page size." ARM CPUs also support 16 KB pages, and fewer, larger pages mean less memory-management overhead for the same working set. Google published the measured gains on its guide:
Measurement on 16 KB devicesImprovement Google reports
App launch under memory pressure"3.16% lower on average, with more significant improvements (up to 30%) for some apps that we tested"
Power draw during app launch"4.56% reduction on average"
Camera launch"4.48% faster hot starts on average, and 6.60% faster cold starts on average"
System boot"improved by 8% (approximately 950 milliseconds) on average"
The trade-off was stated when the work began. The same August 2024 post reported "an overall performance boost of 5-10% while using ~9% additional memory." Larger pages waste more of their partly used tail, and that cost is paid in RAM. For app teams the point is simpler: the platform is moving, the gains are system-wide, and an app whose native libraries assume 4 KB pages becomes the thing that holds a device back, or that does not load at all.

What Actually Breaks

There are three distinct failure modes, and they are fixed in different places. 1. ELF segment alignment. Each shared library declares how its LOAD segments are aligned. On a 16 KB device they must be aligned to at least 16 KB. The guide's check is to read the program headers and "ensure that the load segments don't have values less than 214. If any load segments are 213, 2**12, or lower values, you'll need to update the packaging for those libraries." This is fixed at *compile* time, by whoever compiled the library. 2. Zip alignment. "16 KB devices require apps that ship with uncompressed shared libraries to align them on a 16 KB zip-aligned boundary." This is fixed at *packaging* time, by your Gradle build. The guide flags a trap in older plugin versions: on AGP 8.3 to 8.5 "bundletool does not zipalign APKs by default. So, the app may appear to work, but when built from a bundle in Play, it won't install." 3. Code that assumes 4096. Native code that hard-codes the page size, or uses the PAGE_SIZE macro as a constant, breaks at run time. The guide's instruction: look for code that assumes "a device's page size is 4 KB (4096). Use getpagesize() or sysconf(_SC_PAGESIZE) instead," and audit mmap() calls with page-aligned arguments. It also notes that "PAGE_SIZE is undefined when 16 KB mode is enabled on NDK r27 and higher," so some of this surfaces as compile errors, which is the good outcome. Android does have a safety net, and you should not rely on it. On a 16 KB device, the package manager can run an app with 4 KB-aligned libraries in a backcompat mode, and "the app displays a warning when it's first launched saying that it's running in 16 KB backcompat mode." A warning dialog on first launch is a bug report your users file on your behalf.

Find It Before Google Play Does

Every check you need is documented and scriptable: - APK Analyzer. In Android Studio, "the Alignment column displays warning messages for any files that have alignment issues," and "Lint in Android Studio also highlights native libraries that aren't 16 KB aligned." - Command line. llvm-objdump -p on each .so for segment alignment; zipalign -c -P 16 -v 4 on the APK for zip alignment; Google also links a check_elf_alignment.sh script that runs both. - Play Console. The App Bundle Explorer reports "your app's build compliance" and "guidance on where your app may need updating." - A real 16 KB runtime. The SDK Manager offers 16 KB emulator images for ARM64 and x86_64, and on Pixel 8, 8 Pro and 8a (Android 15 QPR1 or higher) and Pixel 9-series devices a developer option boots the device in 16 KB mode. Confirm with adb shell getconf PAGE_SIZE, which "should return a value of 16384." The cheapest insurance is a CI gate, so a dependency upgrade that pulls in a misaligned library fails the pull request instead of the Play upload. The script below uses only the two documented checks.
bash
#!/usr/bin/env bash
# CI gate: fail if any 64-bit native library is not 16 KB aligned.
set -euo pipefail

APK=app/build/outputs/apk/release/app-release.apk
OBJDUMP="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objdump"
WORK=$(mktemp -d)
bad=0

# 1. ELF segment alignment: every LOAD segment must be 2**14 (16 KB) or larger.
unzip -q "$APK" 'lib/arm64-v8a/*' 'lib/x86_64/*' -d "$WORK" || true
for so in "$WORK"/lib/*/*.so; do
  [ -e "$so" ] || continue
  if "$OBJDUMP" -p "$so" | awk '$1 == "LOAD" && $NF != "2**14" && $NF != "2**16" { hit = 1 } END { exit !hit }'; then
    echo "NOT 16 KB ALIGNED: $(basename "$so")"
    bad=1
  fi
done

# 2. Zip alignment of uncompressed libraries, exactly as the Android docs check it.
if ! zipalign -c -P 16 -v 4 "$APK" > /dev/null; then
  echo "zip alignment check failed"
  bad=1
fi

exit $bad

Fix It in Order: Toolchain, Dependencies, Code

Toolchain first, because it is free. The guide's own shortcut: "If you update your tools to the latest versions (AGP version 8.5.1 or higher and NDK version r28 or higher) and use 16 KB-compatible prebuilt dependencies, then your app is 16 KB compatible by default." AGP 8.5.1 handles zip alignment of uncompressed libraries during packaging; "NDK version r28 and higher compile 16 KB-aligned by default." If you are pinned to an older NDK, the documented linker flags are -Wl,-z,max-page-size=16384 and -Wl,-z,common-page-size=16384. If you cannot upgrade AGP past 8.5, the documented fallback is to "switch to use compressed shared libraries" with useLegacyPackaging, which avoids zip alignment at the cost of install size and load time. Dependencies second, because you cannot fix them yourself. A prebuilt .so inside a vendor SDK can only be realigned by recompiling it, and you do not have its source. Map every misaligned library to the SDK that ships it, check each vendor's release notes for a 16 KB-compatible version, and escalate the ones without one now. Vendors facing the same deadline across their whole customer base will prioritise the customers who are asking. An SDK with no fix and no roadmap is a replacement decision, and replacement decisions take a quarter. Your own native code last, because it is the part you control. Rebuild with the current NDK, then search for 4096, PAGE_SIZE and mmap. Test on a 16 KB emulator image, not just by reading alignment tables: a correctly aligned library can still carry a hard-coded page size in its logic.
kotlin
// build.gradle.kts: fallback ONLY if AGP cannot be upgraded past 8.5
android {
    packaging {
        jniLibs {
            useLegacyPackaging = true   // compressed libs: no zip alignment, larger installs
        }
    }
}

/* CMakeLists.txt: only needed on NDK r27 or lower (r28+ aligns to 16 KB by default)
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
    "-Wl,-z,max-page-size=16384"
    "-Wl,-z,common-page-size=16384"
)
*/

Four Months Is Less Time Than It Sounds

February 1, 2027 is roughly four months from this post, and most of that time belongs to other people's release cycles. A realistic plan: 1. This week: inventory. List every .so in your release APK and the dependency that ships it. That list is the whole project. 2. This sprint: toolchain. AGP 8.5.1 or later, NDK r28 or later, and the CI gate above on every pull request. 3. This month: vendors. A ticket per SDK that ships a misaligned library, with a named owner and a date. Chase the ones with no answer. 4. Next month: test on 16 KB. Emulator image in CI, a Pixel in 16 KB mode on the QA desk, and a manual pass over the flows that exercise native code: camera, media, ML, maps, payments. 5. Before January: ship it. Release the aligned build behind a staged rollout well before the deadline, so the release that proves compliance is not also the release that carries a new feature. The teams that will scramble in January are the ones who answered "we don't have native code" in September. Open the APK.
MOD · TAKEAWAYS6 POINTSSUMMARY

Key Takeaways

  1. 1Google Play will block app updates that do not support 16 KB memory page sizes from February 1, 2027, for apps targeting Android 15 and higher.
  2. 2Pure Kotlin and Java apps are exempt only if every library and SDK is also free of native code; most production apps ship .so files from third-party SDKs.
  3. 3Three things break: ELF LOAD segments aligned below 2**14, uncompressed libraries not 16 KB zip-aligned, and native code that assumes a 4096-byte page.
  4. 4AGP 8.5.1+ and NDK r28+ make your own builds 16 KB compatible by default; on AGP 8.3 to 8.5 an app can pass locally and fail to install from Play.
  5. 5Prebuilt libraries inside vendor SDKs can only be fixed by the vendor; inventory them and escalate now.
  6. 6Gate CI with llvm-objdump and zipalign -c -P 16, and test on a 16 KB emulator image or a Pixel in 16 KB mode.
MOD · FAQ3 ENTRIESANSWERED

Frequently Asked

Does a Kotlin-only Android app need to support 16 KB pages?

Only if no library or SDK it includes ships native code. Google’s guide exempts apps that use only Java or Kotlin "including all libraries or SDKs"; check the lib/ folder of your APK for .so files.

What is the 16 KB deadline on Google Play?

Google’s page size guide states that from February 1, 2027, app updates that do not support 16 KB memory page sizes cannot be released, for apps targeting Android 15 (API 35) and higher.

Which tool versions support 16 KB pages by default?

AGP 8.5.1 or higher zip-aligns uncompressed native libraries to 16 KB, and NDK r28 or higher compiles 16 KB-aligned libraries by default. Older NDKs need the -z max-page-size=16384 linker flags.

MOD · BUILD · NEXTS/N · AX-CTA-0001READY

Ready to architect your next Android app?

ANDROID-ARCHITECT generates production-ready Kotlin code, architecture blueprints, and CI/CD configurations from plain-language descriptions. Start building for free.

ANDROID-ARCHITECT · CONSOLE
S/N · AX-1A-00001
STRATEGIA-X · ENGINEERED · IN · CALIFORNIA