Skip to content

Commit 331653c

Browse files
committed
fix: harden android and webrtc ci
1 parent 66eeeed commit 331653c

2 files changed

Lines changed: 78 additions & 56 deletions

File tree

packages/server/src/android.rs

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ use crate::error::AppError;
22
use serde_json::{json, Value};
33
use std::collections::HashMap;
44
use std::env;
5+
#[cfg(unix)]
56
use std::ffi::CString;
67
use std::ffi::OsString;
78
use std::io::{Read, Write};
9+
#[cfg(unix)]
810
use std::mem::MaybeUninit;
911
use std::net::{SocketAddr, TcpStream};
12+
#[cfg(unix)]
1013
use std::os::fd::RawFd;
1114
use std::path::{Path, PathBuf};
1215
use std::process::{Command, Stdio};
@@ -36,6 +39,9 @@ const MODIFIER_OPTION: u32 = 1 << 2;
3639
const MODIFIER_COMMAND: u32 = 1 << 3;
3740
const MODIFIER_CAPS_LOCK: u32 = 1 << 4;
3841

42+
#[cfg(not(unix))]
43+
type RawFd = i32;
44+
3945
type TimedMap<T> = Option<(Instant, HashMap<String, T>)>;
4046
type DisplayMetricsCache = HashMap<String, (Instant, AndroidDisplayMetrics)>;
4147
type ConsoleConnectionCache = HashMap<u16, TcpStream>;
@@ -1102,6 +1108,7 @@ impl AndroidSharedVideoFrameStream {
11021108

11031109
impl Drop for AndroidSharedVideoFrameStream {
11041110
fn drop(&mut self) {
1111+
#[cfg(unix)]
11051112
unsafe {
11061113
if !self.ptr.is_null() && self.length > 0 {
11071114
libc::munmap(self.ptr.cast(), self.length);
@@ -1150,75 +1157,86 @@ fn round_android_h264_dimension(value: u32) -> u32 {
11501157
}
11511158

11521159
fn open_android_shared_video_memory(handle: &str) -> Result<(RawFd, *mut u8, usize), AppError> {
1153-
let mut names = vec![handle.to_owned()];
1154-
if !handle.starts_with('/') {
1155-
names.push(format!("/{handle}"));
1156-
}
1157-
let mut last_error = None;
1158-
for name in names {
1159-
let c_name = CString::new(name.as_str())
1160-
.map_err(|_| AppError::native("Android shared video handle contains a NUL byte."))?;
1161-
let fd = unsafe { libc::shm_open(c_name.as_ptr(), libc::O_RDONLY, 0) };
1162-
if fd < 0 {
1163-
last_error = Some(std::io::Error::last_os_error());
1164-
continue;
1165-
}
1160+
#[cfg(not(unix))]
1161+
{
1162+
return Err(AppError::native(format!(
1163+
"Android emulator shared video `{handle}` requires POSIX shared memory and is not available on this host."
1164+
)));
1165+
}
11661166

1167-
let mut stat = MaybeUninit::<libc::stat>::uninit();
1168-
if unsafe { libc::fstat(fd, stat.as_mut_ptr()) } != 0 {
1169-
let error = std::io::Error::last_os_error();
1170-
unsafe {
1171-
libc::close(fd);
1172-
}
1173-
last_error = Some(error);
1174-
continue;
1167+
#[cfg(unix)]
1168+
{
1169+
let mut names = vec![handle.to_owned()];
1170+
if !handle.starts_with('/') {
1171+
names.push(format!("/{handle}"));
11751172
}
1176-
let stat = unsafe { stat.assume_init() };
1177-
let length = usize::try_from(stat.st_size).map_err(|_| {
1178-
unsafe {
1179-
libc::close(fd);
1173+
let mut last_error = None;
1174+
for name in names {
1175+
let c_name = CString::new(name.as_str()).map_err(|_| {
1176+
AppError::native("Android shared video handle contains a NUL byte.")
1177+
})?;
1178+
let fd = unsafe { libc::shm_open(c_name.as_ptr(), libc::O_RDONLY, 0) };
1179+
if fd < 0 {
1180+
last_error = Some(std::io::Error::last_os_error());
1181+
continue;
11801182
}
1181-
AppError::native(format!(
1182-
"Android emulator shared video `{handle}` reported an invalid size."
1183-
))
1184-
})?;
1185-
if length <= ANDROID_SHARED_VIDEO_HEADER_BYTES {
1186-
unsafe {
1187-
libc::close(fd);
1183+
1184+
let mut stat = MaybeUninit::<libc::stat>::uninit();
1185+
if unsafe { libc::fstat(fd, stat.as_mut_ptr()) } != 0 {
1186+
let error = std::io::Error::last_os_error();
1187+
unsafe {
1188+
libc::close(fd);
1189+
}
1190+
last_error = Some(error);
1191+
continue;
1192+
}
1193+
let stat = unsafe { stat.assume_init() };
1194+
let length = usize::try_from(stat.st_size).map_err(|_| {
1195+
unsafe {
1196+
libc::close(fd);
1197+
}
1198+
AppError::native(format!(
1199+
"Android emulator shared video `{handle}` reported an invalid size."
1200+
))
1201+
})?;
1202+
if length <= ANDROID_SHARED_VIDEO_HEADER_BYTES {
1203+
unsafe {
1204+
libc::close(fd);
1205+
}
1206+
return Err(AppError::native(format!(
1207+
"Android emulator shared video `{handle}` is smaller than the display header."
1208+
)));
11881209
}
1189-
return Err(AppError::native(format!(
1190-
"Android emulator shared video `{handle}` is smaller than the display header."
1191-
)));
1192-
}
11931210

1194-
let ptr = unsafe {
1195-
libc::mmap(
1196-
ptr::null_mut(),
1197-
length,
1198-
libc::PROT_READ,
1199-
libc::MAP_SHARED,
1200-
fd,
1201-
0,
1202-
)
1203-
};
1204-
if ptr == libc::MAP_FAILED {
1205-
let error = std::io::Error::last_os_error();
1206-
unsafe {
1207-
libc::close(fd);
1211+
let ptr = unsafe {
1212+
libc::mmap(
1213+
ptr::null_mut(),
1214+
length,
1215+
libc::PROT_READ,
1216+
libc::MAP_SHARED,
1217+
fd,
1218+
0,
1219+
)
1220+
};
1221+
if ptr == libc::MAP_FAILED {
1222+
let error = std::io::Error::last_os_error();
1223+
unsafe {
1224+
libc::close(fd);
1225+
}
1226+
last_error = Some(error);
1227+
continue;
12081228
}
1209-
last_error = Some(error);
1210-
continue;
1229+
return Ok((fd, ptr.cast::<u8>(), length));
12111230
}
1212-
return Ok((fd, ptr.cast::<u8>(), length));
1213-
}
12141231

1215-
Err(AppError::native(format!(
1232+
Err(AppError::native(format!(
12161233
"Android emulator shared video `{handle}` is unavailable. Start the emulator through SimDeck or launch it with `-share-vid`{}.",
12171234
last_error
12181235
.as_ref()
12191236
.map(|error| format!(" ({error})"))
12201237
.unwrap_or_default()
12211238
)))
1239+
}
12221240
}
12231241

12241242
fn read_android_shared_video_header_volatile(

scripts/integration/webrtc.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ const coreSimulatorCommandTimeoutMs = Number(
2828
const simdeckBootTimeoutMs = Number(
2929
process.env.SIMDECK_INTEGRATION_BOOT_TIMEOUT_MS ?? "300000",
3030
);
31+
const fixtureLaunchMaxRecoveries = Number(
32+
process.env.SIMDECK_INTEGRATION_FIXTURE_LAUNCH_MAX_RECOVERIES ??
33+
(process.env.CI === "true" ? "2" : "1"),
34+
);
3135

3236
let simulatorUDID = "";
3337
let serverProcess = null;
@@ -188,7 +192,7 @@ async function waitForHealth() {
188192

189193
async function launchFixtureWithRecovery(appPath, options = {}) {
190194
const recoveryCount = options.recoveryCount ?? 0;
191-
const maxRecoveries = options.maxRecoveries ?? 1;
195+
const maxRecoveries = options.maxRecoveries ?? fixtureLaunchMaxRecoveries;
192196

193197
simdeckJson(["install", simulatorUDID, appPath], {
194198
timeoutMs: 60_000,

0 commit comments

Comments
 (0)