xref: /aosp_15_r20/system/librustutils/system_properties.rs (revision e51878c104ea269309bae357ae559a9fff179380)
1*e51878c1SAndroid Build Coastguard Worker // Copyright (C) 2021 The Android Open Source Project
2*e51878c1SAndroid Build Coastguard Worker //
3*e51878c1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e51878c1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e51878c1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e51878c1SAndroid Build Coastguard Worker //
7*e51878c1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*e51878c1SAndroid Build Coastguard Worker //
9*e51878c1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e51878c1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e51878c1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e51878c1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e51878c1SAndroid Build Coastguard Worker // limitations under the License.
14*e51878c1SAndroid Build Coastguard Worker 
15*e51878c1SAndroid Build Coastguard Worker //! This crate provides the PropertyWatcher type, which watches for changes
16*e51878c1SAndroid Build Coastguard Worker //! in Android system properties.
17*e51878c1SAndroid Build Coastguard Worker 
18*e51878c1SAndroid Build Coastguard Worker // Temporary public re-export to avoid breaking dependents.
19*e51878c1SAndroid Build Coastguard Worker pub use self::error::{PropertyWatcherError, Result};
20*e51878c1SAndroid Build Coastguard Worker use anyhow::Context;
21*e51878c1SAndroid Build Coastguard Worker use libc::timespec;
22*e51878c1SAndroid Build Coastguard Worker use std::os::raw::c_char;
23*e51878c1SAndroid Build Coastguard Worker use std::ptr::null;
24*e51878c1SAndroid Build Coastguard Worker use std::{
25*e51878c1SAndroid Build Coastguard Worker     ffi::{c_uint, c_void, CStr, CString},
26*e51878c1SAndroid Build Coastguard Worker     time::{Duration, Instant},
27*e51878c1SAndroid Build Coastguard Worker };
28*e51878c1SAndroid Build Coastguard Worker use system_properties_bindgen::prop_info as PropInfo;
29*e51878c1SAndroid Build Coastguard Worker 
30*e51878c1SAndroid Build Coastguard Worker pub mod error;
31*e51878c1SAndroid Build Coastguard Worker #[doc(hidden)]
32*e51878c1SAndroid Build Coastguard Worker pub mod parsers_formatters;
33*e51878c1SAndroid Build Coastguard Worker 
34*e51878c1SAndroid Build Coastguard Worker /// PropertyWatcher takes the name of an Android system property such
35*e51878c1SAndroid Build Coastguard Worker /// as `keystore.boot_level`; it can report the current value of this
36*e51878c1SAndroid Build Coastguard Worker /// property, or wait for it to change.
37*e51878c1SAndroid Build Coastguard Worker pub struct PropertyWatcher {
38*e51878c1SAndroid Build Coastguard Worker     prop_name: CString,
39*e51878c1SAndroid Build Coastguard Worker     prop_info: Option<&'static PropInfo>,
40*e51878c1SAndroid Build Coastguard Worker     serial: c_uint,
41*e51878c1SAndroid Build Coastguard Worker }
42*e51878c1SAndroid Build Coastguard Worker 
43*e51878c1SAndroid Build Coastguard Worker impl PropertyWatcher {
44*e51878c1SAndroid Build Coastguard Worker     /// Create a PropertyWatcher for the named system property.
new(name: &str) -> Result<Self>45*e51878c1SAndroid Build Coastguard Worker     pub fn new(name: &str) -> Result<Self> {
46*e51878c1SAndroid Build Coastguard Worker         Ok(Self { prop_name: CString::new(name)?, prop_info: None, serial: 0 })
47*e51878c1SAndroid Build Coastguard Worker     }
48*e51878c1SAndroid Build Coastguard Worker 
49*e51878c1SAndroid Build Coastguard Worker     // Lazy-initializing accessor for self.prop_info.
get_prop_info(&mut self) -> Option<&'static PropInfo>50*e51878c1SAndroid Build Coastguard Worker     fn get_prop_info(&mut self) -> Option<&'static PropInfo> {
51*e51878c1SAndroid Build Coastguard Worker         if self.prop_info.is_none() {
52*e51878c1SAndroid Build Coastguard Worker             // SAFETY: Input and output are both const. The returned pointer is valid for the
53*e51878c1SAndroid Build Coastguard Worker             // lifetime of the program.
54*e51878c1SAndroid Build Coastguard Worker             self.prop_info = unsafe {
55*e51878c1SAndroid Build Coastguard Worker                 system_properties_bindgen::__system_property_find(self.prop_name.as_ptr()).as_ref()
56*e51878c1SAndroid Build Coastguard Worker             };
57*e51878c1SAndroid Build Coastguard Worker         }
58*e51878c1SAndroid Build Coastguard Worker         self.prop_info
59*e51878c1SAndroid Build Coastguard Worker     }
60*e51878c1SAndroid Build Coastguard Worker 
read_raw<F: FnMut(Option<&CStr>, Option<&CStr>)>(prop_info: &PropInfo, mut f: F)61*e51878c1SAndroid Build Coastguard Worker     fn read_raw<F: FnMut(Option<&CStr>, Option<&CStr>)>(prop_info: &PropInfo, mut f: F) {
62*e51878c1SAndroid Build Coastguard Worker         // Unsafe function converts values passed to us by
63*e51878c1SAndroid Build Coastguard Worker         // __system_property_read_callback to Rust form
64*e51878c1SAndroid Build Coastguard Worker         // and pass them to inner callback.
65*e51878c1SAndroid Build Coastguard Worker         unsafe extern "C" fn callback<F: FnMut(Option<&CStr>, Option<&CStr>)>(
66*e51878c1SAndroid Build Coastguard Worker             res_p: *mut c_void,
67*e51878c1SAndroid Build Coastguard Worker             name: *const c_char,
68*e51878c1SAndroid Build Coastguard Worker             value: *const c_char,
69*e51878c1SAndroid Build Coastguard Worker             _: c_uint,
70*e51878c1SAndroid Build Coastguard Worker         ) {
71*e51878c1SAndroid Build Coastguard Worker             let name = if name.is_null() {
72*e51878c1SAndroid Build Coastguard Worker                 None
73*e51878c1SAndroid Build Coastguard Worker             } else {
74*e51878c1SAndroid Build Coastguard Worker                 // SAFETY: system property names are null-terminated C strings in UTF-8. See
75*e51878c1SAndroid Build Coastguard Worker                 // IsLegalPropertyName in system/core/init/util.cpp.
76*e51878c1SAndroid Build Coastguard Worker                 Some(unsafe { CStr::from_ptr(name) })
77*e51878c1SAndroid Build Coastguard Worker             };
78*e51878c1SAndroid Build Coastguard Worker             let value = if value.is_null() {
79*e51878c1SAndroid Build Coastguard Worker                 None
80*e51878c1SAndroid Build Coastguard Worker             } else {
81*e51878c1SAndroid Build Coastguard Worker                 // SAFETY: system property values are null-terminated C strings in UTF-8. See
82*e51878c1SAndroid Build Coastguard Worker                 // IsLegalPropertyValue in system/core/init/util.cpp.
83*e51878c1SAndroid Build Coastguard Worker                 Some(unsafe { CStr::from_ptr(value) })
84*e51878c1SAndroid Build Coastguard Worker             };
85*e51878c1SAndroid Build Coastguard Worker             // SAFETY: We converted the FnMut from `F` to a void pointer below, now we convert it
86*e51878c1SAndroid Build Coastguard Worker             // back.
87*e51878c1SAndroid Build Coastguard Worker             let f = unsafe { &mut *res_p.cast::<F>() };
88*e51878c1SAndroid Build Coastguard Worker             f(name, value);
89*e51878c1SAndroid Build Coastguard Worker         }
90*e51878c1SAndroid Build Coastguard Worker 
91*e51878c1SAndroid Build Coastguard Worker         // SAFETY: We convert the FnMut to a void pointer, and unwrap it in our callback.
92*e51878c1SAndroid Build Coastguard Worker         unsafe {
93*e51878c1SAndroid Build Coastguard Worker             system_properties_bindgen::__system_property_read_callback(
94*e51878c1SAndroid Build Coastguard Worker                 prop_info,
95*e51878c1SAndroid Build Coastguard Worker                 Some(callback::<F>),
96*e51878c1SAndroid Build Coastguard Worker                 &mut f as *mut F as *mut c_void,
97*e51878c1SAndroid Build Coastguard Worker             )
98*e51878c1SAndroid Build Coastguard Worker         }
99*e51878c1SAndroid Build Coastguard Worker     }
100*e51878c1SAndroid Build Coastguard Worker 
101*e51878c1SAndroid Build Coastguard Worker     /// Call the passed function, passing it the name and current value
102*e51878c1SAndroid Build Coastguard Worker     /// of this system property. See documentation for
103*e51878c1SAndroid Build Coastguard Worker     /// `__system_property_read_callback` for details.
104*e51878c1SAndroid Build Coastguard Worker     /// Returns an error if the property is empty or doesn't exist.
read<T, F>(&mut self, mut f: F) -> Result<T> where F: FnMut(&str, &str) -> anyhow::Result<T>,105*e51878c1SAndroid Build Coastguard Worker     pub fn read<T, F>(&mut self, mut f: F) -> Result<T>
106*e51878c1SAndroid Build Coastguard Worker     where
107*e51878c1SAndroid Build Coastguard Worker         F: FnMut(&str, &str) -> anyhow::Result<T>,
108*e51878c1SAndroid Build Coastguard Worker     {
109*e51878c1SAndroid Build Coastguard Worker         let prop_info = self.get_prop_info().ok_or(PropertyWatcherError::SystemPropertyAbsent)?;
110*e51878c1SAndroid Build Coastguard Worker         let mut result = Err(PropertyWatcherError::ReadCallbackNotCalled);
111*e51878c1SAndroid Build Coastguard Worker         Self::read_raw(prop_info, |name, value| {
112*e51878c1SAndroid Build Coastguard Worker             // use a wrapping closure as an erzatz try block.
113*e51878c1SAndroid Build Coastguard Worker             result = (|| {
114*e51878c1SAndroid Build Coastguard Worker                 let name = name.ok_or(PropertyWatcherError::MissingCString)?.to_str()?;
115*e51878c1SAndroid Build Coastguard Worker                 let value = value.ok_or(PropertyWatcherError::MissingCString)?.to_str()?;
116*e51878c1SAndroid Build Coastguard Worker                 f(name, value).map_err(PropertyWatcherError::CallbackError)
117*e51878c1SAndroid Build Coastguard Worker             })()
118*e51878c1SAndroid Build Coastguard Worker         });
119*e51878c1SAndroid Build Coastguard Worker         result
120*e51878c1SAndroid Build Coastguard Worker     }
121*e51878c1SAndroid Build Coastguard Worker 
122*e51878c1SAndroid Build Coastguard Worker     // Waits for the property that self is watching to be created. Returns immediately if the
123*e51878c1SAndroid Build Coastguard Worker     // property already exists.
wait_for_property_creation_until(&mut self, until: Option<Instant>) -> Result<()>124*e51878c1SAndroid Build Coastguard Worker     fn wait_for_property_creation_until(&mut self, until: Option<Instant>) -> Result<()> {
125*e51878c1SAndroid Build Coastguard Worker         let mut global_serial = 0;
126*e51878c1SAndroid Build Coastguard Worker         loop {
127*e51878c1SAndroid Build Coastguard Worker             match self.get_prop_info() {
128*e51878c1SAndroid Build Coastguard Worker                 Some(_) => return Ok(()),
129*e51878c1SAndroid Build Coastguard Worker                 None => {
130*e51878c1SAndroid Build Coastguard Worker                     let remaining_timeout = remaining_time_until(until);
131*e51878c1SAndroid Build Coastguard Worker                     // SAFETY: The function modifies only global_serial, and has no side-effects.
132*e51878c1SAndroid Build Coastguard Worker                     if !unsafe {
133*e51878c1SAndroid Build Coastguard Worker                         // Wait for a global serial number change, then try again. On success,
134*e51878c1SAndroid Build Coastguard Worker                         // the function will update global_serial with the last version seen.
135*e51878c1SAndroid Build Coastguard Worker                         system_properties_bindgen::__system_property_wait(
136*e51878c1SAndroid Build Coastguard Worker                             null(),
137*e51878c1SAndroid Build Coastguard Worker                             global_serial,
138*e51878c1SAndroid Build Coastguard Worker                             &mut global_serial,
139*e51878c1SAndroid Build Coastguard Worker                             if let Some(remaining_timeout) = &remaining_timeout {
140*e51878c1SAndroid Build Coastguard Worker                                 remaining_timeout
141*e51878c1SAndroid Build Coastguard Worker                             } else {
142*e51878c1SAndroid Build Coastguard Worker                                 null()
143*e51878c1SAndroid Build Coastguard Worker                             },
144*e51878c1SAndroid Build Coastguard Worker                         )
145*e51878c1SAndroid Build Coastguard Worker                     } {
146*e51878c1SAndroid Build Coastguard Worker                         return Err(PropertyWatcherError::WaitFailed);
147*e51878c1SAndroid Build Coastguard Worker                     }
148*e51878c1SAndroid Build Coastguard Worker                 }
149*e51878c1SAndroid Build Coastguard Worker             }
150*e51878c1SAndroid Build Coastguard Worker         }
151*e51878c1SAndroid Build Coastguard Worker     }
152*e51878c1SAndroid Build Coastguard Worker 
153*e51878c1SAndroid Build Coastguard Worker     /// Waits until the system property changes, or `until` is reached.
154*e51878c1SAndroid Build Coastguard Worker     ///
155*e51878c1SAndroid Build Coastguard Worker     /// This records the serial number of the last change, so race conditions are avoided.
wait_for_property_change_until(&mut self, until: Option<Instant>) -> Result<()>156*e51878c1SAndroid Build Coastguard Worker     fn wait_for_property_change_until(&mut self, until: Option<Instant>) -> Result<()> {
157*e51878c1SAndroid Build Coastguard Worker         // If the property is None, then wait for it to be created. Subsequent waits will
158*e51878c1SAndroid Build Coastguard Worker         // skip this step and wait for our specific property to change.
159*e51878c1SAndroid Build Coastguard Worker         if self.prop_info.is_none() {
160*e51878c1SAndroid Build Coastguard Worker             return self.wait_for_property_creation_until(None);
161*e51878c1SAndroid Build Coastguard Worker         }
162*e51878c1SAndroid Build Coastguard Worker 
163*e51878c1SAndroid Build Coastguard Worker         let remaining_timeout = remaining_time_until(until);
164*e51878c1SAndroid Build Coastguard Worker         let mut new_serial = self.serial;
165*e51878c1SAndroid Build Coastguard Worker         // SAFETY: All arguments are private to PropertyWatcher so we can be confident they are
166*e51878c1SAndroid Build Coastguard Worker         // valid.
167*e51878c1SAndroid Build Coastguard Worker         if !unsafe {
168*e51878c1SAndroid Build Coastguard Worker             system_properties_bindgen::__system_property_wait(
169*e51878c1SAndroid Build Coastguard Worker                 match self.prop_info {
170*e51878c1SAndroid Build Coastguard Worker                     Some(p) => p,
171*e51878c1SAndroid Build Coastguard Worker                     None => null(),
172*e51878c1SAndroid Build Coastguard Worker                 },
173*e51878c1SAndroid Build Coastguard Worker                 self.serial,
174*e51878c1SAndroid Build Coastguard Worker                 &mut new_serial,
175*e51878c1SAndroid Build Coastguard Worker                 if let Some(remaining_timeout) = &remaining_timeout {
176*e51878c1SAndroid Build Coastguard Worker                     remaining_timeout
177*e51878c1SAndroid Build Coastguard Worker                 } else {
178*e51878c1SAndroid Build Coastguard Worker                     null()
179*e51878c1SAndroid Build Coastguard Worker                 },
180*e51878c1SAndroid Build Coastguard Worker             )
181*e51878c1SAndroid Build Coastguard Worker         } {
182*e51878c1SAndroid Build Coastguard Worker             return Err(PropertyWatcherError::WaitFailed);
183*e51878c1SAndroid Build Coastguard Worker         }
184*e51878c1SAndroid Build Coastguard Worker         self.serial = new_serial;
185*e51878c1SAndroid Build Coastguard Worker         Ok(())
186*e51878c1SAndroid Build Coastguard Worker     }
187*e51878c1SAndroid Build Coastguard Worker 
188*e51878c1SAndroid Build Coastguard Worker     /// Waits for the system property to change, or the timeout to elapse.
189*e51878c1SAndroid Build Coastguard Worker     ///
190*e51878c1SAndroid Build Coastguard Worker     /// This records the serial number of the last change, so race conditions are avoided.
wait(&mut self, timeout: Option<Duration>) -> Result<()>191*e51878c1SAndroid Build Coastguard Worker     pub fn wait(&mut self, timeout: Option<Duration>) -> Result<()> {
192*e51878c1SAndroid Build Coastguard Worker         let until = timeout.map(|timeout| Instant::now() + timeout);
193*e51878c1SAndroid Build Coastguard Worker         self.wait_for_property_change_until(until)
194*e51878c1SAndroid Build Coastguard Worker     }
195*e51878c1SAndroid Build Coastguard Worker 
196*e51878c1SAndroid Build Coastguard Worker     /// Waits until the property exists and has the given value.
wait_for_value( &mut self, expected_value: &str, timeout: Option<Duration>, ) -> Result<()>197*e51878c1SAndroid Build Coastguard Worker     pub fn wait_for_value(
198*e51878c1SAndroid Build Coastguard Worker         &mut self,
199*e51878c1SAndroid Build Coastguard Worker         expected_value: &str,
200*e51878c1SAndroid Build Coastguard Worker         timeout: Option<Duration>,
201*e51878c1SAndroid Build Coastguard Worker     ) -> Result<()> {
202*e51878c1SAndroid Build Coastguard Worker         let until = timeout.map(|timeout| Instant::now() + timeout);
203*e51878c1SAndroid Build Coastguard Worker 
204*e51878c1SAndroid Build Coastguard Worker         self.wait_for_property_creation_until(until)?;
205*e51878c1SAndroid Build Coastguard Worker 
206*e51878c1SAndroid Build Coastguard Worker         while self.read(|_, value| Ok(value != expected_value))? {
207*e51878c1SAndroid Build Coastguard Worker             self.wait_for_property_change_until(until)?;
208*e51878c1SAndroid Build Coastguard Worker         }
209*e51878c1SAndroid Build Coastguard Worker 
210*e51878c1SAndroid Build Coastguard Worker         Ok(())
211*e51878c1SAndroid Build Coastguard Worker     }
212*e51878c1SAndroid Build Coastguard Worker }
213*e51878c1SAndroid Build Coastguard Worker 
214*e51878c1SAndroid Build Coastguard Worker /// Reads a system property.
215*e51878c1SAndroid Build Coastguard Worker ///
216*e51878c1SAndroid Build Coastguard Worker /// Returns `Ok(None)` if the property doesn't exist.
read(name: &str) -> Result<Option<String>>217*e51878c1SAndroid Build Coastguard Worker pub fn read(name: &str) -> Result<Option<String>> {
218*e51878c1SAndroid Build Coastguard Worker     match PropertyWatcher::new(name)?.read(|_name, value| Ok(value.to_owned())) {
219*e51878c1SAndroid Build Coastguard Worker         Ok(value) => Ok(Some(value)),
220*e51878c1SAndroid Build Coastguard Worker         Err(PropertyWatcherError::SystemPropertyAbsent) => Ok(None),
221*e51878c1SAndroid Build Coastguard Worker         Err(e) => Err(e),
222*e51878c1SAndroid Build Coastguard Worker     }
223*e51878c1SAndroid Build Coastguard Worker }
224*e51878c1SAndroid Build Coastguard Worker 
parse_bool(value: &str) -> Option<bool>225*e51878c1SAndroid Build Coastguard Worker fn parse_bool(value: &str) -> Option<bool> {
226*e51878c1SAndroid Build Coastguard Worker     match value {
227*e51878c1SAndroid Build Coastguard Worker         "1" | "y" | "yes" | "on" | "true" => Some(true),
228*e51878c1SAndroid Build Coastguard Worker         "0" | "n" | "no" | "off" | "false" => Some(false),
229*e51878c1SAndroid Build Coastguard Worker         _ => None,
230*e51878c1SAndroid Build Coastguard Worker     }
231*e51878c1SAndroid Build Coastguard Worker }
232*e51878c1SAndroid Build Coastguard Worker 
233*e51878c1SAndroid Build Coastguard Worker /// Returns the duration remaining until the given instant.
234*e51878c1SAndroid Build Coastguard Worker ///
235*e51878c1SAndroid Build Coastguard Worker /// Returns `None` if `None` is passed in, or `Some(0)` if `until` is in the past.
remaining_time_until(until: Option<Instant>) -> Option<timespec>236*e51878c1SAndroid Build Coastguard Worker fn remaining_time_until(until: Option<Instant>) -> Option<timespec> {
237*e51878c1SAndroid Build Coastguard Worker     until.map(|until| {
238*e51878c1SAndroid Build Coastguard Worker         duration_to_timespec(until.checked_duration_since(Instant::now()).unwrap_or_default())
239*e51878c1SAndroid Build Coastguard Worker     })
240*e51878c1SAndroid Build Coastguard Worker }
241*e51878c1SAndroid Build Coastguard Worker 
242*e51878c1SAndroid Build Coastguard Worker /// Converts the given `Duration` to a C `timespec`.
duration_to_timespec(duration: Duration) -> timespec243*e51878c1SAndroid Build Coastguard Worker fn duration_to_timespec(duration: Duration) -> timespec {
244*e51878c1SAndroid Build Coastguard Worker     timespec {
245*e51878c1SAndroid Build Coastguard Worker         tv_sec: duration.as_secs().try_into().unwrap(),
246*e51878c1SAndroid Build Coastguard Worker         tv_nsec: duration.subsec_nanos() as _,
247*e51878c1SAndroid Build Coastguard Worker     }
248*e51878c1SAndroid Build Coastguard Worker }
249*e51878c1SAndroid Build Coastguard Worker 
250*e51878c1SAndroid Build Coastguard Worker /// Returns true if the system property `name` has the value "1", "y", "yes", "on", or "true",
251*e51878c1SAndroid Build Coastguard Worker /// false for "0", "n", "no", "off", or "false", or `default_value` otherwise.
read_bool(name: &str, default_value: bool) -> Result<bool>252*e51878c1SAndroid Build Coastguard Worker pub fn read_bool(name: &str, default_value: bool) -> Result<bool> {
253*e51878c1SAndroid Build Coastguard Worker     Ok(read(name)?.as_deref().and_then(parse_bool).unwrap_or(default_value))
254*e51878c1SAndroid Build Coastguard Worker }
255*e51878c1SAndroid Build Coastguard Worker 
256*e51878c1SAndroid Build Coastguard Worker /// Writes a system property.
write(name: &str, value: &str) -> Result<()>257*e51878c1SAndroid Build Coastguard Worker pub fn write(name: &str, value: &str) -> Result<()> {
258*e51878c1SAndroid Build Coastguard Worker     if
259*e51878c1SAndroid Build Coastguard Worker     // SAFETY: Input and output are both const and valid strings.
260*e51878c1SAndroid Build Coastguard Worker     unsafe {
261*e51878c1SAndroid Build Coastguard Worker         // If successful, __system_property_set returns 0, otherwise, returns -1.
262*e51878c1SAndroid Build Coastguard Worker         system_properties_bindgen::__system_property_set(
263*e51878c1SAndroid Build Coastguard Worker             CString::new(name).context("Failed to construct CString from name.")?.as_ptr(),
264*e51878c1SAndroid Build Coastguard Worker             CString::new(value).context("Failed to construct CString from value.")?.as_ptr(),
265*e51878c1SAndroid Build Coastguard Worker         )
266*e51878c1SAndroid Build Coastguard Worker     } == 0
267*e51878c1SAndroid Build Coastguard Worker     {
268*e51878c1SAndroid Build Coastguard Worker         Ok(())
269*e51878c1SAndroid Build Coastguard Worker     } else {
270*e51878c1SAndroid Build Coastguard Worker         Err(PropertyWatcherError::SetPropertyFailed)
271*e51878c1SAndroid Build Coastguard Worker     }
272*e51878c1SAndroid Build Coastguard Worker }
273*e51878c1SAndroid Build Coastguard Worker 
274*e51878c1SAndroid Build Coastguard Worker /// Iterates through the properties (that the current process is allowed to access).
foreach<F>(mut f: F) -> Result<()> where F: FnMut(&str, &str),275*e51878c1SAndroid Build Coastguard Worker pub fn foreach<F>(mut f: F) -> Result<()>
276*e51878c1SAndroid Build Coastguard Worker where
277*e51878c1SAndroid Build Coastguard Worker     F: FnMut(&str, &str),
278*e51878c1SAndroid Build Coastguard Worker {
279*e51878c1SAndroid Build Coastguard Worker     extern "C" fn read_callback<F: FnMut(&str, &str)>(
280*e51878c1SAndroid Build Coastguard Worker         res_p: *mut c_void,
281*e51878c1SAndroid Build Coastguard Worker         name: *const c_char,
282*e51878c1SAndroid Build Coastguard Worker         value: *const c_char,
283*e51878c1SAndroid Build Coastguard Worker         _: c_uint,
284*e51878c1SAndroid Build Coastguard Worker     ) {
285*e51878c1SAndroid Build Coastguard Worker         // SAFETY: system property names are null-terminated C strings in UTF-8. See
286*e51878c1SAndroid Build Coastguard Worker         // IsLegalPropertyName in system/core/init/util.cpp.
287*e51878c1SAndroid Build Coastguard Worker         let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
288*e51878c1SAndroid Build Coastguard Worker         // SAFETY: system property values are null-terminated C strings in UTF-8. See
289*e51878c1SAndroid Build Coastguard Worker         // IsLegalPropertyValue in system/core/init/util.cpp.
290*e51878c1SAndroid Build Coastguard Worker         let value = unsafe { CStr::from_ptr(value) }.to_str().unwrap();
291*e51878c1SAndroid Build Coastguard Worker 
292*e51878c1SAndroid Build Coastguard Worker         let ptr = res_p as *mut F;
293*e51878c1SAndroid Build Coastguard Worker         // SAFETY: ptr points to the API user's callback, which was cast to `*mut c_void` below.
294*e51878c1SAndroid Build Coastguard Worker         // Here we're casting it back.
295*e51878c1SAndroid Build Coastguard Worker         let f = unsafe { ptr.as_mut() }.unwrap();
296*e51878c1SAndroid Build Coastguard Worker         f(name, value);
297*e51878c1SAndroid Build Coastguard Worker     }
298*e51878c1SAndroid Build Coastguard Worker 
299*e51878c1SAndroid Build Coastguard Worker     extern "C" fn foreach_callback<F: FnMut(&str, &str)>(
300*e51878c1SAndroid Build Coastguard Worker         prop_info: *const PropInfo,
301*e51878c1SAndroid Build Coastguard Worker         res_p: *mut c_void,
302*e51878c1SAndroid Build Coastguard Worker     ) {
303*e51878c1SAndroid Build Coastguard Worker         // SAFETY: FFI call with an internal callback function in Rust, with other parameters
304*e51878c1SAndroid Build Coastguard Worker         // passed through.
305*e51878c1SAndroid Build Coastguard Worker         unsafe {
306*e51878c1SAndroid Build Coastguard Worker             system_properties_bindgen::__system_property_read_callback(
307*e51878c1SAndroid Build Coastguard Worker                 prop_info,
308*e51878c1SAndroid Build Coastguard Worker                 Some(read_callback::<F>),
309*e51878c1SAndroid Build Coastguard Worker                 res_p,
310*e51878c1SAndroid Build Coastguard Worker             )
311*e51878c1SAndroid Build Coastguard Worker         }
312*e51878c1SAndroid Build Coastguard Worker     }
313*e51878c1SAndroid Build Coastguard Worker 
314*e51878c1SAndroid Build Coastguard Worker     // SAFETY: FFI call with an internal callback function in Rust, and another client's callback
315*e51878c1SAndroid Build Coastguard Worker     // that's cast only for our own use right above.
316*e51878c1SAndroid Build Coastguard Worker     let retval = unsafe {
317*e51878c1SAndroid Build Coastguard Worker         system_properties_bindgen::__system_property_foreach(
318*e51878c1SAndroid Build Coastguard Worker             Some(foreach_callback::<F>),
319*e51878c1SAndroid Build Coastguard Worker             &mut f as *mut F as *mut c_void,
320*e51878c1SAndroid Build Coastguard Worker         )
321*e51878c1SAndroid Build Coastguard Worker     };
322*e51878c1SAndroid Build Coastguard Worker     if retval < 0 {
323*e51878c1SAndroid Build Coastguard Worker         Err(PropertyWatcherError::Uninitialized)
324*e51878c1SAndroid Build Coastguard Worker     } else {
325*e51878c1SAndroid Build Coastguard Worker         Ok(())
326*e51878c1SAndroid Build Coastguard Worker     }
327*e51878c1SAndroid Build Coastguard Worker }
328*e51878c1SAndroid Build Coastguard Worker 
329*e51878c1SAndroid Build Coastguard Worker #[cfg(test)]
330*e51878c1SAndroid Build Coastguard Worker mod test {
331*e51878c1SAndroid Build Coastguard Worker     use super::*;
332*e51878c1SAndroid Build Coastguard Worker 
333*e51878c1SAndroid Build Coastguard Worker     #[test]
parse_bool_test()334*e51878c1SAndroid Build Coastguard Worker     fn parse_bool_test() {
335*e51878c1SAndroid Build Coastguard Worker         for s in ["1", "y", "yes", "on", "true"] {
336*e51878c1SAndroid Build Coastguard Worker             assert_eq!(parse_bool(s), Some(true), "testing with {}", s);
337*e51878c1SAndroid Build Coastguard Worker         }
338*e51878c1SAndroid Build Coastguard Worker         for s in ["0", "n", "no", "off", "false"] {
339*e51878c1SAndroid Build Coastguard Worker             assert_eq!(parse_bool(s), Some(false), "testing with {}", s);
340*e51878c1SAndroid Build Coastguard Worker         }
341*e51878c1SAndroid Build Coastguard Worker         for s in ["random", "00", "of course", "no way", "YES", "Off"] {
342*e51878c1SAndroid Build Coastguard Worker             assert_eq!(parse_bool(s), None, "testing with {}", s);
343*e51878c1SAndroid Build Coastguard Worker         }
344*e51878c1SAndroid Build Coastguard Worker     }
345*e51878c1SAndroid Build Coastguard Worker 
346*e51878c1SAndroid Build Coastguard Worker     #[test]
read_absent_bool_test()347*e51878c1SAndroid Build Coastguard Worker     fn read_absent_bool_test() {
348*e51878c1SAndroid Build Coastguard Worker         let prop = "certainly.does.not.exist";
349*e51878c1SAndroid Build Coastguard Worker         assert!(matches!(read(prop), Ok(None)));
350*e51878c1SAndroid Build Coastguard Worker         assert!(read_bool(prop, true).unwrap_or(false));
351*e51878c1SAndroid Build Coastguard Worker         assert!(!read_bool(prop, false).unwrap_or(true));
352*e51878c1SAndroid Build Coastguard Worker     }
353*e51878c1SAndroid Build Coastguard Worker 
354*e51878c1SAndroid Build Coastguard Worker     #[test]
foreach_test()355*e51878c1SAndroid Build Coastguard Worker     fn foreach_test() {
356*e51878c1SAndroid Build Coastguard Worker         let mut properties = Vec::new();
357*e51878c1SAndroid Build Coastguard Worker         assert!(foreach(|name, value| {
358*e51878c1SAndroid Build Coastguard Worker             properties.push((name.to_owned(), value.to_owned()));
359*e51878c1SAndroid Build Coastguard Worker         })
360*e51878c1SAndroid Build Coastguard Worker         .is_ok());
361*e51878c1SAndroid Build Coastguard Worker         // Assuming the test runs on Android, any process can at least see some system properties.
362*e51878c1SAndroid Build Coastguard Worker         assert!(!properties.is_empty());
363*e51878c1SAndroid Build Coastguard Worker     }
364*e51878c1SAndroid Build Coastguard Worker }
365