Skip to content

Commit acf613e

Browse files
committed
android: Probe whether dl_iterate_phdr is defined
Dynamically determine at build time whether the Android API version is high enough such that we can enable the usage of `dl_iterate_phdr`. This means that builds for old API revisions like libstd won't pull in new binary deps, but builds on crates.io of this crate with newer toolchains should have better backtraces by default. Some tests for actually executing Android tests have now been enabled on CI as well which were failing previously and after this change are now working. Closes #151 Closes #227
1 parent 7d93adb commit acf613e

File tree

5 files changed

+181
-4
lines changed

5 files changed

+181
-4
lines changed

ci/android-sdk.sh

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env sh
2+
# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
3+
# file at the top-level directory of this distribution and at
4+
# http://rust-lang.org/COPYRIGHT.
5+
#
6+
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7+
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8+
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9+
# option. This file may not be copied, modified, or distributed
10+
# except according to those terms.
11+
12+
set -ex
13+
14+
# Prep the SDK and emulator
15+
#
16+
# Note that the update process requires that we accept a bunch of licenses, and
17+
# we can't just pipe `yes` into it for some reason, so we take the same strategy
18+
# located in https://github.com/appunite/docker by just wrapping it in a script
19+
# which apparently magically accepts the licenses.
20+
21+
SDK=4333796
22+
mkdir sdk
23+
curl --retry 20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip -O
24+
unzip -q -d sdk sdk-tools-linux-${SDK}.zip
25+
26+
case "$1" in
27+
arm | armv7)
28+
api=24
29+
image="system-images;android-${api};google_apis;armeabi-v7a"
30+
;;
31+
aarch64)
32+
api=24
33+
image="system-images;android-${api};google_apis;arm64-v8a"
34+
;;
35+
i686)
36+
api=28
37+
image="system-images;android-${api};default;x86"
38+
;;
39+
x86_64)
40+
api=28
41+
image="system-images;android-${api};default;x86_64"
42+
;;
43+
*)
44+
echo "invalid arch: $1"
45+
exit 1
46+
;;
47+
esac;
48+
49+
# Try to fix warning about missing file.
50+
# See https://askubuntu.com/a/1078784
51+
mkdir -p /root/.android/
52+
echo '### User Sources for Android SDK Manager' >> /root/.android/repositories.cfg
53+
echo '#Fri Nov 03 10:11:27 CET 2017 count=0' >> /root/.android/repositories.cfg
54+
55+
# Print all available packages
56+
# yes | ./sdk/tools/bin/sdkmanager --list --verbose
57+
58+
# --no_https avoids
59+
# javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
60+
#
61+
# | grep -v = || true removes the progress bar output from the sdkmanager
62+
# which produces an insane amount of output.
63+
yes | ./sdk/tools/bin/sdkmanager --licenses --no_https | grep -v = || true
64+
yes | ./sdk/tools/bin/sdkmanager --no_https \
65+
"emulator" \
66+
"platform-tools" \
67+
"platforms;android-${api}" \
68+
"${image}" | grep -v = || true
69+
70+
echo "no" |
71+
./sdk/tools/bin/avdmanager create avd \
72+
--name "${1}" \
73+
--package "${image}" | grep -v = || true
74+

ci/docker/arm-linux-androideabi/Dockerfile

+21-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,27 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
1111

