xref: /aosp_15_r20/external/crosvm/devices/src/suspendable.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Trait to suspend virtual hardware.
6 
7 use anyhow::anyhow;
8 use serde::Deserialize;
9 use serde::Serialize;
10 
11 #[derive(Copy, Clone, Serialize, Deserialize)]
12 pub enum DeviceState {
13     Awake,
14     Sleep,
15 }
16 
17 /// This trait provides the functions required for a device to implement to successfully
18 /// suspend/resume in crosvm.
19 pub trait Suspendable {
20     /// Save the device state in an image that can be restored.
snapshot(&mut self) -> anyhow::Result<serde_json::Value>21     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
22         Err(anyhow!(
23             "Suspendable::snapshot not implemented for {}",
24             std::any::type_name::<Self>()
25         ))
26     }
27     /// Load a saved snapshot of an image.
restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()>28     fn restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()> {
29         Err(anyhow!(
30             "Suspendable::restore not implemented for {}",
31             std::any::type_name::<Self>()
32         ))
33     }
34     /// Stop all threads related to the device.
35     /// Sleep should be idempotent.
sleep(&mut self) -> anyhow::Result<()>36     fn sleep(&mut self) -> anyhow::Result<()> {
37         Err(anyhow!(
38             "Suspendable::sleep not implemented for {}",
39             std::any::type_name::<Self>()
40         ))
41     }
42     /// Create/Resume all threads related to the device.
43     /// Wake should be idempotent.
wake(&mut self) -> anyhow::Result<()>44     fn wake(&mut self) -> anyhow::Result<()> {
45         Err(anyhow!(
46             "Suspendable::wake not implemented for {}",
47             std::any::type_name::<Self>()
48         ))
49     }
50 }
51 
52 // General tests that should pass on all suspendables.
53 // Do implement device-specific tests to validate the functionality of the device.
54 // Those tests are not a replacement for regular tests. Only an extension specific to the trait's
55 // basic functionality.
56 /// `dev` is the device.
57 /// `modfun` is the function name of the function that would modify the device. The function call
58 /// should modify the device so that a snapshot taken after the function call would be different
59 /// from a snapshot taken before the function call.
60 #[macro_export]
61 macro_rules! suspendable_tests {
62     ($name:ident, $dev:expr, $modfun:ident) => {
63         mod $name {
64             use super::*;
65 
66             #[test]
67             fn test_sleep_idempotent() {
68                 let unit = &mut $dev;
69                 let res = unit.sleep();
70                 let res2 = unit.sleep();
71                 match res {
72                     Ok(()) => (),
73                     Err(e) => println!("{}", e),
74                 }
75                 match res2 {
76                     Ok(()) => (),
77                     Err(e) => println!("idempotent: {}", e),
78                 }
79             }
80 
81             #[test]
82             fn test_snapshot_restore() {
83                 let unit = &mut $dev;
84                 let snap = unit.snapshot();
85                 match snap {
86                     Ok(snap_res) => {
87                         let res = unit.restore(snap_res);
88                         match res {
89                             Ok(()) => (),
90                             Err(e) => println!("{}", e),
91                         }
92                     }
93                     Err(e) => println!("{}", e),
94                 }
95             }
96 
97             #[test]
98             fn test_sleep_snapshot() {
99                 let unit = &mut $dev;
100                 let sleep_result = unit.sleep();
101                 let snap_result = unit.snapshot();
102                 match sleep_result {
103                     Ok(()) => (),
104                     Err(e) => println!("{}", e),
105                 }
106                 match snap_result {
107                     Ok(_res) => (),
108                     Err(e) => println!("{}", e),
109                 }
110             }
111 
112             #[test]
113             fn test_sleep_snapshot_restore_wake() {
114                 let unit = &mut $dev;
115                 let sleep_result = unit.sleep();
116                 let snap_result = unit.snapshot();
117                 match sleep_result {
118                     Ok(()) => (),
119                     Err(e) => println!("{}", e),
120                 }
121                 match snap_result {
122                     Ok(snap_res) => {
123                         let res = unit.restore(snap_res);
124                         match res {
125                             Ok(()) => (),
126                             Err(e) => println!("{}", e),
127                         }
128                     }
129                     Err(e) => println!("{}", e),
130                 }
131                 let wake_res = unit.wake();
132                 match wake_res {
133                     Ok(()) => (),
134                     Err(e) => println!("{}", e),
135                 }
136             }
137 
138             #[test]
139             fn test_sleep_snapshot_wake() {
140                 let unit = &mut $dev;
141                 let sleep_result = unit.sleep();
142                 let snap_result = unit.snapshot();
143                 match sleep_result {
144                     Ok(()) => (),
145                     Err(e) => println!("{}", e),
146                 }
147                 match snap_result {
148                     Ok(_snap_res) => (),
149                     Err(e) => println!("{}", e),
150                 }
151                 let wake_res = unit.wake();
152                 match wake_res {
153                     Ok(()) => (),
154                     Err(e) => println!("{}", e),
155                 }
156             }
157 
158             #[test]
159             fn test_snapshot() {
160                 let unit = &mut $dev;
161                 let snap_result = unit.snapshot();
162                 match snap_result {
163                     Ok(_snap_res) => (),
164                     Err(e) => println!("{}", e),
165                 }
166             }
167 
168             #[test]
169             fn test_suspend_mod_restore() {
170                 let unit = &mut $dev;
171                 let snap_result = unit.snapshot().expect("failed to take initial snapshot");
172                 $modfun(unit);
173                 unit.restore(snap_result.clone())
174                     .expect("failed to restore snapshot");
175                 let snap2_result = unit
176                     .snapshot()
177                     .expect("failed to take snapshot after modification");
178                 assert_eq!(snap_result, snap2_result);
179             }
180 
181             #[test]
182             fn test_suspend_mod() {
183                 let unit = &mut $dev;
184                 let snap_result = unit.snapshot().expect("failed to take initial snapshot");
185                 $modfun(unit);
186                 let snap2_result = unit
187                     .snapshot()
188                     .expect("failed to take snapshot after modification");
189                 assert_ne!(snap_result, snap2_result)
190             }
191         }
192     };
193 }
194