xref: /aosp_15_r20/external/crosvm/crosvm_control/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2021 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Provides parts of crosvm as a library to communicate with running crosvm instances.
6*bb4ee6a4SAndroid Build Coastguard Worker //!
7*bb4ee6a4SAndroid Build Coastguard Worker //! This crate is a programmatic alternative to invoking crosvm with subcommands that produce the
8*bb4ee6a4SAndroid Build Coastguard Worker //! result on stdout.
9*bb4ee6a4SAndroid Build Coastguard Worker //!
10*bb4ee6a4SAndroid Build Coastguard Worker //! Downstream projects rely on this library maintaining a stable API surface.
11*bb4ee6a4SAndroid Build Coastguard Worker //! Do not make changes to this library without consulting the crosvm externalization team.
12*bb4ee6a4SAndroid Build Coastguard Worker //! Email: <[email protected]>
13*bb4ee6a4SAndroid Build Coastguard Worker //!
14*bb4ee6a4SAndroid Build Coastguard Worker //! The API of this library should remain the same regardless of which crosvm features are enabled.
15*bb4ee6a4SAndroid Build Coastguard Worker //! Any missing functionality should be handled by returning an error at runtime, not conditional
16*bb4ee6a4SAndroid Build Coastguard Worker //! compilation, so that users can rely on the the same set of functions with the same prototypes
17*bb4ee6a4SAndroid Build Coastguard Worker //! regardless of how crosvm is configured.
18*bb4ee6a4SAndroid Build Coastguard Worker //!
19*bb4ee6a4SAndroid Build Coastguard Worker //! For more information see:
20*bb4ee6a4SAndroid Build Coastguard Worker //! <https://crosvm.dev/book/running_crosvm/programmatic_interaction.html#usage>
21*bb4ee6a4SAndroid Build Coastguard Worker 
22*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryFrom;
23*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto;
24*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::CStr;
25*bb4ee6a4SAndroid Build Coastguard Worker use std::panic::catch_unwind;
26*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
27*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
28*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonStats;
31*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonWS;
32*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::WSBucket;
33*bb4ee6a4SAndroid Build Coastguard Worker use libc::c_char;
34*bb4ee6a4SAndroid Build Coastguard Worker use libc::ssize_t;
35*bb4ee6a4SAndroid Build Coastguard Worker pub use swap::SwapStatus;
36*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::do_modify_battery;
37*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::do_net_add;
38*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::do_net_remove;
39*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::do_security_key_attach;
40*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::do_usb_attach;
41*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::do_usb_detach;
42*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::do_usb_list;
43*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::handle_request;
44*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::handle_request_with_timeout;
45*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::client::vms_request;
46*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::BalloonControlCommand;
47*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::BatProperty;
48*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::DiskControlCommand;
49*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::RegisteredEvent;
50*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::SwapCommand;
51*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::UsbControlAttachedDevice;
52*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::UsbControlResult;
53*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmRequest;
54*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmResponse;
55*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::USB_CONTROL_MAX_PORTS;
56*bb4ee6a4SAndroid Build Coastguard Worker 
57*bb4ee6a4SAndroid Build Coastguard Worker pub const VIRTIO_BALLOON_WS_MAX_NUM_BINS: usize = 16;
58*bb4ee6a4SAndroid Build Coastguard Worker pub const VIRTIO_BALLOON_WS_MAX_NUM_INTERVALS: usize = 15;
59*bb4ee6a4SAndroid Build Coastguard Worker 
60*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
61*bb4ee6a4SAndroid Build Coastguard Worker ///
62*bb4ee6a4SAndroid Build Coastguard Worker /// This function is safe when the caller ensures the socket_path raw pointer can be safely passed
63*bb4ee6a4SAndroid Build Coastguard Worker /// to `CStr::from_ptr()`.
validate_socket_path(socket_path: *const c_char) -> Option<PathBuf>64*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn validate_socket_path(socket_path: *const c_char) -> Option<PathBuf> {
65*bb4ee6a4SAndroid Build Coastguard Worker     if !socket_path.is_null() {
66*bb4ee6a4SAndroid Build Coastguard Worker         let socket_path = CStr::from_ptr(socket_path);
67*bb4ee6a4SAndroid Build Coastguard Worker         Some(PathBuf::from(socket_path.to_str().ok()?))
68*bb4ee6a4SAndroid Build Coastguard Worker     } else {
69*bb4ee6a4SAndroid Build Coastguard Worker         None
70*bb4ee6a4SAndroid Build Coastguard Worker     }
71*bb4ee6a4SAndroid Build Coastguard Worker }
72*bb4ee6a4SAndroid Build Coastguard Worker 
73*bb4ee6a4SAndroid Build Coastguard Worker /// Stops the crosvm instance whose control socket is listening on `socket_path`.
74*bb4ee6a4SAndroid Build Coastguard Worker ///
75*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
76*bb4ee6a4SAndroid Build Coastguard Worker ///
77*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
78*bb4ee6a4SAndroid Build Coastguard Worker ///
79*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
80*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
81*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
82*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_stop_vm(socket_path: *const c_char) -> bool83*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_stop_vm(socket_path: *const c_char) -> bool {
84*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
85*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
86*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::Exit, socket_path).is_ok()
87*bb4ee6a4SAndroid Build Coastguard Worker         } else {
88*bb4ee6a4SAndroid Build Coastguard Worker             false
89*bb4ee6a4SAndroid Build Coastguard Worker         }
90*bb4ee6a4SAndroid Build Coastguard Worker     })
91*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
92*bb4ee6a4SAndroid Build Coastguard Worker }
93*bb4ee6a4SAndroid Build Coastguard Worker 
94*bb4ee6a4SAndroid Build Coastguard Worker /// Suspends the crosvm instance whose control socket is listening on `socket_path`.
95*bb4ee6a4SAndroid Build Coastguard Worker ///
96*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
97*bb4ee6a4SAndroid Build Coastguard Worker ///
98*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
99*bb4ee6a4SAndroid Build Coastguard Worker ///
100*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
101*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
102*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
103*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_suspend_vm(socket_path: *const c_char) -> bool104*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_suspend_vm(socket_path: *const c_char) -> bool {
105*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
106*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
107*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::SuspendVcpus, socket_path).is_ok()
108*bb4ee6a4SAndroid Build Coastguard Worker         } else {
109*bb4ee6a4SAndroid Build Coastguard Worker             false
110*bb4ee6a4SAndroid Build Coastguard Worker         }
111*bb4ee6a4SAndroid Build Coastguard Worker     })
112*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
113*bb4ee6a4SAndroid Build Coastguard Worker }
114*bb4ee6a4SAndroid Build Coastguard Worker 
115*bb4ee6a4SAndroid Build Coastguard Worker /// Resumes the crosvm instance whose control socket is listening on `socket_path`.
116*bb4ee6a4SAndroid Build Coastguard Worker ///
117*bb4ee6a4SAndroid Build Coastguard Worker /// Note: this function just resumes vcpus of the vm. If you need to perform a full resume, call
118*bb4ee6a4SAndroid Build Coastguard Worker /// crosvm_client_resume_vm_full.
119*bb4ee6a4SAndroid Build Coastguard Worker ///
120*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
121*bb4ee6a4SAndroid Build Coastguard Worker ///
122*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
123*bb4ee6a4SAndroid Build Coastguard Worker ///
124*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
125*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
126*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
127*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_resume_vm(socket_path: *const c_char) -> bool128*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_resume_vm(socket_path: *const c_char) -> bool {
129*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
130*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
131*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::ResumeVcpus, socket_path).is_ok()
132*bb4ee6a4SAndroid Build Coastguard Worker         } else {
133*bb4ee6a4SAndroid Build Coastguard Worker             false
134*bb4ee6a4SAndroid Build Coastguard Worker         }
135*bb4ee6a4SAndroid Build Coastguard Worker     })
136*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
137*bb4ee6a4SAndroid Build Coastguard Worker }
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker /// Resumes the crosvm instance whose control socket is listening on `socket_path`.
140*bb4ee6a4SAndroid Build Coastguard Worker ///
141*bb4ee6a4SAndroid Build Coastguard Worker /// Note: unlike crosvm_client_resume_vm, this function resumes both vcpus and devices.
142*bb4ee6a4SAndroid Build Coastguard Worker ///
143*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
144*bb4ee6a4SAndroid Build Coastguard Worker ///
145*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
146*bb4ee6a4SAndroid Build Coastguard Worker ///
147*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
148*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
149*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
150*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_resume_vm_full(socket_path: *const c_char) -> bool151*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_resume_vm_full(socket_path: *const c_char) -> bool {
152*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
153*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
154*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::ResumeVm, socket_path).is_ok()
155*bb4ee6a4SAndroid Build Coastguard Worker         } else {
156*bb4ee6a4SAndroid Build Coastguard Worker             false
157*bb4ee6a4SAndroid Build Coastguard Worker         }
158*bb4ee6a4SAndroid Build Coastguard Worker     })
159*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
160*bb4ee6a4SAndroid Build Coastguard Worker }
161*bb4ee6a4SAndroid Build Coastguard Worker 
162*bb4ee6a4SAndroid Build Coastguard Worker /// Creates an RT vCPU for the crosvm instance whose control socket is listening on `socket_path`.
163*bb4ee6a4SAndroid Build Coastguard Worker ///
164*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
165*bb4ee6a4SAndroid Build Coastguard Worker ///
166*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
167*bb4ee6a4SAndroid Build Coastguard Worker ///
168*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
169*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
170*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
171*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_make_rt_vm(socket_path: *const c_char) -> bool172*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_make_rt_vm(socket_path: *const c_char) -> bool {
173*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
174*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
175*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::MakeRT, socket_path).is_ok()
176*bb4ee6a4SAndroid Build Coastguard Worker         } else {
177*bb4ee6a4SAndroid Build Coastguard Worker             false
178*bb4ee6a4SAndroid Build Coastguard Worker         }
179*bb4ee6a4SAndroid Build Coastguard Worker     })
180*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
181*bb4ee6a4SAndroid Build Coastguard Worker }
182*bb4ee6a4SAndroid Build Coastguard Worker 
183*bb4ee6a4SAndroid Build Coastguard Worker /// Adjusts the balloon size of the crosvm instance whose control socket is
184*bb4ee6a4SAndroid Build Coastguard Worker /// listening on `socket_path`.
185*bb4ee6a4SAndroid Build Coastguard Worker ///
186*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
187*bb4ee6a4SAndroid Build Coastguard Worker ///
188*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
189*bb4ee6a4SAndroid Build Coastguard Worker ///
190*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
191*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
192*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
193*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_balloon_vms( socket_path: *const c_char, num_bytes: u64, ) -> bool194*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_balloon_vms(
195*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
196*bb4ee6a4SAndroid Build Coastguard Worker     num_bytes: u64,
197*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
198*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
199*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
200*bb4ee6a4SAndroid Build Coastguard Worker             let command = BalloonControlCommand::Adjust {
201*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes,
202*bb4ee6a4SAndroid Build Coastguard Worker                 wait_for_success: false,
203*bb4ee6a4SAndroid Build Coastguard Worker             };
204*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::BalloonCommand(command), socket_path).is_ok()
205*bb4ee6a4SAndroid Build Coastguard Worker         } else {
206*bb4ee6a4SAndroid Build Coastguard Worker             false
207*bb4ee6a4SAndroid Build Coastguard Worker         }
208*bb4ee6a4SAndroid Build Coastguard Worker     })
209*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
210*bb4ee6a4SAndroid Build Coastguard Worker }
211*bb4ee6a4SAndroid Build Coastguard Worker 
212*bb4ee6a4SAndroid Build Coastguard Worker /// See crosvm_client_balloon_vms.
213*bb4ee6a4SAndroid Build Coastguard Worker ///
214*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
215*bb4ee6a4SAndroid Build Coastguard Worker ///
216*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
217*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
218*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
219*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_balloon_vms_wait_with_timeout( socket_path: *const c_char, num_bytes: u64, timeout_ms: u64, ) -> bool220*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_balloon_vms_wait_with_timeout(
221*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
222*bb4ee6a4SAndroid Build Coastguard Worker     num_bytes: u64,
223*bb4ee6a4SAndroid Build Coastguard Worker     timeout_ms: u64,
224*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
225*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
226*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
227*bb4ee6a4SAndroid Build Coastguard Worker             let command = BalloonControlCommand::Adjust {
228*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes,
229*bb4ee6a4SAndroid Build Coastguard Worker                 wait_for_success: true,
230*bb4ee6a4SAndroid Build Coastguard Worker             };
231*bb4ee6a4SAndroid Build Coastguard Worker             let resp = handle_request_with_timeout(
232*bb4ee6a4SAndroid Build Coastguard Worker                 &VmRequest::BalloonCommand(command),
233*bb4ee6a4SAndroid Build Coastguard Worker                 socket_path,
234*bb4ee6a4SAndroid Build Coastguard Worker                 Some(Duration::from_millis(timeout_ms)),
235*bb4ee6a4SAndroid Build Coastguard Worker             );
236*bb4ee6a4SAndroid Build Coastguard Worker             if matches!(resp, Ok(VmResponse::Ok)) {
237*bb4ee6a4SAndroid Build Coastguard Worker                 return true;
238*bb4ee6a4SAndroid Build Coastguard Worker             }
239*bb4ee6a4SAndroid Build Coastguard Worker             println!("adjust failure: {:?}", resp);
240*bb4ee6a4SAndroid Build Coastguard Worker         }
241*bb4ee6a4SAndroid Build Coastguard Worker         false
242*bb4ee6a4SAndroid Build Coastguard Worker     })
243*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
244*bb4ee6a4SAndroid Build Coastguard Worker }
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker /// Enable vmm swap for crosvm instance whose control socket is listening on `socket_path`.
247*bb4ee6a4SAndroid Build Coastguard Worker ///
248*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
249*bb4ee6a4SAndroid Build Coastguard Worker ///
250*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
251*bb4ee6a4SAndroid Build Coastguard Worker ///
252*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
253*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
254*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
255*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_swap_enable_vm(socket_path: *const c_char) -> bool256*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_swap_enable_vm(socket_path: *const c_char) -> bool {
257*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
258*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
259*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::Swap(SwapCommand::Enable), socket_path).is_ok()
260*bb4ee6a4SAndroid Build Coastguard Worker         } else {
261*bb4ee6a4SAndroid Build Coastguard Worker             false
262*bb4ee6a4SAndroid Build Coastguard Worker         }
263*bb4ee6a4SAndroid Build Coastguard Worker     })
264*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
265*bb4ee6a4SAndroid Build Coastguard Worker }
266*bb4ee6a4SAndroid Build Coastguard Worker 
267*bb4ee6a4SAndroid Build Coastguard Worker /// Swap out staging memory for crosvm instance whose control socket is listening
268*bb4ee6a4SAndroid Build Coastguard Worker /// on `socket_path`.
269*bb4ee6a4SAndroid Build Coastguard Worker ///
270*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
271*bb4ee6a4SAndroid Build Coastguard Worker ///
272*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
273*bb4ee6a4SAndroid Build Coastguard Worker ///
274*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
275*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
276*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
277*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_swap_swapout_vm(socket_path: *const c_char) -> bool278*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_swap_swapout_vm(socket_path: *const c_char) -> bool {
279*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
280*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
281*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::Swap(SwapCommand::SwapOut), socket_path).is_ok()
282*bb4ee6a4SAndroid Build Coastguard Worker         } else {
283*bb4ee6a4SAndroid Build Coastguard Worker             false
284*bb4ee6a4SAndroid Build Coastguard Worker         }
285*bb4ee6a4SAndroid Build Coastguard Worker     })
286*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
287*bb4ee6a4SAndroid Build Coastguard Worker }
288*bb4ee6a4SAndroid Build Coastguard Worker 
289*bb4ee6a4SAndroid Build Coastguard Worker /// Arguments structure for crosvm_client_swap_disable_vm2.
290*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
291*bb4ee6a4SAndroid Build Coastguard Worker pub struct SwapDisableArgs {
292*bb4ee6a4SAndroid Build Coastguard Worker     /// The path of the control socket to target.
293*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
294*bb4ee6a4SAndroid Build Coastguard Worker     /// Whether or not the swap file should be cleaned up in the background.
295*bb4ee6a4SAndroid Build Coastguard Worker     slow_file_cleanup: bool,
296*bb4ee6a4SAndroid Build Coastguard Worker }
297*bb4ee6a4SAndroid Build Coastguard Worker 
298*bb4ee6a4SAndroid Build Coastguard Worker /// Disable vmm swap according to `args`.
299*bb4ee6a4SAndroid Build Coastguard Worker ///
300*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
301*bb4ee6a4SAndroid Build Coastguard Worker ///
302*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
303*bb4ee6a4SAndroid Build Coastguard Worker ///
304*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
305*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
306*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
307*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_swap_disable_vm(args: *mut SwapDisableArgs) -> bool308*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_swap_disable_vm(args: *mut SwapDisableArgs) -> bool {
309*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
310*bb4ee6a4SAndroid Build Coastguard Worker         if args.is_null() {
311*bb4ee6a4SAndroid Build Coastguard Worker             return false;
312*bb4ee6a4SAndroid Build Coastguard Worker         }
313*bb4ee6a4SAndroid Build Coastguard Worker         let Some(socket_path) = validate_socket_path((*args).socket_path) else {
314*bb4ee6a4SAndroid Build Coastguard Worker             return false;
315*bb4ee6a4SAndroid Build Coastguard Worker         };
316*bb4ee6a4SAndroid Build Coastguard Worker         vms_request(
317*bb4ee6a4SAndroid Build Coastguard Worker             &VmRequest::Swap(SwapCommand::Disable {
318*bb4ee6a4SAndroid Build Coastguard Worker                 slow_file_cleanup: (*args).slow_file_cleanup,
319*bb4ee6a4SAndroid Build Coastguard Worker             }),
320*bb4ee6a4SAndroid Build Coastguard Worker             socket_path,
321*bb4ee6a4SAndroid Build Coastguard Worker         )
322*bb4ee6a4SAndroid Build Coastguard Worker         .is_ok()
323*bb4ee6a4SAndroid Build Coastguard Worker     })
324*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
325*bb4ee6a4SAndroid Build Coastguard Worker }
326*bb4ee6a4SAndroid Build Coastguard Worker 
327*bb4ee6a4SAndroid Build Coastguard Worker /// Trim staging memory for vmm swap for crosvm instance whose control socket is listening on
328*bb4ee6a4SAndroid Build Coastguard Worker /// `socket_path`.
329*bb4ee6a4SAndroid Build Coastguard Worker ///
330*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
331*bb4ee6a4SAndroid Build Coastguard Worker ///
332*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
333*bb4ee6a4SAndroid Build Coastguard Worker ///
334*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
335*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
336*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
337*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_swap_trim(socket_path: *const c_char) -> bool338*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_swap_trim(socket_path: *const c_char) -> bool {
339*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
340*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
341*bb4ee6a4SAndroid Build Coastguard Worker             vms_request(&VmRequest::Swap(SwapCommand::Trim), socket_path).is_ok()
342*bb4ee6a4SAndroid Build Coastguard Worker         } else {
343*bb4ee6a4SAndroid Build Coastguard Worker             false
344*bb4ee6a4SAndroid Build Coastguard Worker         }
345*bb4ee6a4SAndroid Build Coastguard Worker     })
346*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
347*bb4ee6a4SAndroid Build Coastguard Worker }
348*bb4ee6a4SAndroid Build Coastguard Worker 
349*bb4ee6a4SAndroid Build Coastguard Worker /// Returns vmm-swap status of the crosvm instance whose control socket is listening on
350*bb4ee6a4SAndroid Build Coastguard Worker /// `socket_path`.
351*bb4ee6a4SAndroid Build Coastguard Worker ///
352*bb4ee6a4SAndroid Build Coastguard Worker /// The parameters `status` is optional and will only be written to if they are non-null.
353*bb4ee6a4SAndroid Build Coastguard Worker ///
354*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
355*bb4ee6a4SAndroid Build Coastguard Worker ///
356*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
357*bb4ee6a4SAndroid Build Coastguard Worker ///
358*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
359*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
360*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
361*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_swap_status( socket_path: *const c_char, status: *mut SwapStatus, ) -> bool362*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_swap_status(
363*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
364*bb4ee6a4SAndroid Build Coastguard Worker     status: *mut SwapStatus,
365*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
366*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
367*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
368*bb4ee6a4SAndroid Build Coastguard Worker             let request = &VmRequest::Swap(SwapCommand::Status);
369*bb4ee6a4SAndroid Build Coastguard Worker             if let Ok(VmResponse::SwapStatus(response)) = handle_request(request, socket_path) {
370*bb4ee6a4SAndroid Build Coastguard Worker                 if !status.is_null() {
371*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: just checked that `status` is not null.
372*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe {
373*bb4ee6a4SAndroid Build Coastguard Worker                         *status = response;
374*bb4ee6a4SAndroid Build Coastguard Worker                     }
375*bb4ee6a4SAndroid Build Coastguard Worker                 }
376*bb4ee6a4SAndroid Build Coastguard Worker                 true
377*bb4ee6a4SAndroid Build Coastguard Worker             } else {
378*bb4ee6a4SAndroid Build Coastguard Worker                 false
379*bb4ee6a4SAndroid Build Coastguard Worker             }
380*bb4ee6a4SAndroid Build Coastguard Worker         } else {
381*bb4ee6a4SAndroid Build Coastguard Worker             false
382*bb4ee6a4SAndroid Build Coastguard Worker         }
383*bb4ee6a4SAndroid Build Coastguard Worker     })
384*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
385*bb4ee6a4SAndroid Build Coastguard Worker }
386*bb4ee6a4SAndroid Build Coastguard Worker 
387*bb4ee6a4SAndroid Build Coastguard Worker /// Represents an individual attached USB device.
388*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
389*bb4ee6a4SAndroid Build Coastguard Worker pub struct UsbDeviceEntry {
390*bb4ee6a4SAndroid Build Coastguard Worker     /// Internal port index used for identifying this individual device.
391*bb4ee6a4SAndroid Build Coastguard Worker     port: u8,
392*bb4ee6a4SAndroid Build Coastguard Worker     /// USB vendor ID
393*bb4ee6a4SAndroid Build Coastguard Worker     vendor_id: u16,
394*bb4ee6a4SAndroid Build Coastguard Worker     /// USB product ID
395*bb4ee6a4SAndroid Build Coastguard Worker     product_id: u16,
396*bb4ee6a4SAndroid Build Coastguard Worker }
397*bb4ee6a4SAndroid Build Coastguard Worker 
398*bb4ee6a4SAndroid Build Coastguard Worker impl From<&UsbControlAttachedDevice> for UsbDeviceEntry {
from(other: &UsbControlAttachedDevice) -> Self399*bb4ee6a4SAndroid Build Coastguard Worker     fn from(other: &UsbControlAttachedDevice) -> Self {
400*bb4ee6a4SAndroid Build Coastguard Worker         Self {
401*bb4ee6a4SAndroid Build Coastguard Worker             port: other.port,
402*bb4ee6a4SAndroid Build Coastguard Worker             vendor_id: other.vendor_id,
403*bb4ee6a4SAndroid Build Coastguard Worker             product_id: other.product_id,
404*bb4ee6a4SAndroid Build Coastguard Worker         }
405*bb4ee6a4SAndroid Build Coastguard Worker     }
406*bb4ee6a4SAndroid Build Coastguard Worker }
407*bb4ee6a4SAndroid Build Coastguard Worker 
408*bb4ee6a4SAndroid Build Coastguard Worker /// Simply returns the maximum possible number of USB devices
409*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_max_usb_devices() -> usize410*bb4ee6a4SAndroid Build Coastguard Worker pub extern "C" fn crosvm_client_max_usb_devices() -> usize {
411*bb4ee6a4SAndroid Build Coastguard Worker     USB_CONTROL_MAX_PORTS
412*bb4ee6a4SAndroid Build Coastguard Worker }
413*bb4ee6a4SAndroid Build Coastguard Worker 
414*bb4ee6a4SAndroid Build Coastguard Worker /// Returns all USB devices passed through the crosvm instance whose control socket is listening on
415*bb4ee6a4SAndroid Build Coastguard Worker /// `socket_path`.
416*bb4ee6a4SAndroid Build Coastguard Worker ///
417*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns the amount of entries written.
418*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
419*bb4ee6a4SAndroid Build Coastguard Worker ///
420*bb4ee6a4SAndroid Build Coastguard Worker /// * `socket_path` - Path to the crosvm control socket
421*bb4ee6a4SAndroid Build Coastguard Worker /// * `entries` - Pointer to an array of `UsbDeviceEntry` where the details about the attached
422*bb4ee6a4SAndroid Build Coastguard Worker ///   devices will be written to
423*bb4ee6a4SAndroid Build Coastguard Worker /// * `entries_length` - Amount of entries in the array specified by `entries`
424*bb4ee6a4SAndroid Build Coastguard Worker ///
425*bb4ee6a4SAndroid Build Coastguard Worker /// Use the value returned by [`crosvm_client_max_usb_devices()`] to determine the size of the input
426*bb4ee6a4SAndroid Build Coastguard Worker /// array to this function.
427*bb4ee6a4SAndroid Build Coastguard Worker ///
428*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
429*bb4ee6a4SAndroid Build Coastguard Worker ///
430*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
431*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
432*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
433*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_usb_list( socket_path: *const c_char, entries: *mut UsbDeviceEntry, entries_length: ssize_t, ) -> ssize_t434*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_usb_list(
435*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
436*bb4ee6a4SAndroid Build Coastguard Worker     entries: *mut UsbDeviceEntry,
437*bb4ee6a4SAndroid Build Coastguard Worker     entries_length: ssize_t,
438*bb4ee6a4SAndroid Build Coastguard Worker ) -> ssize_t {
439*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
440*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
441*bb4ee6a4SAndroid Build Coastguard Worker             if entries.is_null() {
442*bb4ee6a4SAndroid Build Coastguard Worker                 return -1;
443*bb4ee6a4SAndroid Build Coastguard Worker             }
444*bb4ee6a4SAndroid Build Coastguard Worker             if let Ok(UsbControlResult::Devices(res)) = do_usb_list(socket_path) {
445*bb4ee6a4SAndroid Build Coastguard Worker                 let mut i = 0;
446*bb4ee6a4SAndroid Build Coastguard Worker                 for entry in res.iter().filter(|x| x.valid()) {
447*bb4ee6a4SAndroid Build Coastguard Worker                     if i >= entries_length {
448*bb4ee6a4SAndroid Build Coastguard Worker                         break;
449*bb4ee6a4SAndroid Build Coastguard Worker                     }
450*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: checked that `entries` is not null.
451*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe {
452*bb4ee6a4SAndroid Build Coastguard Worker                         *entries.offset(i) = entry.into();
453*bb4ee6a4SAndroid Build Coastguard Worker                         i += 1;
454*bb4ee6a4SAndroid Build Coastguard Worker                     }
455*bb4ee6a4SAndroid Build Coastguard Worker                 }
456*bb4ee6a4SAndroid Build Coastguard Worker                 i
457*bb4ee6a4SAndroid Build Coastguard Worker             } else {
458*bb4ee6a4SAndroid Build Coastguard Worker                 -1
459*bb4ee6a4SAndroid Build Coastguard Worker             }
460*bb4ee6a4SAndroid Build Coastguard Worker         } else {
461*bb4ee6a4SAndroid Build Coastguard Worker             -1
462*bb4ee6a4SAndroid Build Coastguard Worker         }
463*bb4ee6a4SAndroid Build Coastguard Worker     })
464*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(-1)
465*bb4ee6a4SAndroid Build Coastguard Worker }
466*bb4ee6a4SAndroid Build Coastguard Worker 
467*bb4ee6a4SAndroid Build Coastguard Worker /// Attaches an USB device to crosvm instance whose control socket is listening on `socket_path`.
468*bb4ee6a4SAndroid Build Coastguard Worker ///
469*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns the amount of entries written.
470*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
471*bb4ee6a4SAndroid Build Coastguard Worker ///
472*bb4ee6a4SAndroid Build Coastguard Worker /// * `socket_path` - Path to the crosvm control socket
473*bb4ee6a4SAndroid Build Coastguard Worker /// * `bus` - USB device bus ID (unused)
474*bb4ee6a4SAndroid Build Coastguard Worker /// * `addr` - USB device address (unused)
475*bb4ee6a4SAndroid Build Coastguard Worker /// * `vid` - USB device vendor ID (unused)
476*bb4ee6a4SAndroid Build Coastguard Worker /// * `pid` - USB device product ID (unused)
477*bb4ee6a4SAndroid Build Coastguard Worker /// * `dev_path` - Path to the USB device (Most likely `/dev/bus/usb/<bus>/<addr>`).
478*bb4ee6a4SAndroid Build Coastguard Worker /// * `out_port` - (optional) internal port will be written here if provided.
479*bb4ee6a4SAndroid Build Coastguard Worker ///
480*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
481*bb4ee6a4SAndroid Build Coastguard Worker ///
482*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
483*bb4ee6a4SAndroid Build Coastguard Worker ///
484*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage.
485*bb4ee6a4SAndroid Build Coastguard Worker /// Trivial !raw_pointer.is_null() checks prevent some unsafe behavior, but the caller should
486*bb4ee6a4SAndroid Build Coastguard Worker /// ensure no null pointers are passed into the function.
487*bb4ee6a4SAndroid Build Coastguard Worker ///
488*bb4ee6a4SAndroid Build Coastguard Worker /// The safety requirements for `socket_path` and `dev_path` are the same as the ones from
489*bb4ee6a4SAndroid Build Coastguard Worker /// `CStr::from_ptr()`. `out_port` should be a non-null pointer that points to a writable 1byte
490*bb4ee6a4SAndroid Build Coastguard Worker /// region.
491*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_usb_attach( socket_path: *const c_char, _bus: u8, _addr: u8, _vid: u16, _pid: u16, dev_path: *const c_char, out_port: *mut u8, ) -> bool492*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_usb_attach(
493*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
494*bb4ee6a4SAndroid Build Coastguard Worker     _bus: u8,
495*bb4ee6a4SAndroid Build Coastguard Worker     _addr: u8,
496*bb4ee6a4SAndroid Build Coastguard Worker     _vid: u16,
497*bb4ee6a4SAndroid Build Coastguard Worker     _pid: u16,
498*bb4ee6a4SAndroid Build Coastguard Worker     dev_path: *const c_char,
499*bb4ee6a4SAndroid Build Coastguard Worker     out_port: *mut u8,
500*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
501*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
502*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
503*bb4ee6a4SAndroid Build Coastguard Worker             if dev_path.is_null() {
504*bb4ee6a4SAndroid Build Coastguard Worker                 return false;
505*bb4ee6a4SAndroid Build Coastguard Worker             }
506*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: just checked that `dev_path` is not null.
507*bb4ee6a4SAndroid Build Coastguard Worker             let dev_path = Path::new(unsafe { CStr::from_ptr(dev_path) }.to_str().unwrap_or(""));
508*bb4ee6a4SAndroid Build Coastguard Worker 
509*bb4ee6a4SAndroid Build Coastguard Worker             if let Ok(UsbControlResult::Ok { port }) = do_usb_attach(socket_path, dev_path) {
510*bb4ee6a4SAndroid Build Coastguard Worker                 if !out_port.is_null() {
511*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: trivially safe
512*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe { *out_port = port };
513*bb4ee6a4SAndroid Build Coastguard Worker                 }
514*bb4ee6a4SAndroid Build Coastguard Worker                 true
515*bb4ee6a4SAndroid Build Coastguard Worker             } else {
516*bb4ee6a4SAndroid Build Coastguard Worker                 false
517*bb4ee6a4SAndroid Build Coastguard Worker             }
518*bb4ee6a4SAndroid Build Coastguard Worker         } else {
519*bb4ee6a4SAndroid Build Coastguard Worker             false
520*bb4ee6a4SAndroid Build Coastguard Worker         }
521*bb4ee6a4SAndroid Build Coastguard Worker     })
522*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
523*bb4ee6a4SAndroid Build Coastguard Worker }
524*bb4ee6a4SAndroid Build Coastguard Worker 
525*bb4ee6a4SAndroid Build Coastguard Worker /// Attaches a u2f security key to crosvm instance whose control socket is listening on
526*bb4ee6a4SAndroid Build Coastguard Worker /// `socket_path`.
527*bb4ee6a4SAndroid Build Coastguard Worker ///
528*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns the amount of entries written.
529*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
530*bb4ee6a4SAndroid Build Coastguard Worker ///
531*bb4ee6a4SAndroid Build Coastguard Worker /// * `socket_path` - Path to the crosvm control socket
532*bb4ee6a4SAndroid Build Coastguard Worker /// * `hidraw_path` - Path to the hidraw device of the security key (like `/dev/hidraw0`)
533*bb4ee6a4SAndroid Build Coastguard Worker /// * `out_port` - (optional) internal port will be written here if provided.
534*bb4ee6a4SAndroid Build Coastguard Worker ///
535*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
536*bb4ee6a4SAndroid Build Coastguard Worker ///
537*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
538*bb4ee6a4SAndroid Build Coastguard Worker ///
539*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage.
540*bb4ee6a4SAndroid Build Coastguard Worker /// Trivial !raw_pointer.is_null() checks prevent some unsafe behavior, but the caller should
541*bb4ee6a4SAndroid Build Coastguard Worker /// ensure no null pointers are passed into the function.
542*bb4ee6a4SAndroid Build Coastguard Worker ///
543*bb4ee6a4SAndroid Build Coastguard Worker /// The safety requirements for `socket_path` and `hidraw_path` are the same as the ones from
544*bb4ee6a4SAndroid Build Coastguard Worker /// `CStr::from_ptr()`. `out_port` should be a non-null pointer that points to a writable 1byte
545*bb4ee6a4SAndroid Build Coastguard Worker /// region.
546*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_security_key_attach( socket_path: *const c_char, hidraw_path: *const c_char, out_port: *mut u8, ) -> bool547*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_security_key_attach(
548*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
549*bb4ee6a4SAndroid Build Coastguard Worker     hidraw_path: *const c_char,
550*bb4ee6a4SAndroid Build Coastguard Worker     out_port: *mut u8,
551*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
552*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
553*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
554*bb4ee6a4SAndroid Build Coastguard Worker             if hidraw_path.is_null() {
555*bb4ee6a4SAndroid Build Coastguard Worker                 return false;
556*bb4ee6a4SAndroid Build Coastguard Worker             }
557*bb4ee6a4SAndroid Build Coastguard Worker             let hidraw_path = Path::new(
558*bb4ee6a4SAndroid Build Coastguard Worker                 // SAFETY: just checked that `hidraw_path` is not null.
559*bb4ee6a4SAndroid Build Coastguard Worker                 unsafe { CStr::from_ptr(hidraw_path) }
560*bb4ee6a4SAndroid Build Coastguard Worker                     .to_str()
561*bb4ee6a4SAndroid Build Coastguard Worker                     .unwrap_or(""),
562*bb4ee6a4SAndroid Build Coastguard Worker             );
563*bb4ee6a4SAndroid Build Coastguard Worker 
564*bb4ee6a4SAndroid Build Coastguard Worker             if let Ok(UsbControlResult::Ok { port }) =
565*bb4ee6a4SAndroid Build Coastguard Worker                 do_security_key_attach(socket_path, hidraw_path)
566*bb4ee6a4SAndroid Build Coastguard Worker             {
567*bb4ee6a4SAndroid Build Coastguard Worker                 if !out_port.is_null() {
568*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: trivially safe
569*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe { *out_port = port };
570*bb4ee6a4SAndroid Build Coastguard Worker                 }
571*bb4ee6a4SAndroid Build Coastguard Worker                 true
572*bb4ee6a4SAndroid Build Coastguard Worker             } else {
573*bb4ee6a4SAndroid Build Coastguard Worker                 false
574*bb4ee6a4SAndroid Build Coastguard Worker             }
575*bb4ee6a4SAndroid Build Coastguard Worker         } else {
576*bb4ee6a4SAndroid Build Coastguard Worker             false
577*bb4ee6a4SAndroid Build Coastguard Worker         }
578*bb4ee6a4SAndroid Build Coastguard Worker     })
579*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
580*bb4ee6a4SAndroid Build Coastguard Worker }
581*bb4ee6a4SAndroid Build Coastguard Worker 
582*bb4ee6a4SAndroid Build Coastguard Worker /// Detaches an USB device from crosvm instance whose control socket is listening on `socket_path`.
583*bb4ee6a4SAndroid Build Coastguard Worker /// `port` determines device to be detached.
584*bb4ee6a4SAndroid Build Coastguard Worker ///
585*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
586*bb4ee6a4SAndroid Build Coastguard Worker ///
587*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
588*bb4ee6a4SAndroid Build Coastguard Worker ///
589*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
590*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
591*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
592*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_usb_detach(socket_path: *const c_char, port: u8) -> bool593*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_usb_detach(socket_path: *const c_char, port: u8) -> bool {
594*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
595*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
596*bb4ee6a4SAndroid Build Coastguard Worker             do_usb_detach(socket_path, port).is_ok()
597*bb4ee6a4SAndroid Build Coastguard Worker         } else {
598*bb4ee6a4SAndroid Build Coastguard Worker             false
599*bb4ee6a4SAndroid Build Coastguard Worker         }
600*bb4ee6a4SAndroid Build Coastguard Worker     })
601*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
602*bb4ee6a4SAndroid Build Coastguard Worker }
603*bb4ee6a4SAndroid Build Coastguard Worker 
604*bb4ee6a4SAndroid Build Coastguard Worker /// Attaches a net tap device to the crosvm instance with control socket at `socket_path`.
605*bb4ee6a4SAndroid Build Coastguard Worker ///
606*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
607*bb4ee6a4SAndroid Build Coastguard Worker ///
608*bb4ee6a4SAndroid Build Coastguard Worker /// * `socket_path` - Path to the crosvm control socket
609*bb4ee6a4SAndroid Build Coastguard Worker /// * `tap_name` - Name of the tap device
610*bb4ee6a4SAndroid Build Coastguard Worker /// * `out_bus_num` - guest bus number will be written here
611*bb4ee6a4SAndroid Build Coastguard Worker ///
612*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success, false on failure.
613*bb4ee6a4SAndroid Build Coastguard Worker ///
614*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
615*bb4ee6a4SAndroid Build Coastguard Worker ///
616*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - socket_path and tap_name are assumed to point to a
617*bb4ee6a4SAndroid Build Coastguard Worker /// null-terminated CStr. Function checks that the pointers are not null, but caller need to check
618*bb4ee6a4SAndroid Build Coastguard Worker /// the validity of the pointer. out_bus_num is assumed to point to a u8 integer.
619*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_net_tap_attach( socket_path: *const c_char, tap_name: *const c_char, out_bus_num: *mut u8, ) -> bool620*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_net_tap_attach(
621*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
622*bb4ee6a4SAndroid Build Coastguard Worker     tap_name: *const c_char,
623*bb4ee6a4SAndroid Build Coastguard Worker     out_bus_num: *mut u8,
624*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
625*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
626*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
627*bb4ee6a4SAndroid Build Coastguard Worker             if tap_name.is_null() || out_bus_num.is_null() {
628*bb4ee6a4SAndroid Build Coastguard Worker                 return false;
629*bb4ee6a4SAndroid Build Coastguard Worker             }
630*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: just checked that `tap_name` is not null. Function caller guarantees it
631*bb4ee6a4SAndroid Build Coastguard Worker             // points to a valid CStr.
632*bb4ee6a4SAndroid Build Coastguard Worker             let tap_name = unsafe { CStr::from_ptr(tap_name) }.to_str().unwrap_or("");
633*bb4ee6a4SAndroid Build Coastguard Worker 
634*bb4ee6a4SAndroid Build Coastguard Worker             match do_net_add(tap_name, socket_path) {
635*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(bus_num) => {
636*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: checked out_bus_num is not null. Function caller guarantees
637*bb4ee6a4SAndroid Build Coastguard Worker                     // validity of pointer.
638*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe { *out_bus_num = bus_num };
639*bb4ee6a4SAndroid Build Coastguard Worker                     true
640*bb4ee6a4SAndroid Build Coastguard Worker                 }
641*bb4ee6a4SAndroid Build Coastguard Worker                 Err(_e) => false,
642*bb4ee6a4SAndroid Build Coastguard Worker             }
643*bb4ee6a4SAndroid Build Coastguard Worker         } else {
644*bb4ee6a4SAndroid Build Coastguard Worker             false
645*bb4ee6a4SAndroid Build Coastguard Worker         }
646*bb4ee6a4SAndroid Build Coastguard Worker     })
647*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
648*bb4ee6a4SAndroid Build Coastguard Worker }
649*bb4ee6a4SAndroid Build Coastguard Worker 
650*bb4ee6a4SAndroid Build Coastguard Worker /// Detaches a hotplugged tap device from the crosvm instance with control socket at `socket_path`.
651*bb4ee6a4SAndroid Build Coastguard Worker ///
652*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
653*bb4ee6a4SAndroid Build Coastguard Worker ///
654*bb4ee6a4SAndroid Build Coastguard Worker /// * `socket_path` - Path to the crosvm control socket
655*bb4ee6a4SAndroid Build Coastguard Worker /// * `bus_num` - Bus number of the tap device to be removed.
656*bb4ee6a4SAndroid Build Coastguard Worker ///
657*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success, and false on failure.
658*bb4ee6a4SAndroid Build Coastguard Worker ///
659*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
660*bb4ee6a4SAndroid Build Coastguard Worker ///
661*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - socket_path is assumed to point to a
662*bb4ee6a4SAndroid Build Coastguard Worker /// null-terminated Cstr. Function checks that the pointers are not null, but caller need to check
663*bb4ee6a4SAndroid Build Coastguard Worker /// the validity of the pointer.
664*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_net_tap_detach( socket_path: *const c_char, bus_num: u8, ) -> bool665*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_net_tap_detach(
666*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
667*bb4ee6a4SAndroid Build Coastguard Worker     bus_num: u8,
668*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
669*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
670*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
671*bb4ee6a4SAndroid Build Coastguard Worker             match do_net_remove(bus_num, socket_path) {
672*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(()) => true,
673*bb4ee6a4SAndroid Build Coastguard Worker                 Err(_e) => false,
674*bb4ee6a4SAndroid Build Coastguard Worker             }
675*bb4ee6a4SAndroid Build Coastguard Worker         } else {
676*bb4ee6a4SAndroid Build Coastguard Worker             false
677*bb4ee6a4SAndroid Build Coastguard Worker         }
678*bb4ee6a4SAndroid Build Coastguard Worker     })
679*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
680*bb4ee6a4SAndroid Build Coastguard Worker }
681*bb4ee6a4SAndroid Build Coastguard Worker 
682*bb4ee6a4SAndroid Build Coastguard Worker /// Modifies the battery status of crosvm instance whose control socket is listening on
683*bb4ee6a4SAndroid Build Coastguard Worker /// `socket_path`.
684*bb4ee6a4SAndroid Build Coastguard Worker ///
685*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
686*bb4ee6a4SAndroid Build Coastguard Worker ///
687*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
688*bb4ee6a4SAndroid Build Coastguard Worker ///
689*bb4ee6a4SAndroid Build Coastguard Worker /// The caller will ensure the raw pointers in arguments passed in can be safely used by
690*bb4ee6a4SAndroid Build Coastguard Worker /// `CStr::from_ptr()`
691*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_modify_battery( socket_path: *const c_char, battery_type: *const c_char, property: *const c_char, target: *const c_char, ) -> bool692*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_modify_battery(
693*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
694*bb4ee6a4SAndroid Build Coastguard Worker     battery_type: *const c_char,
695*bb4ee6a4SAndroid Build Coastguard Worker     property: *const c_char,
696*bb4ee6a4SAndroid Build Coastguard Worker     target: *const c_char,
697*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
698*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
699*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
700*bb4ee6a4SAndroid Build Coastguard Worker             if battery_type.is_null() || property.is_null() || target.is_null() {
701*bb4ee6a4SAndroid Build Coastguard Worker                 return false;
702*bb4ee6a4SAndroid Build Coastguard Worker             }
703*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: trivially safe
704*bb4ee6a4SAndroid Build Coastguard Worker             let battery_type = unsafe { CStr::from_ptr(battery_type) };
705*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: trivially safe
706*bb4ee6a4SAndroid Build Coastguard Worker             let property = unsafe { CStr::from_ptr(property) };
707*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: trivially safe
708*bb4ee6a4SAndroid Build Coastguard Worker             let target = unsafe { CStr::from_ptr(target) };
709*bb4ee6a4SAndroid Build Coastguard Worker 
710*bb4ee6a4SAndroid Build Coastguard Worker             do_modify_battery(
711*bb4ee6a4SAndroid Build Coastguard Worker                 socket_path,
712*bb4ee6a4SAndroid Build Coastguard Worker                 battery_type.to_str().unwrap(),
713*bb4ee6a4SAndroid Build Coastguard Worker                 property.to_str().unwrap(),
714*bb4ee6a4SAndroid Build Coastguard Worker                 target.to_str().unwrap(),
715*bb4ee6a4SAndroid Build Coastguard Worker             )
716*bb4ee6a4SAndroid Build Coastguard Worker             .is_ok()
717*bb4ee6a4SAndroid Build Coastguard Worker         } else {
718*bb4ee6a4SAndroid Build Coastguard Worker             false
719*bb4ee6a4SAndroid Build Coastguard Worker         }
720*bb4ee6a4SAndroid Build Coastguard Worker     })
721*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
722*bb4ee6a4SAndroid Build Coastguard Worker }
723*bb4ee6a4SAndroid Build Coastguard Worker 
724*bb4ee6a4SAndroid Build Coastguard Worker /// Fakes the battery status of crosvm instance. The power status will always be on
725*bb4ee6a4SAndroid Build Coastguard Worker /// battery, and the maximum battery capacity could be read by guest is set to the
726*bb4ee6a4SAndroid Build Coastguard Worker /// `max_battery_capacity`.
727*bb4ee6a4SAndroid Build Coastguard Worker ///
728*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
729*bb4ee6a4SAndroid Build Coastguard Worker ///
730*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
731*bb4ee6a4SAndroid Build Coastguard Worker ///
732*bb4ee6a4SAndroid Build Coastguard Worker /// * `socket_path` - Path to the crosvm control socket
733*bb4ee6a4SAndroid Build Coastguard Worker /// * `battery_type` - Type of battery emulation corresponding to vm_tools::BatteryType
734*bb4ee6a4SAndroid Build Coastguard Worker /// * `max_battery_capacity` - maximum battery capacity could be read by guest
735*bb4ee6a4SAndroid Build Coastguard Worker ///
736*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
737*bb4ee6a4SAndroid Build Coastguard Worker ///
738*bb4ee6a4SAndroid Build Coastguard Worker /// The caller will ensure the raw pointers in arguments passed in can be safely used by
739*bb4ee6a4SAndroid Build Coastguard Worker /// `CStr::from_ptr()`
740*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_fake_power( socket_path: *const c_char, battery_type: *const c_char, max_battery_capacity: u32, ) -> bool741*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_fake_power(
742*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
743*bb4ee6a4SAndroid Build Coastguard Worker     battery_type: *const c_char,
744*bb4ee6a4SAndroid Build Coastguard Worker     max_battery_capacity: u32,
745*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
746*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
747*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
748*bb4ee6a4SAndroid Build Coastguard Worker             if battery_type.is_null() || max_battery_capacity > 100 {
749*bb4ee6a4SAndroid Build Coastguard Worker                 return false;
750*bb4ee6a4SAndroid Build Coastguard Worker             }
751*bb4ee6a4SAndroid Build Coastguard Worker 
752*bb4ee6a4SAndroid Build Coastguard Worker             let battery_type = CStr::from_ptr(battery_type);
753*bb4ee6a4SAndroid Build Coastguard Worker             let fake_max_capacity_target: String = max_battery_capacity.to_string();
754*bb4ee6a4SAndroid Build Coastguard Worker 
755*bb4ee6a4SAndroid Build Coastguard Worker             do_modify_battery(
756*bb4ee6a4SAndroid Build Coastguard Worker                 socket_path.clone(),
757*bb4ee6a4SAndroid Build Coastguard Worker                 battery_type.to_str().unwrap(),
758*bb4ee6a4SAndroid Build Coastguard Worker                 &BatProperty::SetFakeBatConfig.to_string(),
759*bb4ee6a4SAndroid Build Coastguard Worker                 fake_max_capacity_target.as_str(),
760*bb4ee6a4SAndroid Build Coastguard Worker             )
761*bb4ee6a4SAndroid Build Coastguard Worker             .is_ok()
762*bb4ee6a4SAndroid Build Coastguard Worker         } else {
763*bb4ee6a4SAndroid Build Coastguard Worker             false
764*bb4ee6a4SAndroid Build Coastguard Worker         }
765*bb4ee6a4SAndroid Build Coastguard Worker     })
766*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
767*bb4ee6a4SAndroid Build Coastguard Worker }
768*bb4ee6a4SAndroid Build Coastguard Worker 
769*bb4ee6a4SAndroid Build Coastguard Worker /// Resume the battery status of crosvm instance from fake status
770*bb4ee6a4SAndroid Build Coastguard Worker ///
771*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
772*bb4ee6a4SAndroid Build Coastguard Worker ///
773*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
774*bb4ee6a4SAndroid Build Coastguard Worker ///
775*bb4ee6a4SAndroid Build Coastguard Worker /// * `socket_path` - Path to the crosvm control socket
776*bb4ee6a4SAndroid Build Coastguard Worker /// * `battery_type` - Type of battery emulation corresponding to vm_tools::BatteryType
777*bb4ee6a4SAndroid Build Coastguard Worker ///
778*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
779*bb4ee6a4SAndroid Build Coastguard Worker ///
780*bb4ee6a4SAndroid Build Coastguard Worker /// The caller will ensure the raw pointers in arguments passed in can be safely used by
781*bb4ee6a4SAndroid Build Coastguard Worker /// `CStr::from_ptr()`.
782*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_cancel_fake_power( socket_path: *const c_char, battery_type: *const c_char, ) -> bool783*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_cancel_fake_power(
784*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
785*bb4ee6a4SAndroid Build Coastguard Worker     battery_type: *const c_char,
786*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
787*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
788*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
789*bb4ee6a4SAndroid Build Coastguard Worker             if battery_type.is_null() {
790*bb4ee6a4SAndroid Build Coastguard Worker                 return false;
791*bb4ee6a4SAndroid Build Coastguard Worker             }
792*bb4ee6a4SAndroid Build Coastguard Worker 
793*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: the caller has a responsibility of giving a valid char* pointer
794*bb4ee6a4SAndroid Build Coastguard Worker             let battery_type = CStr::from_ptr(battery_type);
795*bb4ee6a4SAndroid Build Coastguard Worker 
796*bb4ee6a4SAndroid Build Coastguard Worker             do_modify_battery(
797*bb4ee6a4SAndroid Build Coastguard Worker                 socket_path,
798*bb4ee6a4SAndroid Build Coastguard Worker                 battery_type.to_str().unwrap(),
799*bb4ee6a4SAndroid Build Coastguard Worker                 &BatProperty::CancelFakeBatConfig.to_string(),
800*bb4ee6a4SAndroid Build Coastguard Worker                 "",
801*bb4ee6a4SAndroid Build Coastguard Worker             )
802*bb4ee6a4SAndroid Build Coastguard Worker             .is_ok()
803*bb4ee6a4SAndroid Build Coastguard Worker         } else {
804*bb4ee6a4SAndroid Build Coastguard Worker             false
805*bb4ee6a4SAndroid Build Coastguard Worker         }
806*bb4ee6a4SAndroid Build Coastguard Worker     })
807*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
808*bb4ee6a4SAndroid Build Coastguard Worker }
809*bb4ee6a4SAndroid Build Coastguard Worker 
810*bb4ee6a4SAndroid Build Coastguard Worker /// Resizes the disk of the crosvm instance whose control socket is listening on `socket_path`.
811*bb4ee6a4SAndroid Build Coastguard Worker ///
812*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
813*bb4ee6a4SAndroid Build Coastguard Worker ///
814*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
815*bb4ee6a4SAndroid Build Coastguard Worker ///
816*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
817*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
818*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
819*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_resize_disk( socket_path: *const c_char, disk_index: u64, new_size: u64, ) -> bool820*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_resize_disk(
821*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
822*bb4ee6a4SAndroid Build Coastguard Worker     disk_index: u64,
823*bb4ee6a4SAndroid Build Coastguard Worker     new_size: u64,
824*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
825*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
826*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
827*bb4ee6a4SAndroid Build Coastguard Worker             if let Ok(disk_index) = usize::try_from(disk_index) {
828*bb4ee6a4SAndroid Build Coastguard Worker                 let request = VmRequest::DiskCommand {
829*bb4ee6a4SAndroid Build Coastguard Worker                     disk_index,
830*bb4ee6a4SAndroid Build Coastguard Worker                     command: DiskControlCommand::Resize { new_size },
831*bb4ee6a4SAndroid Build Coastguard Worker                 };
832*bb4ee6a4SAndroid Build Coastguard Worker                 vms_request(&request, socket_path).is_ok()
833*bb4ee6a4SAndroid Build Coastguard Worker             } else {
834*bb4ee6a4SAndroid Build Coastguard Worker                 false
835*bb4ee6a4SAndroid Build Coastguard Worker             }
836*bb4ee6a4SAndroid Build Coastguard Worker         } else {
837*bb4ee6a4SAndroid Build Coastguard Worker             false
838*bb4ee6a4SAndroid Build Coastguard Worker         }
839*bb4ee6a4SAndroid Build Coastguard Worker     })
840*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
841*bb4ee6a4SAndroid Build Coastguard Worker }
842*bb4ee6a4SAndroid Build Coastguard Worker 
843*bb4ee6a4SAndroid Build Coastguard Worker /// Similar to internally used `BalloonStats` but using `i64` instead of
844*bb4ee6a4SAndroid Build Coastguard Worker /// `Option<u64>`. `None` (or values bigger than `i64::max`) will be encoded as -1.
845*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
846*bb4ee6a4SAndroid Build Coastguard Worker pub struct BalloonStatsFfi {
847*bb4ee6a4SAndroid Build Coastguard Worker     swap_in: i64,
848*bb4ee6a4SAndroid Build Coastguard Worker     swap_out: i64,
849*bb4ee6a4SAndroid Build Coastguard Worker     major_faults: i64,
850*bb4ee6a4SAndroid Build Coastguard Worker     minor_faults: i64,
851*bb4ee6a4SAndroid Build Coastguard Worker     free_memory: i64,
852*bb4ee6a4SAndroid Build Coastguard Worker     total_memory: i64,
853*bb4ee6a4SAndroid Build Coastguard Worker     available_memory: i64,
854*bb4ee6a4SAndroid Build Coastguard Worker     disk_caches: i64,
855*bb4ee6a4SAndroid Build Coastguard Worker     hugetlb_allocations: i64,
856*bb4ee6a4SAndroid Build Coastguard Worker     hugetlb_failures: i64,
857*bb4ee6a4SAndroid Build Coastguard Worker     shared_memory: i64,
858*bb4ee6a4SAndroid Build Coastguard Worker     unevictable_memory: i64,
859*bb4ee6a4SAndroid Build Coastguard Worker }
860*bb4ee6a4SAndroid Build Coastguard Worker 
861*bb4ee6a4SAndroid Build Coastguard Worker impl From<&BalloonStats> for BalloonStatsFfi {
from(other: &BalloonStats) -> Self862*bb4ee6a4SAndroid Build Coastguard Worker     fn from(other: &BalloonStats) -> Self {
863*bb4ee6a4SAndroid Build Coastguard Worker         let convert = |x: Option<u64>| -> i64 { x.and_then(|y| y.try_into().ok()).unwrap_or(-1) };
864*bb4ee6a4SAndroid Build Coastguard Worker         Self {
865*bb4ee6a4SAndroid Build Coastguard Worker             swap_in: convert(other.swap_in),
866*bb4ee6a4SAndroid Build Coastguard Worker             swap_out: convert(other.swap_out),
867*bb4ee6a4SAndroid Build Coastguard Worker             major_faults: convert(other.major_faults),
868*bb4ee6a4SAndroid Build Coastguard Worker             minor_faults: convert(other.minor_faults),
869*bb4ee6a4SAndroid Build Coastguard Worker             free_memory: convert(other.free_memory),
870*bb4ee6a4SAndroid Build Coastguard Worker             total_memory: convert(other.total_memory),
871*bb4ee6a4SAndroid Build Coastguard Worker             available_memory: convert(other.available_memory),
872*bb4ee6a4SAndroid Build Coastguard Worker             disk_caches: convert(other.disk_caches),
873*bb4ee6a4SAndroid Build Coastguard Worker             hugetlb_allocations: convert(other.hugetlb_allocations),
874*bb4ee6a4SAndroid Build Coastguard Worker             hugetlb_failures: convert(other.hugetlb_failures),
875*bb4ee6a4SAndroid Build Coastguard Worker             shared_memory: convert(other.shared_memory),
876*bb4ee6a4SAndroid Build Coastguard Worker             unevictable_memory: convert(other.unevictable_memory),
877*bb4ee6a4SAndroid Build Coastguard Worker         }
878*bb4ee6a4SAndroid Build Coastguard Worker     }
879*bb4ee6a4SAndroid Build Coastguard Worker }
880*bb4ee6a4SAndroid Build Coastguard Worker 
881*bb4ee6a4SAndroid Build Coastguard Worker /// Returns balloon stats of the crosvm instance whose control socket is listening on `socket_path`.
882*bb4ee6a4SAndroid Build Coastguard Worker ///
883*bb4ee6a4SAndroid Build Coastguard Worker /// The parameters `stats` and `actual` are optional and will only be written to if they are
884*bb4ee6a4SAndroid Build Coastguard Worker /// non-null.
885*bb4ee6a4SAndroid Build Coastguard Worker ///
886*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
887*bb4ee6a4SAndroid Build Coastguard Worker ///
888*bb4ee6a4SAndroid Build Coastguard Worker /// # Note
889*bb4ee6a4SAndroid Build Coastguard Worker ///
890*bb4ee6a4SAndroid Build Coastguard Worker /// Entries in `BalloonStatsFfi` that are not available will be set to `-1`.
891*bb4ee6a4SAndroid Build Coastguard Worker ///
892*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
893*bb4ee6a4SAndroid Build Coastguard Worker ///
894*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
895*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
896*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
897*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_balloon_stats( socket_path: *const c_char, stats: *mut BalloonStatsFfi, actual: *mut u64, ) -> bool898*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_balloon_stats(
899*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
900*bb4ee6a4SAndroid Build Coastguard Worker     stats: *mut BalloonStatsFfi,
901*bb4ee6a4SAndroid Build Coastguard Worker     actual: *mut u64,
902*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
903*bb4ee6a4SAndroid Build Coastguard Worker     crosvm_client_balloon_stats_impl(socket_path, None, stats, actual)
904*bb4ee6a4SAndroid Build Coastguard Worker }
905*bb4ee6a4SAndroid Build Coastguard Worker 
906*bb4ee6a4SAndroid Build Coastguard Worker /// See crosvm_client_balloon_stats.
907*bb4ee6a4SAndroid Build Coastguard Worker ///
908*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
909*bb4ee6a4SAndroid Build Coastguard Worker ///
910*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
911*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
912*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
913*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_balloon_stats_with_timeout( socket_path: *const c_char, timeout_ms: u64, stats: *mut BalloonStatsFfi, actual: *mut u64, ) -> bool914*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_balloon_stats_with_timeout(
915*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
916*bb4ee6a4SAndroid Build Coastguard Worker     timeout_ms: u64,
917*bb4ee6a4SAndroid Build Coastguard Worker     stats: *mut BalloonStatsFfi,
918*bb4ee6a4SAndroid Build Coastguard Worker     actual: *mut u64,
919*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
920*bb4ee6a4SAndroid Build Coastguard Worker     crosvm_client_balloon_stats_impl(
921*bb4ee6a4SAndroid Build Coastguard Worker         socket_path,
922*bb4ee6a4SAndroid Build Coastguard Worker         Some(Duration::from_millis(timeout_ms)),
923*bb4ee6a4SAndroid Build Coastguard Worker         stats,
924*bb4ee6a4SAndroid Build Coastguard Worker         actual,
925*bb4ee6a4SAndroid Build Coastguard Worker     )
926*bb4ee6a4SAndroid Build Coastguard Worker }
927*bb4ee6a4SAndroid Build Coastguard Worker 
928*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
929*bb4ee6a4SAndroid Build Coastguard Worker ///
930*bb4ee6a4SAndroid Build Coastguard Worker /// This function is safe when the caller ensures the socket_path raw pointer can be safely passed
931*bb4ee6a4SAndroid Build Coastguard Worker /// to `CStr::from_ptr()`.
crosvm_client_balloon_stats_impl( socket_path: *const c_char, timeout_ms: Option<Duration>, stats: *mut BalloonStatsFfi, actual: *mut u64, ) -> bool932*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn crosvm_client_balloon_stats_impl(
933*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
934*bb4ee6a4SAndroid Build Coastguard Worker     timeout_ms: Option<Duration>,
935*bb4ee6a4SAndroid Build Coastguard Worker     stats: *mut BalloonStatsFfi,
936*bb4ee6a4SAndroid Build Coastguard Worker     actual: *mut u64,
937*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
938*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
939*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
940*bb4ee6a4SAndroid Build Coastguard Worker             let request = &VmRequest::BalloonCommand(BalloonControlCommand::Stats {});
941*bb4ee6a4SAndroid Build Coastguard Worker             let resp = handle_request_with_timeout(request, socket_path, timeout_ms);
942*bb4ee6a4SAndroid Build Coastguard Worker             if let Ok(VmResponse::BalloonStats {
943*bb4ee6a4SAndroid Build Coastguard Worker                 stats: ref balloon_stats,
944*bb4ee6a4SAndroid Build Coastguard Worker                 balloon_actual,
945*bb4ee6a4SAndroid Build Coastguard Worker             }) = resp
946*bb4ee6a4SAndroid Build Coastguard Worker             {
947*bb4ee6a4SAndroid Build Coastguard Worker                 if !stats.is_null() {
948*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: just checked that `stats` is not null.
949*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe {
950*bb4ee6a4SAndroid Build Coastguard Worker                         *stats = balloon_stats.into();
951*bb4ee6a4SAndroid Build Coastguard Worker                     }
952*bb4ee6a4SAndroid Build Coastguard Worker                 }
953*bb4ee6a4SAndroid Build Coastguard Worker 
954*bb4ee6a4SAndroid Build Coastguard Worker                 if !actual.is_null() {
955*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: just checked that `actual` is not null.
956*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe {
957*bb4ee6a4SAndroid Build Coastguard Worker                         *actual = balloon_actual;
958*bb4ee6a4SAndroid Build Coastguard Worker                     }
959*bb4ee6a4SAndroid Build Coastguard Worker                 }
960*bb4ee6a4SAndroid Build Coastguard Worker                 true
961*bb4ee6a4SAndroid Build Coastguard Worker             } else {
962*bb4ee6a4SAndroid Build Coastguard Worker                 false
963*bb4ee6a4SAndroid Build Coastguard Worker             }
964*bb4ee6a4SAndroid Build Coastguard Worker         } else {
965*bb4ee6a4SAndroid Build Coastguard Worker             false
966*bb4ee6a4SAndroid Build Coastguard Worker         }
967*bb4ee6a4SAndroid Build Coastguard Worker     })
968*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
969*bb4ee6a4SAndroid Build Coastguard Worker }
970*bb4ee6a4SAndroid Build Coastguard Worker 
971*bb4ee6a4SAndroid Build Coastguard Worker /// Externally exposed variant of BalloonWS/WSBucket, used for FFI.
972*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug)]
973*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
974*bb4ee6a4SAndroid Build Coastguard Worker pub struct WorkingSetBucketFfi {
975*bb4ee6a4SAndroid Build Coastguard Worker     age: u64,
976*bb4ee6a4SAndroid Build Coastguard Worker     bytes: [u64; 2],
977*bb4ee6a4SAndroid Build Coastguard Worker }
978*bb4ee6a4SAndroid Build Coastguard Worker 
979*bb4ee6a4SAndroid Build Coastguard Worker impl WorkingSetBucketFfi {
new() -> Self980*bb4ee6a4SAndroid Build Coastguard Worker     fn new() -> Self {
981*bb4ee6a4SAndroid Build Coastguard Worker         Self {
982*bb4ee6a4SAndroid Build Coastguard Worker             age: 0,
983*bb4ee6a4SAndroid Build Coastguard Worker             bytes: [0, 0],
984*bb4ee6a4SAndroid Build Coastguard Worker         }
985*bb4ee6a4SAndroid Build Coastguard Worker     }
986*bb4ee6a4SAndroid Build Coastguard Worker }
987*bb4ee6a4SAndroid Build Coastguard Worker 
988*bb4ee6a4SAndroid Build Coastguard Worker impl From<WSBucket> for WorkingSetBucketFfi {
from(other: WSBucket) -> Self989*bb4ee6a4SAndroid Build Coastguard Worker     fn from(other: WSBucket) -> Self {
990*bb4ee6a4SAndroid Build Coastguard Worker         Self {
991*bb4ee6a4SAndroid Build Coastguard Worker             age: other.age,
992*bb4ee6a4SAndroid Build Coastguard Worker             bytes: other.bytes,
993*bb4ee6a4SAndroid Build Coastguard Worker         }
994*bb4ee6a4SAndroid Build Coastguard Worker     }
995*bb4ee6a4SAndroid Build Coastguard Worker }
996*bb4ee6a4SAndroid Build Coastguard Worker 
997*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
998*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
999*bb4ee6a4SAndroid Build Coastguard Worker pub struct BalloonWSFfi {
1000*bb4ee6a4SAndroid Build Coastguard Worker     ws: [WorkingSetBucketFfi; VIRTIO_BALLOON_WS_MAX_NUM_BINS],
1001*bb4ee6a4SAndroid Build Coastguard Worker     num_bins: u8,
1002*bb4ee6a4SAndroid Build Coastguard Worker     _reserved: [u8; 7],
1003*bb4ee6a4SAndroid Build Coastguard Worker }
1004*bb4ee6a4SAndroid Build Coastguard Worker 
1005*bb4ee6a4SAndroid Build Coastguard Worker impl TryFrom<&BalloonWS> for BalloonWSFfi {
1006*bb4ee6a4SAndroid Build Coastguard Worker     type Error = &'static str;
1007*bb4ee6a4SAndroid Build Coastguard Worker 
try_from(value: &BalloonWS) -> Result<Self, Self::Error>1008*bb4ee6a4SAndroid Build Coastguard Worker     fn try_from(value: &BalloonWS) -> Result<Self, Self::Error> {
1009*bb4ee6a4SAndroid Build Coastguard Worker         if value.ws.len() > VIRTIO_BALLOON_WS_MAX_NUM_BINS {
1010*bb4ee6a4SAndroid Build Coastguard Worker             return Err("too many WS buckets in source object.");
1011*bb4ee6a4SAndroid Build Coastguard Worker         }
1012*bb4ee6a4SAndroid Build Coastguard Worker 
1013*bb4ee6a4SAndroid Build Coastguard Worker         let mut ffi = Self {
1014*bb4ee6a4SAndroid Build Coastguard Worker             ws: [WorkingSetBucketFfi::new(); VIRTIO_BALLOON_WS_MAX_NUM_BINS],
1015*bb4ee6a4SAndroid Build Coastguard Worker             num_bins: value.ws.len() as u8,
1016*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
1017*bb4ee6a4SAndroid Build Coastguard Worker         };
1018*bb4ee6a4SAndroid Build Coastguard Worker         for (ffi_ws, other_ws) in ffi.ws.iter_mut().zip(value.ws.iter()) {
1019*bb4ee6a4SAndroid Build Coastguard Worker             *ffi_ws = (*other_ws).into();
1020*bb4ee6a4SAndroid Build Coastguard Worker         }
1021*bb4ee6a4SAndroid Build Coastguard Worker         Ok(ffi)
1022*bb4ee6a4SAndroid Build Coastguard Worker     }
1023*bb4ee6a4SAndroid Build Coastguard Worker }
1024*bb4ee6a4SAndroid Build Coastguard Worker 
1025*bb4ee6a4SAndroid Build Coastguard Worker impl BalloonWSFfi {
new() -> Self1026*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new() -> Self {
1027*bb4ee6a4SAndroid Build Coastguard Worker         Self {
1028*bb4ee6a4SAndroid Build Coastguard Worker             ws: [WorkingSetBucketFfi::new(); VIRTIO_BALLOON_WS_MAX_NUM_BINS],
1029*bb4ee6a4SAndroid Build Coastguard Worker             num_bins: 0,
1030*bb4ee6a4SAndroid Build Coastguard Worker             _reserved: [0; 7],
1031*bb4ee6a4SAndroid Build Coastguard Worker         }
1032*bb4ee6a4SAndroid Build Coastguard Worker     }
1033*bb4ee6a4SAndroid Build Coastguard Worker }
1034*bb4ee6a4SAndroid Build Coastguard Worker 
1035*bb4ee6a4SAndroid Build Coastguard Worker impl Default for BalloonWSFfi {
default() -> Self1036*bb4ee6a4SAndroid Build Coastguard Worker     fn default() -> Self {
1037*bb4ee6a4SAndroid Build Coastguard Worker         Self::new()
1038*bb4ee6a4SAndroid Build Coastguard Worker     }
1039*bb4ee6a4SAndroid Build Coastguard Worker }
1040*bb4ee6a4SAndroid Build Coastguard Worker 
1041*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
1042*bb4ee6a4SAndroid Build Coastguard Worker pub struct BalloonWSRConfigFfi {
1043*bb4ee6a4SAndroid Build Coastguard Worker     intervals: [u64; VIRTIO_BALLOON_WS_MAX_NUM_INTERVALS],
1044*bb4ee6a4SAndroid Build Coastguard Worker     num_intervals: u8,
1045*bb4ee6a4SAndroid Build Coastguard Worker     _reserved: [u8; 7],
1046*bb4ee6a4SAndroid Build Coastguard Worker     refresh_threshold: u64,
1047*bb4ee6a4SAndroid Build Coastguard Worker     report_threshold: u64,
1048*bb4ee6a4SAndroid Build Coastguard Worker }
1049*bb4ee6a4SAndroid Build Coastguard Worker 
1050*bb4ee6a4SAndroid Build Coastguard Worker /// Returns balloon working set of the crosvm instance whose control socket is listening on
1051*bb4ee6a4SAndroid Build Coastguard Worker /// socket_path.
1052*bb4ee6a4SAndroid Build Coastguard Worker ///
1053*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
1054*bb4ee6a4SAndroid Build Coastguard Worker ///
1055*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
1056*bb4ee6a4SAndroid Build Coastguard Worker ///
1057*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
1058*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
1059*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
1060*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_balloon_working_set( socket_path: *const c_char, ws: *mut BalloonWSFfi, actual: *mut u64, ) -> bool1061*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_balloon_working_set(
1062*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
1063*bb4ee6a4SAndroid Build Coastguard Worker     ws: *mut BalloonWSFfi,
1064*bb4ee6a4SAndroid Build Coastguard Worker     actual: *mut u64,
1065*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
1066*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
1067*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
1068*bb4ee6a4SAndroid Build Coastguard Worker             let request = &VmRequest::BalloonCommand(BalloonControlCommand::WorkingSet);
1069*bb4ee6a4SAndroid Build Coastguard Worker             if let Ok(VmResponse::BalloonWS {
1070*bb4ee6a4SAndroid Build Coastguard Worker                 ws: ref balloon_ws,
1071*bb4ee6a4SAndroid Build Coastguard Worker                 balloon_actual,
1072*bb4ee6a4SAndroid Build Coastguard Worker             }) = handle_request(request, socket_path)
1073*bb4ee6a4SAndroid Build Coastguard Worker             {
1074*bb4ee6a4SAndroid Build Coastguard Worker                 if !ws.is_null() {
1075*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: just checked that `ws` is not null.
1076*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe {
1077*bb4ee6a4SAndroid Build Coastguard Worker                         *ws = match balloon_ws.try_into() {
1078*bb4ee6a4SAndroid Build Coastguard Worker                             Ok(result) => result,
1079*bb4ee6a4SAndroid Build Coastguard Worker                             Err(_) => return false,
1080*bb4ee6a4SAndroid Build Coastguard Worker                         };
1081*bb4ee6a4SAndroid Build Coastguard Worker                     }
1082*bb4ee6a4SAndroid Build Coastguard Worker                 }
1083*bb4ee6a4SAndroid Build Coastguard Worker 
1084*bb4ee6a4SAndroid Build Coastguard Worker                 if !actual.is_null() {
1085*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY: just checked that `actual` is not null.
1086*bb4ee6a4SAndroid Build Coastguard Worker                     unsafe {
1087*bb4ee6a4SAndroid Build Coastguard Worker                         *actual = balloon_actual;
1088*bb4ee6a4SAndroid Build Coastguard Worker                     }
1089*bb4ee6a4SAndroid Build Coastguard Worker                 }
1090*bb4ee6a4SAndroid Build Coastguard Worker                 true
1091*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1092*bb4ee6a4SAndroid Build Coastguard Worker                 false
1093*bb4ee6a4SAndroid Build Coastguard Worker             }
1094*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1095*bb4ee6a4SAndroid Build Coastguard Worker             false
1096*bb4ee6a4SAndroid Build Coastguard Worker         }
1097*bb4ee6a4SAndroid Build Coastguard Worker     })
1098*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
1099*bb4ee6a4SAndroid Build Coastguard Worker }
1100*bb4ee6a4SAndroid Build Coastguard Worker 
1101*bb4ee6a4SAndroid Build Coastguard Worker /// Publically exposed version of RegisteredEvent enum, implemented as an
1102*bb4ee6a4SAndroid Build Coastguard Worker /// integral newtype for FFI safety.
1103*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
1104*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, PartialEq, Eq)]
1105*bb4ee6a4SAndroid Build Coastguard Worker pub struct RegisteredEventFfi(u32);
1106*bb4ee6a4SAndroid Build Coastguard Worker 
1107*bb4ee6a4SAndroid Build Coastguard Worker pub const REGISTERED_EVENT_VIRTIO_BALLOON_WS_REPORT: RegisteredEventFfi = RegisteredEventFfi(0);
1108*bb4ee6a4SAndroid Build Coastguard Worker pub const REGISTERED_EVENT_VIRTIO_BALLOON_RESIZE: RegisteredEventFfi = RegisteredEventFfi(1);
1109*bb4ee6a4SAndroid Build Coastguard Worker pub const REGISTERED_EVENT_VIRTIO_BALLOON_OOM_DEFLATION: RegisteredEventFfi = RegisteredEventFfi(2);
1110*bb4ee6a4SAndroid Build Coastguard Worker 
1111*bb4ee6a4SAndroid Build Coastguard Worker impl TryFrom<RegisteredEventFfi> for RegisteredEvent {
1112*bb4ee6a4SAndroid Build Coastguard Worker     type Error = &'static str;
1113*bb4ee6a4SAndroid Build Coastguard Worker 
try_from(value: RegisteredEventFfi) -> Result<Self, Self::Error>1114*bb4ee6a4SAndroid Build Coastguard Worker     fn try_from(value: RegisteredEventFfi) -> Result<Self, Self::Error> {
1115*bb4ee6a4SAndroid Build Coastguard Worker         match value.0 {
1116*bb4ee6a4SAndroid Build Coastguard Worker             0 => Ok(RegisteredEvent::VirtioBalloonWsReport),
1117*bb4ee6a4SAndroid Build Coastguard Worker             1 => Ok(RegisteredEvent::VirtioBalloonResize),
1118*bb4ee6a4SAndroid Build Coastguard Worker             2 => Ok(RegisteredEvent::VirtioBalloonOOMDeflation),
1119*bb4ee6a4SAndroid Build Coastguard Worker             _ => Err("RegisteredEventFFi outside of known RegisteredEvent enum range"),
1120*bb4ee6a4SAndroid Build Coastguard Worker         }
1121*bb4ee6a4SAndroid Build Coastguard Worker     }
1122*bb4ee6a4SAndroid Build Coastguard Worker }
1123*bb4ee6a4SAndroid Build Coastguard Worker 
1124*bb4ee6a4SAndroid Build Coastguard Worker /// Registers the connected process as a listener for `event`.
1125*bb4ee6a4SAndroid Build Coastguard Worker ///
1126*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
1127*bb4ee6a4SAndroid Build Coastguard Worker ///
1128*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
1129*bb4ee6a4SAndroid Build Coastguard Worker ///
1130*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
1131*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
1132*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
1133*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_register_events_listener( socket_path: *const c_char, listening_socket_path: *const c_char, event: RegisteredEventFfi, ) -> bool1134*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_register_events_listener(
1135*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
1136*bb4ee6a4SAndroid Build Coastguard Worker     listening_socket_path: *const c_char,
1137*bb4ee6a4SAndroid Build Coastguard Worker     event: RegisteredEventFfi,
1138*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
1139*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
1140*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
1141*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(listening_socket_path) = validate_socket_path(listening_socket_path) {
1142*bb4ee6a4SAndroid Build Coastguard Worker                 if let Ok(event) = event.try_into() {
1143*bb4ee6a4SAndroid Build Coastguard Worker                     let request = VmRequest::RegisterListener {
1144*bb4ee6a4SAndroid Build Coastguard Worker                         event,
1145*bb4ee6a4SAndroid Build Coastguard Worker                         socket_addr: listening_socket_path.to_str().unwrap().to_string(),
1146*bb4ee6a4SAndroid Build Coastguard Worker                     };
1147*bb4ee6a4SAndroid Build Coastguard Worker                     vms_request(&request, socket_path).is_ok()
1148*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
1149*bb4ee6a4SAndroid Build Coastguard Worker                     false
1150*bb4ee6a4SAndroid Build Coastguard Worker                 }
1151*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1152*bb4ee6a4SAndroid Build Coastguard Worker                 false
1153*bb4ee6a4SAndroid Build Coastguard Worker             }
1154*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1155*bb4ee6a4SAndroid Build Coastguard Worker             false
1156*bb4ee6a4SAndroid Build Coastguard Worker         }
1157*bb4ee6a4SAndroid Build Coastguard Worker     })
1158*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
1159*bb4ee6a4SAndroid Build Coastguard Worker }
1160*bb4ee6a4SAndroid Build Coastguard Worker 
1161*bb4ee6a4SAndroid Build Coastguard Worker /// Unegisters the connected process as a listener for `event`.
1162*bb4ee6a4SAndroid Build Coastguard Worker ///
1163*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
1164*bb4ee6a4SAndroid Build Coastguard Worker ///
1165*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
1166*bb4ee6a4SAndroid Build Coastguard Worker ///
1167*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
1168*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
1169*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
1170*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_unregister_events_listener( socket_path: *const c_char, listening_socket_path: *const c_char, event: RegisteredEventFfi, ) -> bool1171*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_unregister_events_listener(
1172*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
1173*bb4ee6a4SAndroid Build Coastguard Worker     listening_socket_path: *const c_char,
1174*bb4ee6a4SAndroid Build Coastguard Worker     event: RegisteredEventFfi,
1175*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
1176*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
1177*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
1178*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(listening_socket_path) = validate_socket_path(listening_socket_path) {
1179*bb4ee6a4SAndroid Build Coastguard Worker                 if let Ok(event) = event.try_into() {
1180*bb4ee6a4SAndroid Build Coastguard Worker                     let request = VmRequest::UnregisterListener {
1181*bb4ee6a4SAndroid Build Coastguard Worker                         event,
1182*bb4ee6a4SAndroid Build Coastguard Worker                         socket_addr: listening_socket_path.to_str().unwrap().to_string(),
1183*bb4ee6a4SAndroid Build Coastguard Worker                     };
1184*bb4ee6a4SAndroid Build Coastguard Worker                     vms_request(&request, socket_path).is_ok()
1185*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
1186*bb4ee6a4SAndroid Build Coastguard Worker                     false
1187*bb4ee6a4SAndroid Build Coastguard Worker                 }
1188*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1189*bb4ee6a4SAndroid Build Coastguard Worker                 false
1190*bb4ee6a4SAndroid Build Coastguard Worker             }
1191*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1192*bb4ee6a4SAndroid Build Coastguard Worker             false
1193*bb4ee6a4SAndroid Build Coastguard Worker         }
1194*bb4ee6a4SAndroid Build Coastguard Worker     })
1195*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
1196*bb4ee6a4SAndroid Build Coastguard Worker }
1197*bb4ee6a4SAndroid Build Coastguard Worker 
1198*bb4ee6a4SAndroid Build Coastguard Worker /// Unegisters the connected process as a listener for all events.
1199*bb4ee6a4SAndroid Build Coastguard Worker ///
1200*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
1201*bb4ee6a4SAndroid Build Coastguard Worker ///
1202*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
1203*bb4ee6a4SAndroid Build Coastguard Worker ///
1204*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
1205*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
1206*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
1207*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_unregister_listener( socket_path: *const c_char, listening_socket_path: *const c_char, ) -> bool1208*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_unregister_listener(
1209*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
1210*bb4ee6a4SAndroid Build Coastguard Worker     listening_socket_path: *const c_char,
1211*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
1212*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
1213*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
1214*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(listening_socket_path) = validate_socket_path(listening_socket_path) {
1215*bb4ee6a4SAndroid Build Coastguard Worker                 let request = VmRequest::Unregister {
1216*bb4ee6a4SAndroid Build Coastguard Worker                     socket_addr: listening_socket_path.to_str().unwrap().to_string(),
1217*bb4ee6a4SAndroid Build Coastguard Worker                 };
1218*bb4ee6a4SAndroid Build Coastguard Worker                 vms_request(&request, socket_path).is_ok()
1219*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1220*bb4ee6a4SAndroid Build Coastguard Worker                 false
1221*bb4ee6a4SAndroid Build Coastguard Worker             }
1222*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1223*bb4ee6a4SAndroid Build Coastguard Worker             false
1224*bb4ee6a4SAndroid Build Coastguard Worker         }
1225*bb4ee6a4SAndroid Build Coastguard Worker     })
1226*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
1227*bb4ee6a4SAndroid Build Coastguard Worker }
1228*bb4ee6a4SAndroid Build Coastguard Worker 
1229*bb4ee6a4SAndroid Build Coastguard Worker /// Set Working Set Reporting config in guest.
1230*bb4ee6a4SAndroid Build Coastguard Worker ///
1231*bb4ee6a4SAndroid Build Coastguard Worker /// The function returns true on success or false if an error occurred.
1232*bb4ee6a4SAndroid Build Coastguard Worker ///
1233*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
1234*bb4ee6a4SAndroid Build Coastguard Worker ///
1235*bb4ee6a4SAndroid Build Coastguard Worker /// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of
1236*bb4ee6a4SAndroid Build Coastguard Worker /// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no
1237*bb4ee6a4SAndroid Build Coastguard Worker /// null pointers are passed.
1238*bb4ee6a4SAndroid Build Coastguard Worker #[no_mangle]
crosvm_client_balloon_wsr_config( socket_path: *const c_char, config: *const BalloonWSRConfigFfi, ) -> bool1239*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe extern "C" fn crosvm_client_balloon_wsr_config(
1240*bb4ee6a4SAndroid Build Coastguard Worker     socket_path: *const c_char,
1241*bb4ee6a4SAndroid Build Coastguard Worker     config: *const BalloonWSRConfigFfi,
1242*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
1243*bb4ee6a4SAndroid Build Coastguard Worker     catch_unwind(|| {
1244*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket_path) = validate_socket_path(socket_path) {
1245*bb4ee6a4SAndroid Build Coastguard Worker             if !config.is_null() {
1246*bb4ee6a4SAndroid Build Coastguard Worker                 // SAFETY: just checked that `config` is not null.
1247*bb4ee6a4SAndroid Build Coastguard Worker                 unsafe {
1248*bb4ee6a4SAndroid Build Coastguard Worker                     if (*config).num_intervals > VIRTIO_BALLOON_WS_MAX_NUM_INTERVALS as u8 {
1249*bb4ee6a4SAndroid Build Coastguard Worker                         return false;
1250*bb4ee6a4SAndroid Build Coastguard Worker                     }
1251*bb4ee6a4SAndroid Build Coastguard Worker                     let mut actual_bins = vec![];
1252*bb4ee6a4SAndroid Build Coastguard Worker                     for idx in 0..(*config).num_intervals {
1253*bb4ee6a4SAndroid Build Coastguard Worker                         actual_bins.push((*config).intervals[idx as usize]);
1254*bb4ee6a4SAndroid Build Coastguard Worker                     }
1255*bb4ee6a4SAndroid Build Coastguard Worker                     let refresh_threshold = match u32::try_from((*config).refresh_threshold) {
1256*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(r_t) => r_t,
1257*bb4ee6a4SAndroid Build Coastguard Worker                         Err(_) => return false,
1258*bb4ee6a4SAndroid Build Coastguard Worker                     };
1259*bb4ee6a4SAndroid Build Coastguard Worker                     let report_threshold = match u32::try_from((*config).report_threshold) {
1260*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(r_p) => r_p,
1261*bb4ee6a4SAndroid Build Coastguard Worker                         Err(_) => return false,
1262*bb4ee6a4SAndroid Build Coastguard Worker                     };
1263*bb4ee6a4SAndroid Build Coastguard Worker                     let request =
1264*bb4ee6a4SAndroid Build Coastguard Worker                         VmRequest::BalloonCommand(BalloonControlCommand::WorkingSetConfig {
1265*bb4ee6a4SAndroid Build Coastguard Worker                             bins: actual_bins
1266*bb4ee6a4SAndroid Build Coastguard Worker                                 .iter()
1267*bb4ee6a4SAndroid Build Coastguard Worker                                 .map(|&b| u32::try_from(b).unwrap())
1268*bb4ee6a4SAndroid Build Coastguard Worker                                 .collect(),
1269*bb4ee6a4SAndroid Build Coastguard Worker                             refresh_threshold,
1270*bb4ee6a4SAndroid Build Coastguard Worker                             report_threshold,
1271*bb4ee6a4SAndroid Build Coastguard Worker                         });
1272*bb4ee6a4SAndroid Build Coastguard Worker                     vms_request(&request, socket_path).is_ok()
1273*bb4ee6a4SAndroid Build Coastguard Worker                 }
1274*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1275*bb4ee6a4SAndroid Build Coastguard Worker                 false
1276*bb4ee6a4SAndroid Build Coastguard Worker             }
1277*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1278*bb4ee6a4SAndroid Build Coastguard Worker             false
1279*bb4ee6a4SAndroid Build Coastguard Worker         }
1280*bb4ee6a4SAndroid Build Coastguard Worker     })
1281*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap_or(false)
1282*bb4ee6a4SAndroid Build Coastguard Worker }
1283