1212
COPY android-ndk.sh /
1313
RUN /android-ndk.sh arm
14-
ENV PATH=$PATH:/android-toolchain/bin
14+
WORKDIR /android
15+
COPY android-sdk.sh /android/sdk.sh
16+
RUN ./sdk.sh arm
17+
RUN mv /root/.android /tmp
18+
RUN chmod 777 -R /tmp/.android
19+
RUN chmod 755 /android/sdk/tools/* /android/sdk/emulator/qemu/linux-x86_64/*
20+
ENV PATH=$PATH:/android-toolchain/bin:/android/sdk/platform-tools
1521

1622
# TODO: run tests in an emulator eventually
1723
ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \
18-
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER="true"
24+
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER=/tmp/runtest \
25+
HOME=/tmp
26+
27+
ADD runtest-android.rs /tmp/runtest.rs
28+
ENTRYPOINT [ \
29+
"bash", \
30+
"-c", \
31+
# set SHELL so android can detect a 64bits system, see
32+
# http://stackoverflow.com/a/41789144
33+
"SHELL=/bin/dash /android/sdk/emulator/emulator @arm -no-window & \
34+
/rust/bin/rustc /tmp/runtest.rs -o /tmp/runtest && \
35+
exec \"$@\"", \
36+
"--" \
37+
]

ci/runtest-android.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::env;
2+
use std::process::Command;
3+
use std::path::{Path, PathBuf};
4+
5+
fn main() {
6+
let args = env::args_os()
7+
.skip(1)
8+
.filter(|arg| arg != "--quiet")
9+
.collect::<Vec<_>>();
10+
assert_eq!(args.len(), 1);
11+
let test = PathBuf::from(&args[0]);
12+
let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());
13+
14+
println!("waiting for device to come online...");
15+
let status = Command::new("adb")
16+
.arg("wait-for-device")
17+
.status()
18+
.expect("failed to run: adb wait-for-device");
19+
assert!(status.success());
20+
21+
println!("pushing executable...");
22+
let status = Command::new("adb")
23+
.arg("push")
24+
.arg(&test)
25+
.arg(&dst)
26+
.status()
27+
.expect("failed to run: adb pushr");
28+
assert!(status.success());
29+
30+
println!("executing tests...");
31+
let output = Command::new("adb")
32+
.arg("shell")
33+
.arg(&dst)
34+
.output()
35+
.expect("failed to run: adb shell");
36+
assert!(status.success());
37+
38+
println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
39+
output.status,
40+
String::from_utf8_lossy(&output.stdout),
41+
String::from_utf8_lossy(&output.stderr));
42+
43+
let stdout = String::from_utf8_lossy(&output.stdout);
44+
stdout.lines().find(|l|
45+
(l.starts_with("PASSED ") && l.contains(" tests")) ||
46+
l.starts_with("test result: ok")
47+
).unwrap_or_else(|| {
48+
panic!("failed to find successful test run");
49+
});
50+
}

crates/backtrace-sys/build.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ fn main() {
5656
build.define("BACKTRACE_SUPPORTS_DATA", "0");
5757

5858
File::create(out_dir.join("config.h")).unwrap();
59-
if !target.contains("apple-ios")
59+
if target.contains("android") {
60+
maybe_enable_dl_iterate_phdr_android(&mut build);
61+
} else if !target.contains("apple-ios")
6062
&& !target.contains("solaris")
6163
&& !target.contains("redox")
62-
&& !target.contains("android")
6364
&& !target.contains("haiku")
6465
&& !target.contains("vxworks")
6566
{
@@ -122,3 +123,32 @@ fn main() {
122123

123124
build.compile("backtrace");
124125
}
126+
127+
// The `dl_iterate_phdr` API was added in Android API 21+ (according to #227),
128+
// so if we can dynamically detect an appropriately configured C compiler for
129+
// that then let's enable the `dl_iterate_phdr` API, otherwise Android just
130+
// won't have any information.
131+
fn maybe_enable_dl_iterate_phdr_android(build: &mut cc::Build) {
132+
let expansion = cc::Build::new().file("src/android-api.c").expand();
133+
let expansion = match std::str::from_utf8(&expansion) {
134+
Ok(s) => s,
135+
Err(_) => return,
136+
};
137+
println!("expanded android version detection:\n{}", expansion);
138+
let marker = "APIVERSION";
139+
let i = match expansion.find(marker) {
140+
Some(i) => i,
141+
None => return,
142+
};
143+
let version = match expansion[i + marker.len() + 1..].split_whitespace().next() {
144+
Some(s) => s,
145+
None => return,
146+
};
147+
let version = match version.parse::<u32>() {
148+
Ok(n) => n,
149+
Err(_) => return,
150+
};
151+
if version >= 21 {
152+
build.define("HAVE_DL_ITERATE_PHDR", "1");
153+
}
154+
}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Used from the build script to detect the value of the `__ANDROID_API__`
2+
// builtin #define
3+
4+
APIVERSION __ANDROID_API__

0 commit comments

Comments
 (0)