Skip to content

Commit e660b0b

Browse files
mxindenlarseggert
andauthored
ci: run tests on Android emulator (#2058)
* ci: run tests on Android emulator * Use different cache key for Android NSS builds * ndk * Set ANDROID_NDK_HOME * Use installed NDK * Again * Fix * Again * Fixes * Fix parameter * Fix * Android * Patch * endsWith * nspr.sh * before * sed * sysroot * long * target * Again * ln * quote * ln * Again * toolchain * again * Again * Again * Again * env * Again * elif * Again * Again * Again * Again * -mandroid * nspr * Again * nspr * Again * dash * Switch * arch * space * cpp * Again * cpp * cpp * ar * ranlib * target * Use script * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * ARGH * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Fixes * More * MSRV * mtu 0.2.7 * Fixes * mold * Again * ls * tmp * include * Again * Again * Again * sysroot * Again * lib * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * c++ * Again * Again * Again * Again * 24 * 25 * pkix * API level * Again * Fixes for 32-bit platforms * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * Again * NSS_DB_PATH * Again * Again * Fix * clippy * Android ECN test * Update neqo-crypto/src/lib.rs Co-authored-by: Max Inden <[email protected]> Signed-off-by: Lars Eggert <[email protected]> * Pin `mozilla/application-services` scripts to `v137.0` * Undo 32-bit changes * Reorder libs --------- Signed-off-by: Lars Eggert <[email protected]> Co-authored-by: Lars Eggert <[email protected]>
1 parent 3e951d1 commit e660b0b

File tree

7 files changed

+172
-18
lines changed

7 files changed

+172
-18
lines changed

.github/actions/nss/action.yml

+47-7
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ inputs:
88
minimum-version:
99
description: "Minimum required version of NSS"
1010
required: true
11+
target:
12+
description: "Target for cross-compilation"
13+
default: ""
1114

1215
runs:
1316
using: composite
1417
steps:
1518
- name: Install system NSS (Linux)
1619
shell: bash
17-
if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' }}
20+
if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' && inputs.target == '' }}
1821
env:
1922
DEBIAN_FRONTEND: noninteractive
2023
run: |
@@ -23,7 +26,7 @@ runs:
2326
2427
- name: Install system NSS (MacOS)
2528
shell: bash
26-
if: ${{ runner.os == 'MacOS' && runner.environment == 'github-hosted' }}
29+
if: ${{ runner.os == 'MacOS' && runner.environment == 'github-hosted' && inputs.target == '' }}
2730
run: |
2831
[ "$BREW_UPDATED" ] || brew update && echo "BREW_UPDATED=1" >> "$GITHUB_ENV"
2932
brew install nss
@@ -33,6 +36,7 @@ runs:
3336
env:
3437
MIN_VERSION: ${{ inputs.minimum-version }}
3538
shell: bash
39+
if: inputs.target == ''
3640
run: |
3741
if ! command -v pkg-config &> /dev/null; then
3842
echo "pkg-config: not found"
@@ -116,7 +120,7 @@ runs:
116120
uses: actions/cache/restore@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
117121
with:
118122
path: dist
119-
key: nss-${{ runner.os }}-${{ runner.arch }}-${{ inputs.type }}-${{ steps.heads.outputs.nss_head }}-${{ steps.heads.outputs.NSPR_HEAD }}
123+
key: nss-${{ inputs.target && inputs.target || runner.os }}-${{ runner.arch }}-${{ inputs.type }}-${{ steps.heads.outputs.nss_head }}-${{ steps.heads.outputs.NSPR_HEAD }}
120124

121125
- name: Check if build is needed
122126
id: check_build
@@ -184,9 +188,10 @@ runs:
184188
if: ${{ !steps.nss.outputs.use_system_nss }}
185189
env:
186190
NSS_TARGET: ${{ inputs.type }}
191+
NSS_TYPE: ${{ inputs.type }}
187192
NSS_DIR: ${{ github.workspace }}/nss
188193
run: |
189-
NSS_OUT="${{ github.workspace }}/nss/../dist/$NSS_TARGET"
194+
NSS_OUT="${{ github.workspace }}/dist/$NSS_TARGET"
190195
{
191196
echo "LD_LIBRARY_PATH=$NSS_OUT/lib"
192197
echo "DYLD_FALLBACK_LIBRARY_PATH=$NSS_OUT/lib"
@@ -202,7 +207,7 @@ runs:
202207
shell: bash
203208
if: ${{ steps.check_build.outputs.build_nss }}
204209
env:
205-
NSS_TARGET: ${{ inputs.type }}
210+
TARGET_PLATFORM: ${{ inputs.target }}
206211
run: |
207212
if [ "$NSS_TARGET" != "Debug" ]; then
208213
# We want to do an optimized build for accurate CPU profiling, but
@@ -211,5 +216,40 @@ runs:
211216
OPT="-o"
212217
[ "${{ runner.os }}" != "Windows" ] && export CFLAGS="-ggdb3 -fno-omit-frame-pointer"
213218
fi
214-
[ "$SCCACHE_CC" ] && [ "$SCCACHE_CXX" ] && export CC="$SCCACHE_CC" CXX="$SCCACHE_CXX"
215-
$NSS_DIR/build.sh -g -Ddisable_tests=1 $OPT --static
219+
if [[ $TARGET_PLATFORM == *-android* ]]; then
220+
for file in build-nss-android.sh build-android-common.sh; do
221+
curl -o "$file" -sSf "https://raw.githubusercontent.com/mozilla/application-services/refs/tags/v137.0/libs/$file"
222+
chmod +x "$file"
223+
done
224+
# See https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md#android
225+
ANDROID_NDK_VERSION=$(basename "$ANDROID_NDK" | cut -d. -f1)
226+
# See https://github.com/mozilla/application-services/blob/46cacda811da094653dc8e93158956f4cd57e87a/libs/build-all.sh#L89-L102
227+
# It figures that NSPR would require monkey-patching to build on Android.
228+
sed -i'' 's/if test -z "$android_ndk" ; then/$as_echo "#define ANDROID 1" >>confdefs.h\n ;;\nunreachable)\n if test -z "$android_ndk" ; then/g' nspr/configure
229+
./build-nss-android.sh "$(pwd)" "/tmp/dist" "$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64" "$TARGET_PLATFORM" "$ANDROID_NDK_VERSION"
230+
# Manually move the temporary build directory to the final location, which is what neqo-crypto expects.
231+
find /tmp/tmp.* > tmp
232+
CERTUTIL="$(grep certutil tmp)"
233+
TARGET_DIR="$(dirname $(dirname $CERTUTIL))"
234+
mkdir -p "dist/$NSS_TARGET"
235+
cp -vaL "$TARGET_DIR"/* "dist/$NSS_TARGET/"
236+
NSPR_H="$(grep nspr.h tmp)"
237+
INCLUDE_DIR="$(dirname $NSPR_H)"
238+
mkdir -p "dist/$NSS_TARGET/include/nspr"
239+
cp -vaL "$INCLUDE_DIR"/* "dist/$NSS_TARGET/include/nspr"
240+
CHACHA="$(grep chacha20poly1305.h tmp)"
241+
PRIVATE_DIR="$(dirname $(dirname $CHACHA))"
242+
mkdir -p "dist/private"
243+
cp -vaL "$PRIVATE_DIR"/* "dist/private/"
244+
UTILRENAME="$(grep utilrename.h tmp)"
245+
PUBLIC_DIR="$(dirname $(dirname $(dirname $UTILRENAME)))"
246+
mkdir -p "dist/public"
247+
cp -vaL "$PUBLIC_DIR"/* "dist/"
248+
LIBNSPR4="$(grep lib/libnspr4.a tmp)"
249+
LIB_DIR="$(dirname $LIBNSPR4)"
250+
mkdir -p "dist/$NSS_TARGET/lib"
251+
cp -vaL "$LIB_DIR"/* "dist/$NSS_TARGET/lib"
252+
else
253+
[ "$SCCACHE_CC" ] && [ "$SCCACHE_CXX" ] && export CC="$SCCACHE_CC" CXX="$SCCACHE_CXX"
254+
$NSS_DIR/build.sh -g -Ddisable_tests=1 $OPT --static
255+
fi

.github/actions/rust/action.yml

+5-3
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ runs:
3838
if: ${{ env.SCCACHE_ENABLED != '1' && runner.environment != 'github-hosted' }}
3939
uses: mozilla-actions/sccache-action@2e7f9ec7921547d4b46598398ca573513895d0bd # v0.0.4
4040

41-
- name: Install build dependencies (Linux)
41+
- name: Install mold (Linux)
4242
shell: bash
43-
if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' }}
43+
if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' && !contains(inputs.targets, '-android')}}
4444
env:
4545
DEBIAN_FRONTEND: noninteractive
4646
run: |
@@ -52,11 +52,13 @@ runs:
5252
# See https://corrode.dev/blog/tips-for-faster-ci-builds/
5353
- name: Set up build environment
5454
shell: bash
55+
env:
56+
TARGETS: ${{ inputs.targets }}
5557
run: |
5658
{
5759
echo "CARGO_PROFILE_RELEASE_LTO=true"
5860
echo "CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1"
59-
if [[ "${{ runner.os }}" == "Linux" && "${{ inputs.targets }}" == "" && "$(command -v mold)" ]]; then
61+
if [[ "${{ runner.os }}" == "Linux" && "$TARGETS" == "" && "$(command -v mold)" ]]; then
6062
echo "RUSTFLAGS=-C linker=clang -C link-arg=-fuse-ld=mold $RUSTFLAGS"
6163
elif [[ "${{ runner.os }}" == "Windows" ]]; then
6264
echo "RUSTFLAGS=-C link-arg=-fuse-ld=lld $RUSTFLAGS"

.github/workflows/check.yml

+89
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,92 @@ jobs:
151151
needs: [check]
152152
if: ${{ !cancelled() && (github.event_name != 'workflow_dispatch' || github.event.inputs.run_benchmarks) && github.actor != 'dependabot[bot]' }}
153153
uses: ./.github/workflows/bench.yml
154+
155+
check-android:
156+
runs-on: ubuntu-latest
157+
env:
158+
# https://searchfox.org/mozilla-central/search?q=NDK_VERSION =&path=python/mozboot/mozboot/android.py
159+
NDK_VERSION: 27.2.12479018 # r27c
160+
# https://searchfox.org/mozilla-central/search?q=\bapi_level=&path=taskcluster/scripts/misc/build-llvm-common.sh&regexp=true
161+
# However, NSS requires an API >= 23 for a few symbols.
162+
API_LEVEL: 23
163+
164+
strategy:
165+
matrix:
166+
include:
167+
- target: x86_64-linux-android
168+
emulator-arch: x86_64
169+
# Note that x86_64 image is only available for API 21+. See
170+
# https://github.com/ReactiveCircus/android-emulator-runner?tab=readme-ov-file#configurations.
171+
- target: i686-linux-android
172+
emulator-arch: x86
173+
# FIXME: https://github.com/ReactiveCircus/android-emulator-runner/issues/404
174+
# - target: armv7-linux-androideabi
175+
# emulator-arch: arm64-v8
176+
177+
steps:
178+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
179+
with:
180+
persist-credentials: false
181+
182+
- uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
183+
with:
184+
distribution: zulu
185+
java-version: 23
186+
187+
- uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2
188+
- run: sdkmanager --install "ndk;${{ env.NDK_VERSION }}"
189+
190+
- uses: ./.github/actions/rust
191+
with:
192+
version: stable
193+
targets: ${{ matrix.target }}
194+
tools: cargo-ndk
195+
token: ${{ secrets.GITHUB_TOKEN }}
196+
197+
- id: nss-version
198+
run: echo "minimum=$(cat neqo-crypto/min_version.txt)" >> "$GITHUB_OUTPUT"
199+
200+
- uses: ./.github/actions/nss
201+
with:
202+
minimum-version: ${{ steps.nss-version.outputs.minimum }}
203+
target: ${{ matrix.target }}
204+
205+
- run: cargo ndk --bindgen --platform "$API_LEVEL" --target ${{ matrix.target }} test --no-run
206+
207+
- env:
208+
TARGET: ${{ matrix.target }}
209+
run: |
210+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
211+
sudo udevadm control --reload-rules
212+
sudo udevadm trigger --name-match=kvm
213+
cat <<'EOF' > /tmp/rust-android-run-tests-on-emulator.sh
214+
#!/bin/bash
215+
set -e
216+
adb wait-for-device
217+
while [ -z "$(adb shell getprop sys.boot_completed | tr -d '\r')" ]; do sleep 1; done
218+
any_failures=0
219+
TMP=/data/local/tmp
220+
adb push "test-fixture/db" "$TMP/"
221+
adb push "$LD_LIBRARY_PATH" "$TMP/"
222+
for test in $(find target/$TARGET/debug/deps/ -type f -executable ! -name "*.so" -name "*-*"); do
223+
adb push "$test" "$TMP/"
224+
adb shell chmod +x "$TMP/$(basename "$test")"
225+
# See https://unix.stackexchange.com/a/451140/409256
226+
adb shell "CARGO_TERM_COLOR=always RUST_BACKTRACE=1 LD_LIBRARY_PATH=$TMP/lib NSS_DB_PATH=$TMP/db API_LEVEL=$API_LEVEL $TMP/$(basename "$test") || echo _FAIL_" 2>&1 | tee output
227+
grep _FAIL_ output > /dev/null && any_failures=1
228+
done
229+
exit $any_failures
230+
EOF
231+
chmod a+x /tmp/rust-android-run-tests-on-emulator.sh
232+
233+
- uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # v2.33.0
234+
with:
235+
api-level: ${{ env.API_LEVEL }}
236+
arch: ${{ matrix.emulator-arch == 'arm64-v8' && 'arm64-v8a' || matrix.emulator-arch }}
237+
ndk: ${{ env.NDK_VERSION }}
238+
emulator-boot-timeout: 120
239+
disk-size: 2G
240+
script: /tmp/rust-android-run-tests-on-emulator.sh
241+
env:
242+
TARGET: ${{ matrix.target }}

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ infinite_loop = "warn"
7777
large_include_file = "warn"
7878
let_underscore_must_use = "warn"
7979
let_underscore_untyped = "warn"
80-
literal_string_with_formatting_args = "allow" # FIXME: Re-enable "warn" when MRSV is > 1.87. See https://github.com/rust-lang/rust-clippy/pull/13953#issuecomment-2676336899
80+
literal_string_with_formatting_args = "allow" # FIXME: Re-enable "warn" when MSRV is > 1.87. See https://github.com/rust-lang/rust-clippy/pull/13953#issuecomment-2676336899
8181
lossy_float_literal = "warn"
8282
mem_forget = "warn"
8383
mixed_read_write_in_expression = "warn"

neqo-crypto/build.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,11 @@ fn static_link() {
185185
// Dynamic libs that aren't transitively included by NSS libs.
186186
let mut other_libs = Vec::new();
187187
if env::consts::OS != "windows" {
188-
other_libs.extend_from_slice(&["pthread", "dl", "c", "z"]);
188+
if env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() != "android" {
189+
// On Android, pthread is part of libc.
190+
other_libs.push("pthread");
191+
}
192+
other_libs.extend_from_slice(&["dl", "c", "z"]);
189193
}
190194
if env::consts::OS == "macos" {
191195
other_libs.push("sqlite3");

neqo-crypto/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub mod selfencrypt;
2828
mod ssl;
2929
mod time;
3030

31-
use std::{ffi::CString, path::PathBuf, ptr::null, sync::OnceLock};
31+
use std::{env, ffi::CString, path::PathBuf, ptr::null, sync::OnceLock};
3232

3333
#[cfg(not(feature = "disable-encryption"))]
3434
pub use self::aead::RealAead as Aead;
@@ -167,6 +167,9 @@ pub fn init() -> Res<()> {
167167
///
168168
/// If NSS cannot be initialized.
169169
pub fn init_db<P: Into<PathBuf>>(dir: P) -> Res<()> {
170+
// Allow overriding the NSS database path with an environment variable.
171+
let dir = env::var("NSS_DB_PATH")
172+
.unwrap_or(dir.into().to_str().ok_or(Error::InternalError)?.to_string());
170173
let res = INITIALIZED.get_or_init(|| init_once(Some(dir.into())));
171174
res.as_ref().map(|_| ()).map_err(Clone::clone)
172175
}

neqo-udp/src/lib.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ impl<S: SocketRef> Socket<S> {
218218

219219
#[cfg(test)]
220220
mod tests {
221+
use std::env;
222+
221223
use neqo_common::{IpTosDscp, IpTosEcn};
222224

223225
use super::*;
@@ -268,11 +270,25 @@ mod tests {
268270
.expect("receive to succeed");
269271

270272
// Assert that the ECN is correct.
271-
assert_eq!(
272-
IpTosEcn::from(datagram.tos()),
273-
IpTosEcn::from(received_datagrams.next().unwrap().tos())
274-
);
275-
273+
// On Android API level <= 25 the IPv4 `IP_TOS` control message is
274+
// not supported and thus ECN bits can not be received.
275+
if cfg!(target_os = "android")
276+
&& env::var("API_LEVEL")
277+
.ok()
278+
.and_then(|v| v.parse::<u32>().ok())
279+
.expect("API_LEVEL environment variable to be set on Android")
280+
<= 25
281+
{
282+
assert_eq!(
283+
IpTosEcn::default(),
284+
IpTosEcn::from(received_datagrams.next().unwrap().tos())
285+
);
286+
} else {
287+
assert_eq!(
288+
IpTosEcn::from(datagram.tos()),
289+
IpTosEcn::from(received_datagrams.next().unwrap().tos())
290+
);
291+
}
276292
Ok(())
277293
}
278294

0 commit comments

Comments
 (0)