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
20 changes: 13 additions & 7 deletions ci/android-install-sdk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,31 @@ mkdir -p sdk/cmdline-tools
wget -q --tries=20 "https://dl.google.com/android/repository/commandlinetools-linux-${sdk}_latest.zip"
unzip -q -d sdk/cmdline-tools "commandlinetools-linux-${sdk}_latest.zip"

case "$1" in
# The API level is passed in (arg 2) so it stays a single source of truth
# shared with the CC wrapper name in the Dockerfile; only the image variant
# is arch-specific here.
arch="$1"
api="$2"
if [ -z "${api}" ]; then
echo "usage: $0 <arch> <api-level>"
exit 1
fi

case "${arch}" in
arm | armv7)
api=24
image="system-images;android-${api};default;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"
echo "invalid arch: ${arch}"
exit 1
;;
esac
Expand Down Expand Up @@ -66,7 +72,7 @@ cp /android/android-emulator-package.xml /android/sdk/emulator/package.xml

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

rm -rf "commandlinetools-linux-${sdk}_latest.zip" emulator-linux_x64-9058569.zip
10 changes: 7 additions & 3 deletions ci/docker/aarch64-linux-android/Dockerfile
Comment thread
10ne1 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,22 @@ WORKDIR /android/
COPY android* /android/

ENV ANDROID_ARCH=aarch64
# Single source of truth for the API level: it selects the emulator system
# image (passed to android-install-sdk.sh) and names the CC wrapper below, so
# the toolchain can never drift from the image the tests run on.
ARG ANDROID_API=24
ENV PATH=$PATH:/android/linux-x86_64/bin:/android/sdk/cmdline-tools/tools:/android/sdk/platform-tools

