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