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