Skip to content

Commit

Permalink
android: Probe whether dl_iterate_phdr is defined
Browse files Browse the repository at this point in the history
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
  • Loading branch information
alexcrichton committed Jul 17, 2019
1 parent 7d93adb commit acf613e
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 4 deletions.
74 changes: 74 additions & 0 deletions ci/android-sdk.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env sh
# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.

set -ex

# Prep the SDK and emulator
#
# Note that the update process requires that we accept a bunch of licenses, and
# we can't just pipe `yes` into it for some reason, so we take the same strategy
# located in https://github.com/appunite/docker by just wrapping it in a script
# which apparently magically accepts the licenses.

SDK=4333796
mkdir sdk
curl --retry 20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip -O
unzip -q -d sdk sdk-tools-linux-${SDK}.zip

case "$1" in
arm | armv7)
api=24
image="system-images;android-${api};google_apis;armeabi-v7a"
;;
aarch64)
api=24
image="system-images;android-${api};google_apis;arm64-v8a"
;;
i686)
api=28
image="system-images;android-${api};default;x86"
;;
x86_64)
api=28
image="system-images;android-${api};default;x86_64"
;;
*)
echo "invalid arch: $1"
exit 1
;;
esac;

# Try to fix warning about missing file.
# See https://askubuntu.com/a/1078784
mkdir -p /root/.android/
echo '### User Sources for Android SDK Manager' >> /root/.android/repositories.cfg
echo '#Fri Nov 03 10:11:27 CET 2017 count=0' >> /root/.android/repositories.cfg

# Print all available packages
# yes | ./sdk/tools/bin/sdkmanager --list --verbose

# --no_https avoids
# javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
#
# | grep -v = || true removes the progress bar output from the sdkmanager
# which produces an insane amount of output.
yes | ./sdk/tools/bin/sdkmanager --licenses --no_https | grep -v = || true
yes | ./sdk/tools/bin/sdkmanager --no_https \
"emulator" \
"platform-tools" \
"platforms;android-${api}" \
"${image}" | grep -v = || true

echo "no" |
./sdk/tools/bin/avdmanager create avd \
--name "${1}" \
--package "${image}" | grep -v = || true

23 changes: 21 additions & 2 deletions ci/docker/arm-linux-androideabi/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,27 @@ RUN apt-get update && apt-get install -y --no-install-recommends \

COPY android-ndk.sh /
RUN /android-ndk.sh arm
ENV PATH=$PATH:/android-toolchain/bin
WORKDIR /android
COPY android-sdk.sh /android/sdk.sh
RUN ./sdk.sh arm
RUN mv /root/.android /tmp
RUN chmod 777 -R /tmp/.android
RUN chmod 755 /android/sdk/tools/* /android/sdk/emulator/qemu/linux-x86_64/*
ENV PATH=$PATH:/android-toolchain/bin:/android/sdk/platform-tools

# TODO: run tests in an emulator eventually
ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER="true"
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER=/tmp/runtest \
HOME=/tmp

ADD runtest-android.rs /tmp/runtest.rs
ENTRYPOINT [ \
"bash", \
"-c", \
# set SHELL so android can detect a 64bits system, see
# http://stackoverflow.com/a/41789144
"SHELL=/bin/dash /android/sdk/emulator/emulator @arm -no-window & \
/rust/bin/rustc /tmp/runtest.rs -o /tmp/runtest && \
exec \"$@\"", \
"--" \
]
50 changes: 50 additions & 0 deletions ci/runtest-android.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};

fn main() {
let args = env::args_os()
.skip(1)
.filter(|arg| arg != "--quiet")
.collect::<Vec<_>>();
assert_eq!(args.len(), 1);
let test = PathBuf::from(&args[0]);
let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());

println!("waiting for device to come online...");
let status = Command::new("adb")
.arg("wait-for-device")
.status()
.expect("failed to run: adb wait-for-device");
assert!(status.success());

println!("pushing executable...");
let status = Command::new("adb")
.arg("push")
.arg(&test)
.arg(&dst)
.status()
.expect("failed to run: adb pushr");
assert!(status.success());

println!("executing tests...");
let output = Command::new("adb")
.arg("shell")
.arg(&dst)
.output()
.expect("failed to run: adb shell");
assert!(status.success());

println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr));

let stdout = String::from_utf8_lossy(&output.stdout);
stdout.lines().find(|l|
(l.starts_with("PASSED ") && l.contains(" tests")) ||
l.starts_with("test result: ok")
).unwrap_or_else(|| {
panic!("failed to find successful test run");
});
}
34 changes: 32 additions & 2 deletions crates/backtrace-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ fn main() {
build.define("BACKTRACE_SUPPORTS_DATA", "0");

File::create(out_dir.join("config.h")).unwrap();
if !target.contains("apple-ios")
if target.contains("android") {
maybe_enable_dl_iterate_phdr_android(&mut build);
} else if !target.contains("apple-ios")
&& !target.contains("solaris")
&& !target.contains("redox")
&& !target.contains("android")
&& !target.contains("haiku")
&& !target.contains("vxworks")
{
Expand Down Expand Up @@ -122,3 +123,32 @@ fn main() {

build.compile("backtrace");
}

// The `dl_iterate_phdr` API was added in Android API 21+ (according to #227),
// so if we can dynamically detect an appropriately configured C compiler for
// that then let's enable the `dl_iterate_phdr` API, otherwise Android just
// won't have any information.
fn maybe_enable_dl_iterate_phdr_android(build: &mut cc::Build) {
let expansion = cc::Build::new().file("src/android-api.c").expand();
let expansion = match std::str::from_utf8(&expansion) {
Ok(s) => s,
Err(_) => return,
};
println!("expanded android version detection:\n{}", expansion);
let marker = "APIVERSION";
let i = match expansion.find(marker) {
Some(i) => i,
None => return,
};
let version = match expansion[i + marker.len() + 1..].split_whitespace().next() {
Some(s) => s,
None => return,
};
let version = match version.parse::<u32>() {
Ok(n) => n,
Err(_) => return,
};
if version >= 21 {
build.define("HAVE_DL_ITERATE_PHDR", "1");
}
}
4 changes: 4 additions & 0 deletions crates/backtrace-sys/src/android-api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Used from the build script to detect the value of the `__ANDROID_API__`
// builtin #define

APIVERSION __ANDROID_API__

0 comments on commit acf613e

Please sign in to comment.