Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ndk-build/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- Link and `zipalign` all libraries with 16KiB alignment for Android 15+. ([#76](https://github.com/rust-mobile/cargo-apk/pull/76))

# 0.10.0 (2023-11-30)

- Add `android:extractNativeLibs`, `android:usesCleartextTraffic` attributes to the manifest's `Application` element, and `android:alwaysRetainTaskState` to the `Activity` element. ([#15](https://github.com/rust-mobile/cargo-apk/pull/15))
Expand Down
7 changes: 6 additions & 1 deletion ndk-build/src/apk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl ApkConfig {
self.build_dir.join(format!("{}.apk", self.apk_name))
}

pub fn create_apk(&self) -> Result<UnalignedApk, NdkError> {
pub fn create_apk(&self) -> Result<UnalignedApk<'_>, NdkError> {
std::fs::create_dir_all(&self.build_dir)?;
self.manifest.write_to(&self.build_dir)?;

Expand Down Expand Up @@ -200,6 +200,8 @@ impl<'a> UnalignedApk<'a> {
let mut aapt = self.config.build_tool(bin!("aapt"))?;
aapt.arg("add");

// TODO: We might want to disable library compression separately, which allows them to be
// mmap'ed without decompression step after installation.
if self.config.disable_aapt_compression {
aapt.arg("-0").arg("");
}
Expand All @@ -218,6 +220,9 @@ impl<'a> UnalignedApk<'a> {
zipalign
.arg("-f")
.arg("-v")
// Force all uncompressed libraries to be 16KiB-aligned for Android 15+
// TODO: This requires build-tools 35.0.0
.args(["-P", "16"])
.arg("4")
.arg(self.config.unaligned_apk())
.arg(self.config.apk());
Expand Down
9 changes: 8 additions & 1 deletion ndk-build/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ pub fn cargo_ndk(
rustflags.push_str("-Clink-arg=");
rustflags.push_str(&clang_target);

if ndk.version().0 < 28 {
// Link with 16KiB alignment. This is the default since NDK r28:
// https://developer.android.com/guide/practices/page-sizes#compile-r28
rustflags.push_str(SEP);
rustflags.push_str("-Clink-arg=-Wl,-z,max-page-size=16384");
}

let ar = ndk.toolchain_bin("ar", target)?;
cargo.env(format!("AR_{triple}"), &ar);
cargo.env(cargo_env_target_cfg("AR", triple), &ar);
Expand All @@ -79,7 +86,7 @@ pub fn cargo_ndk(
// See https://github.com/rust-lang/rust/pull/85806 for a discussion on why libgcc
// is still required even after replacing it with libunwind in the source.
// XXX: Add an upper-bound on the Rust version whenever this is not necessary anymore.
if ndk.build_tag() > 7272597 {
if ndk.version().2 > 7272597 {
let cargo_apk_link_dir = target_dir
.as_ref()
.join("cargo-apk-temp-extra-link-libraries");
Expand Down
32 changes: 18 additions & 14 deletions ndk-build/src/ndk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct Ndk {
user_home: PathBuf,
ndk_path: PathBuf,
build_tools_version: String,
build_tag: u32,
version: (u32, u32, u32),
platforms: Vec<u32>,
}

Expand Down Expand Up @@ -88,22 +88,24 @@ impl Ndk {
let build_tag = std::fs::read_to_string(ndk_path.join("source.properties"))
.expect("Failed to read source.properties");

let build_tag = build_tag
let version = build_tag
.split('\n')
.find_map(|line| {
let (key, value) = line
.split_once('=')
.split_once(" = ")
.expect("Failed to parse `key = value` from source.properties");
if key.trim() == "Pkg.Revision" {
// AOSP writes a constantly-incrementing build version to the patch field.
// This number is incrementing across NDK releases.
let mut parts = value.trim().split('.');
let _major = parts.next().unwrap();
let _minor = parts.next().unwrap();
let patch = parts.next().unwrap();
if key == "Pkg.Revision" {
let mut p = value.split('.');
let major = p.next().unwrap().parse().expect("Parse major field");
let minor = p.next().unwrap().parse().expect("Parse minor field");
let patch = p.next().unwrap();
// Can have an optional `XXX-beta1`
let patch = patch.split_once('-').map_or(patch, |(patch, _beta)| patch);
Some(patch.parse().expect("Failed to parse patch field"))
Some((
major,
minor,
patch.parse().expect("Failed to parse patch field"),
))
} else {
None
}
Expand Down Expand Up @@ -145,7 +147,7 @@ impl Ndk {
user_home,
ndk_path,
build_tools_version,
build_tag,
version,
platforms,
})
}
Expand All @@ -162,8 +164,10 @@ impl Ndk {
&self.build_tools_version
}

pub fn build_tag(&self) -> u32 {
self.build_tag
// WARNING: NDK build tags don't need to be sequential. For example the build tag of NDK r27d
// `27.3.13750724` is ahead of the first r28 release at `28.0.1243356`.
pub fn version(&self) -> (u32, u32, u32) {
self.version
}

pub fn platforms(&self) -> &[u32] {
Expand Down