RUN /android/android-install-ndk.sh
RUN /android/android-install-sdk.sh $ANDROID_ARCH
RUN /android/android-install-sdk.sh $ANDROID_ARCH $ANDROID_API
RUN mv /root/.android /tmp
RUN chmod 777 -R /tmp/.android
RUN chmod 755 /android/sdk/cmdline-tools/tools/* /android/sdk/emulator/qemu/linux-x86_64/*

ENV PATH=$PATH:/rust/bin \
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android28-clang \
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android${ANDROID_API}-clang \
CARGO_TARGET_AARCH64_LINUX_ANDROID_RUNNER=/tmp/runtest \
CC_aarch64_linux_android=aarch64-linux-android28-clang \
CC_aarch64_linux_android=aarch64-linux-android${ANDROID_API}-clang \
AR_aarch64_linux_android=llvm-ar \
HOME=/tmp

Expand Down
10 changes: 7 additions & 3 deletions ci/docker/arm-linux-androideabi/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,22 @@ WORKDIR /android/
COPY android* /android/

ENV ANDROID_ARCH=arm
# Single source of truth for the API level: it selects the emulator system
# image (passed to android-install-sdk.sh) and names the CC wrapper below, so
# the toolchain can never drift from the image the tests run on.
ARG ANDROID_API=24
ENV PATH=$PATH:/android/linux-x86_64/bin:/android/sdk/cmdline-tools/tools:/android/sdk/platform-tools

RUN /android/android-install-ndk.sh
RUN /android/android-install-sdk.sh $ANDROID_ARCH
RUN /android/android-install-sdk.sh $ANDROID_ARCH $ANDROID_API
RUN mv /root/.android /tmp
RUN chmod 777 -R /tmp/.android
RUN chmod 755 /android/sdk/cmdline-tools/tools/* /android/sdk/emulator/qemu/linux-x86_64/*

ENV PATH=$PATH:/rust/bin \
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi28-clang \
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=armv7a-linux-androideabi${ANDROID_API}-clang \
CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER=/tmp/runtest \
CC_arm_linux_androideabi=armv7a-linux-androideabi28-clang \
CC_arm_linux_androideabi=armv7a-linux-androideabi${ANDROID_API}-clang \
AR_arm_linux_androideabi=llvm-ar \
HOME=/tmp

Expand Down
10 changes: 7 additions & 3 deletions ci/docker/x86_64-linux-android/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ RUN curl -fsSL https://us-apt.pkg.dev/doc/repo-signing-key.gpg \

WORKDIR /android/
ENV ANDROID_ARCH=x86_64
# The API level we compile against: this only names the CC wrapper and the toolchain we use.
# The Android Cuttlefish device is pinned separately and is newer, i.e. capable of testing
# newer APIs. The toolchain wrapper is held at the same baseline as arm/aarch64 for now.
ARG ANDROID_API=24
COPY android-install-ndk.sh /android/
RUN /android/android-install-ndk.sh

ENV PATH=$PATH:/rust/bin:/android/linux-x86_64/bin \
ANDROID_SERIAL=127.0.0.1:6520 \
CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android28-clang \
CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android${ANDROID_API}-clang \
CARGO_TARGET_X86_64_LINUX_ANDROID_RUNNER=/tmp/runtest \
CC_x86_64_linux_android=x86_64-linux-android28-clang \
CXX_x86_64_linux_android=x86_64-linux-android28-clang++ \
CC_x86_64_linux_android=x86_64-linux-android${ANDROID_API}-clang \
CXX_x86_64_linux_android=x86_64-linux-android${ANDROID_API}-clang++ \
AR_x86_64_linux_android=llvm-ar \
HOME=/tmp

Expand Down
80 changes: 52 additions & 28 deletions libc-test/build.rs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -2060,6 +2060,10 @@ fn test_android(target: &str) {
};
let x86 = target.contains("i686") || target.contains("x86_64");
let aarch64 = target.contains("aarch64");
// The API level the NDK toolchain targets, which caps the available libc
// API surface (see `Versions`). Detection is required, so unwrap and let a
// toolchain we can't read fail loudly rather than silently skip every test.
let android = VERSIONS.android.unwrap();

let mut cfg = ctest_cfg();
cfg.define("_GNU_SOURCE", None);
Expand Down Expand Up @@ -2251,8 +2255,7 @@ fn test_android(target: &str) {
"posix_spawn_file_actions_t" => true,
"posix_spawnattr_t" => true,

// Added in API level 24
"if_nameindex" => true,
"if_nameindex" if android < 24 => true,

_ => false,
}
Expand Down Expand Up @@ -2450,43 +2453,35 @@ fn test_android(target: &str) {
"reallocarray" => true,
"__system_property_wait" => true,

// Added in API level 30, but tests use level 28.
"memfd_create" | "mlock2" | "renameat2" | "statx" | "statx_timestamp" => true,
"memfd_create" | "mlock2" | "renameat2" | "statx" | "statx_timestamp"
if android < 30 =>
{
true
}

// Added in API level 33, but tests use level 28.
"preadv2" | "pwritev2" => true,

// Added in glibc 2.25.
"getentropy" => true,

// Added in API level 28, but some tests use level 24.
"getrandom" => true,

// Added in API level 28, but some tests use level 24.
"syncfs" => true,

// Added in API level 28, but some tests use level 24.
"pthread_attr_getinheritsched" | "pthread_attr_setinheritsched" => true,
// Added in API level 28, but some tests use level 24.
"fread_unlocked" | "fwrite_unlocked" | "fgets_unlocked" | "fflush_unlocked" => true,

// Added in API level 28, but some tests use level 24.
"aligned_alloc" => true,
"getrandom" | "syncfs" | "aligned_alloc" if android < 28 => true,

// Added in API level 26, but some tests use level 24.
"getgrent" => true,
"pthread_attr_getinheritsched" | "pthread_attr_setinheritsched" if android < 28 => true,

// Added in API level 26, but some tests use level 24.
"setgrent" => true,

// Added in API level 26, but some tests use level 24.
"endgrent" => true,
"fread_unlocked" | "fwrite_unlocked" | "fgets_unlocked" | "fflush_unlocked"
if android < 28 =>
{
true
}

// Added in API level 26, but some tests use level 24.
"getpwent" | "setpwent" | "endpwent" => true,
"getgrent" | "setgrent" | "endgrent" | "getpwent" | "setpwent" | "endpwent"
if android < 26 =>
{
true
}

// Added in API level 26, but some tests use level 24.
"getdomainname" | "setdomainname" => true,
"getdomainname" | "setdomainname" if android < 26 => true,

// FIXME(android): bad function pointers:
"isalnum" | "isalpha" | "iscntrl" | "isdigit" | "isgraph" | "islower" | "isprint"
Expand All @@ -2504,6 +2499,21 @@ fn test_android(target: &str) {
}
});

cfg.skip_fn_ptrcheck(move |func| {
match func {
// termios functions are <termios.h> inlines below API 28, so
// their C-side address never matches the symbol Rust links.
"tcdrain" | "tcflow" | "tcflush" | "tcgetattr" | "tcgetsid" | "tcsendbreak"
| "tcsetattr" | "cfgetispeed" | "cfgetospeed" | "cfmakeraw" | "cfsetispeed"
| "cfsetospeed" | "cfsetspeed"
if android < 28 =>
{
true
}
_ => false,
}
});

cfg.skip_struct_field_type(move |struct_, field| {
match (struct_.ident(), field.ident()) {
// This is a weird union, don't check the type.
Expand Down Expand Up @@ -6404,6 +6414,8 @@ struct Versions {
macos: Option<(u32, u32)>,
emscripten: Option<(u32, u32)>,
wasi_sdk: Option<(u32, WasiVersion)>,
/// Android API level (no minor version).
android: Option<u32>,
}

#[derive(Clone, Copy, Debug, Default)]
Expand Down Expand Up @@ -6432,6 +6444,13 @@ impl Versions {
#include "gnu/libc-version.h"
#endif

#ifdef __ANDROID__
/* The clang driver predefines __ANDROID_MIN_SDK_VERSION__ from the API level
* in the target triple; including api-level.h ensures it is defined even on
* toolchains that leave it to the header. */
#include "android/api-level.h"
#endif

#if defined(__FreeBSD__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__) \
Expand Down Expand Up @@ -6501,6 +6520,11 @@ impl Versions {
}
"__GLIBC__" => ret.glibc.get_or_insert_default().0 = value.parse().unwrap(),
"__GLIBC_MINOR__" => ret.glibc.get_or_insert_default().1 = value.parse().unwrap(),
// Clang 12+ predefines the target API level here as a plain integer.
// Every NDK wrapper we build with carries an API level, so parse it like
// the other version macros above and let a missing value fail loudly at
// the unwrap in `test_android` rather than silently skipping tests.
"__ANDROID_MIN_SDK_VERSION__" => ret.android = Some(value.parse().unwrap()),
"__MAC_OS_X_VERSION_MAX_ALLOWED" => {
let caps = mac_re.captures(value).unwrap();
let major: u32 = caps[1].parse().unwrap();
Expand Down