]> git.proxmox.com Git - rustc.git/blame - library/std/src/sys/unix/android.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / library / std / src / sys / unix / android.rs
CommitLineData
a7813a04
XL
1//! Android ABI-compatibility module
2//!
3//! The ABI of Android has changed quite a bit over time, and libstd attempts to
4//! be both forwards and backwards compatible as much as possible. We want to
5//! always work with the most recent version of Android, but we also want to
6//! work with older versions of Android for whenever projects need to.
7//!
0731742a 8//! Our current minimum supported Android version is `android-9`, e.g., Android
a7813a04
XL
9//! with API level 9. We then in theory want to work on that and all future
10//! versions of Android!
11//!
12//! Some of the detection here is done at runtime via `dlopen` and
13//! introspection. Other times no detection is performed at all and we just
14//! provide a fallback implementation as some versions of Android we support
15//! don't have the function.
16//!
17//! You'll find more details below about why each compatibility shim is needed.
18
19#![cfg(target_os = "android")]
20
c30ab7b3
SL
21use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
22use libc::{ftruncate, pread, pwrite};
a7813a04 23
136023e0 24use super::{cvt, cvt_r, weak::weak};
60c5eb7d 25use crate::io;
a7813a04
XL
26
27// The `log2` and `log2f` functions apparently appeared in android-18, or at
28// least you can see they're not present in the android-17 header [1] and they
29// are present in android-18 [2].
30//
31// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
32// /android-17/arch-arm/usr/include/math.h
33// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
34// /android-18/arch-arm/usr/include/math.h
35//
36// Note that these shims are likely less precise than directly calling `log2`,
37// but hopefully that should be enough for now...
38//
39// Note that mathematically, for any arbitrary `y`:
40//
41// log_2(x) = log_y(x) / log_y(2)
42// = log_y(x) / (1 / log_2(y))
43// = log_y(x) * log_2(y)
44//
45// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
46// and get:
47//
48// log_2(x) = ln(x) * log_2(e)
49
50#[cfg(not(test))]
51pub fn log2f32(f: f32) -> f32 {
532ac7d7 52 f.ln() * crate::f32::consts::LOG2_E
a7813a04
XL
53}
54
55#[cfg(not(test))]
56pub fn log2f64(f: f64) -> f64 {
532ac7d7 57 f.ln() * crate::f64::consts::LOG2_E
a7813a04
XL
58}
59
60// Back in the day [1] the `signal` function was just an inline wrapper
61// around `bsd_signal`, but starting in API level android-20 the `signal`
62// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
63// removed [3].
64//
65// Basically this means that if we want to be binary compatible with multiple
66// Android releases (oldest being 9 and newest being 21) then we need to check
67// for both symbols and not actually link against either.
68//
69// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
70// /android-18/arch-arm/usr/include/signal.h
71// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
72// /platforms/android-20/arch-arm
73// /usr/include/signal.h
74// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
75// /android-21/arch-arm/usr/include/signal.h
76pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
77 weak!(fn signal(c_int, sighandler_t) -> sighandler_t);
78 weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);
79
80 let f = signal.get().or_else(|| bsd_signal.get());
81 let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
82 f(signum, handler)
83}
84
85// The `ftruncate64` symbol apparently appeared in android-12, so we do some
86// dynamic detection to see if we can figure out whether `ftruncate64` exists.
87//
88// If it doesn't we just fall back to `ftruncate`, generating an error for
89// too-large values.
c30ab7b3 90#[cfg(target_pointer_width = "32")]
a7813a04
XL
91pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
92 weak!(fn ftruncate64(c_int, i64) -> c_int);
93
a7813a04
XL
94 unsafe {
95 match ftruncate64.get() {
dfeec247 96 Some(f) => cvt_r(|| f(fd, size as i64)).map(drop),
a7813a04 97 None => {
f035d41b 98 if size > i32::MAX as u64 {
cdc7bbd5 99 Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot truncate >2GB"))
a7813a04 100 } else {
dfeec247 101 cvt_r(|| ftruncate(fd, size as i32)).map(drop)
a7813a04
XL
102 }
103 }
104 }
105 }
106}
c30ab7b3
SL
107
108#[cfg(target_pointer_width = "64")]
109pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
dfeec247 110 unsafe { cvt_r(|| ftruncate(fd, size as i64)).map(drop) }
c30ab7b3
SL
111}
112
113#[cfg(target_pointer_width = "32")]
60c5eb7d
XL
114pub unsafe fn cvt_pread64(
115 fd: c_int,
116 buf: *mut c_void,
117 count: size_t,
118 offset: i64,
119) -> io::Result<ssize_t> {
532ac7d7 120 use crate::convert::TryInto;
c30ab7b3
SL
121 weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
122 pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
123 if let Ok(o) = offset.try_into() {
124 cvt(pread(fd, buf, count, o))
125 } else {
cdc7bbd5 126 Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pread >2GB"))
c30ab7b3
SL
127 }
128 })
129}
130
131#[cfg(target_pointer_width = "32")]
60c5eb7d
XL
132pub unsafe fn cvt_pwrite64(
133 fd: c_int,
134 buf: *const c_void,
135 count: size_t,
136 offset: i64,
137) -> io::Result<ssize_t> {
532ac7d7 138 use crate::convert::TryInto;
c30ab7b3
SL
139 weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
140 pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
141 if let Ok(o) = offset.try_into() {
142 cvt(pwrite(fd, buf, count, o))
143 } else {
cdc7bbd5 144 Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pwrite >2GB"))
c30ab7b3
SL
145 }
146 })
147}
148
149#[cfg(target_pointer_width = "64")]
60c5eb7d
XL
150pub unsafe fn cvt_pread64(
151 fd: c_int,
152 buf: *mut c_void,
153 count: size_t,
154 offset: i64,
155) -> io::Result<ssize_t> {
c30ab7b3
SL
156 cvt(pread(fd, buf, count, offset))
157}
158
159#[cfg(target_pointer_width = "64")]
60c5eb7d
XL
160pub unsafe fn cvt_pwrite64(
161 fd: c_int,
162 buf: *const c_void,
163 count: size_t,
164 offset: i64,
165) -> io::Result<ssize_t> {
c30ab7b3
SL
166 cvt(pwrite(fd, buf, count, offset))
167}