devices/
bat.rs

1// Copyright 2020 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
5use std::ops::DerefMut;
6use std::sync::Arc;
7use std::time::Duration;
8use std::time::SystemTime;
9
10use acpi_tables::aml;
11use acpi_tables::aml::Aml;
12use anyhow::bail;
13use anyhow::Context;
14use base::error;
15use base::warn;
16use base::AsRawDescriptor;
17use base::Event;
18use base::EventToken;
19use base::RawDescriptor;
20use base::ReadNotifier;
21use base::Tube;
22use base::WaitContext;
23use base::WorkerThread;
24use power_monitor::BatteryStatus;
25use power_monitor::CreatePowerClientFn;
26use power_monitor::CreatePowerMonitorFn;
27use power_monitor::PowerClient;
28use remain::sorted;
29use serde::Deserialize;
30use serde::Serialize;
31use snapshot::AnySnapshot;
32use sync::Mutex;
33use thiserror::Error;
34use vm_control::BatControlCommand;
35use vm_control::BatControlResult;
36use vm_control::DeviceId;
37use vm_control::PlatformDeviceId;
38
39use crate::BusAccessInfo;
40use crate::BusDevice;
41use crate::IrqLevelEvent;
42use crate::Suspendable;
43
44/// Errors for battery devices.
45#[sorted]
46#[derive(Error, Debug)]
47pub enum BatteryError {
48    #[error("Non 32-bit mmio address space")]
49    Non32BitMmioAddress,
50}
51
52type Result<T> = std::result::Result<T, BatteryError>;
53
54/// the GoldFish Battery MMIO length.
55pub const GOLDFISHBAT_MMIO_LEN: u64 = 0x1000;
56
57/// Configuration of fake battery status information.
58#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Copy)]
59pub enum BatConfig {
60    /// Propagates host's battery status
61    #[default]
62    Real,
63    /// Fake on battery status. Simulates a disconnected AC adapter.
64    /// This forces ac_online to false and sets the battery status
65    /// to DISCHARGING
66    Fake {
67        // Sets the maximum battery capacity reported to the guest
68        max_capacity: u32,
69    },
70}
71
72#[derive(Clone, Serialize, Deserialize)]
73struct GoldfishBatteryState {
74    // interrupt state
75    int_status: u32,
76    int_enable: u32,
77    // AC state
78    ac_online: u32,
79    // Battery state
80    status: u32,
81    health: u32,
82    present: u32,
83    capacity: u32,
84    voltage: u32,
85    current: u32,
86    charge_counter: u32,
87    charge_full: u32,
88    // bat_config is used for goldfish battery to report fake battery to the guest.
89    bat_config: BatConfig,
90}
91
92macro_rules! create_battery_func {
93    // $property: the battery property which is going to be modified.
94    // $ty: the type annotation of value argument
95    // $int: the interrupt status which is going to be set to notify the guest.
96    ($fn:ident, $property:ident, $ty:ty, $int:ident) => {
97        pub(crate) fn $fn(&mut self, value: $ty) -> bool {
98            let old = std::mem::replace(&mut self.$property, value);
99            old != self.$property && self.set_int_status($int)
100        }
101    };
102}
103
104impl GoldfishBatteryState {
105    fn set_int_status(&mut self, mask: u32) -> bool {
106        let old = self.int_status;
107        self.int_status |= self.int_enable & mask;
108        old != self.int_status
109    }
110
111    fn int_status(&self) -> u32 {
112        self.int_status
113    }
114
115    create_battery_func!(set_ac_online, ac_online, u32, AC_STATUS_CHANGED);
116
117    create_battery_func!(set_status, status, u32, BATTERY_STATUS_CHANGED);
118
119    create_battery_func!(set_health, health, u32, BATTERY_STATUS_CHANGED);
120
121    create_battery_func!(set_present, present, u32, BATTERY_STATUS_CHANGED);
122
123    create_battery_func!(set_capacity, capacity, u32, BATTERY_STATUS_CHANGED);
124
125    create_battery_func!(set_voltage, voltage, u32, BATTERY_STATUS_CHANGED);
126
127    create_battery_func!(set_current, current, u32, BATTERY_STATUS_CHANGED);
128
129    create_battery_func!(
130        set_charge_counter,
131        charge_counter,
132        u32,
133        BATTERY_STATUS_CHANGED
134    );
135
136    create_battery_func!(set_charge_full, charge_full, u32, BATTERY_STATUS_CHANGED);
137
138    create_battery_func!(set_bat_config, bat_config, BatConfig, BATTERY_INT_MASK);
139
140    fn update_from_power_data(&mut self, data: power_monitor::PowerData) -> bool {
141        // Each set_* function called below returns true when interrupt bits
142        // (*_STATUS_CHANGED) changed.
143        let mut inject_irq = self.set_ac_online(data.ac_online.into());
144
145        match data.battery {
146            Some(battery_data) => {
147                inject_irq |= self.set_present(1);
148                inject_irq |= self.set_capacity(battery_data.percent);
149                let battery_status = match battery_data.status {
150                    BatteryStatus::Unknown => BATTERY_STATUS_VAL_UNKNOWN,
151                    BatteryStatus::Charging => BATTERY_STATUS_VAL_CHARGING,
152                    BatteryStatus::Discharging => BATTERY_STATUS_VAL_DISCHARGING,
153                    BatteryStatus::NotCharging => BATTERY_STATUS_VAL_NOT_CHARGING,
154                };
155                inject_irq |= self.set_status(battery_status);
156                inject_irq |= self.set_voltage(battery_data.voltage);
157                inject_irq |= self.set_current(battery_data.current);
158                inject_irq |= self.set_charge_counter(battery_data.charge_counter);
159                inject_irq |= self.set_charge_full(battery_data.charge_full);
160            }
161            None => {
162                inject_irq |= self.set_present(0);
163            }
164        }
165        inject_irq
166    }
167}
168
169enum BatInitializationState {
170    NotYet,
171    Pending(Box<dyn PowerClient>),
172    Done,
173}
174
175/// GoldFish Battery state
176pub struct GoldfishBattery {
177    state: Arc<Mutex<GoldfishBatteryState>>,
178    mmio_base: u32,
179    irq_num: u32,
180    irq_evt: IrqLevelEvent,
181    activated: bool,
182    monitor_thread: Option<WorkerThread<()>>,
183    tube: Option<Tube>,
184    create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
185    create_powerd_client: Option<Box<dyn CreatePowerClientFn>>,
186    init_state: Arc<Mutex<BatInitializationState>>,
187}
188
189#[derive(Serialize, Deserialize)]
190struct GoldfishBatterySnapshot {
191    state: GoldfishBatteryState,
192    mmio_base: u32,
193    irq_num: u32,
194    activated: bool,
195}
196
197/// Goldfish Battery MMIO offset
198const BATTERY_INT_STATUS: u32 = 0;
199const BATTERY_INT_ENABLE: u32 = 0x4;
200const BATTERY_AC_ONLINE: u32 = 0x8;
201const BATTERY_STATUS: u32 = 0xC;
202const BATTERY_HEALTH: u32 = 0x10;
203const BATTERY_PRESENT: u32 = 0x14;
204const BATTERY_CAPACITY: u32 = 0x18;
205const BATTERY_VOLTAGE: u32 = 0x1C;
206const BATTERY_TEMP: u32 = 0x20;
207const BATTERY_CHARGE_COUNTER: u32 = 0x24;
208const BATTERY_VOLTAGE_MAX: u32 = 0x28;
209const BATTERY_CURRENT_MAX: u32 = 0x2C;
210const BATTERY_CURRENT_NOW: u32 = 0x30;
211const BATTERY_CURRENT_AVG: u32 = 0x34;
212const BATTERY_CHARGE_FULL_UAH: u32 = 0x38;
213const BATTERY_CYCLE_COUNT: u32 = 0x40;
214
215/// Goldfish Battery interrupt bits
216const BATTERY_STATUS_CHANGED: u32 = 1 << 0;
217const AC_STATUS_CHANGED: u32 = 1 << 1;
218const BATTERY_INT_MASK: u32 = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED;
219
220/// Goldfish Battery status
221const BATTERY_STATUS_VAL_UNKNOWN: u32 = 0;
222const BATTERY_STATUS_VAL_CHARGING: u32 = 1;
223const BATTERY_STATUS_VAL_DISCHARGING: u32 = 2;
224const BATTERY_STATUS_VAL_NOT_CHARGING: u32 = 3;
225
226/// Goldfish Battery health
227const BATTERY_HEALTH_VAL_UNKNOWN: u32 = 0;
228
229// Goldfish ac online status
230const AC_ONLINE_VAL_OFFLINE: u32 = 0;
231
232#[derive(EventToken)]
233pub(crate) enum Token {
234    Commands,
235    Resample,
236    Kill,
237    Monitor,
238}
239
240fn command_monitor(
241    tube: Tube,
242    irq_evt: IrqLevelEvent,
243    kill_evt: Event,
244    state: Arc<Mutex<GoldfishBatteryState>>,
245    create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
246    init_state: Arc<Mutex<BatInitializationState>>,
247) {
248    // Use `get_read_notifier()` rather than `&tube` (`AsRawDescriptor`) so Windows `WaitContext`
249    // waits on the `StreamChannel` read-notification `Event` instead of the raw named-pipe handle
250    // (which is immediately signaled after connection and would cause `tube.recv()` to block
251    // forever on an empty pipe).
252    let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
253        (tube.get_read_notifier(), Token::Commands),
254        (irq_evt.get_resample(), Token::Resample),
255        (&kill_evt, Token::Kill),
256    ]) {
257        Ok(pc) => pc,
258        Err(e) => {
259            error!("failed to build WaitContext: {}", e);
260            return;
261        }
262    };
263
264    let mut power_monitor = match create_power_monitor {
265        Some(f) => match f() {
266            Ok(p) => match wait_ctx.add(p.get_read_notifier(), Token::Monitor) {
267                Ok(()) => Some(p),
268                Err(e) => {
269                    error!("failed to add power monitor to poll context: {}", e);
270                    None
271                }
272            },
273            Err(e) => {
274                error!("failed to create power monitor: {}", e);
275                None
276            }
277        },
278        None => None,
279    };
280
281    'poll: loop {
282        let events = match wait_ctx.wait() {
283            Ok(v) => v,
284            Err(e) => {
285                error!("error while polling for events: {}", e);
286                break;
287            }
288        };
289
290        for event in events.iter().filter(|e| e.is_readable) {
291            match event.token {
292                Token::Commands => {
293                    let req = match tube.recv() {
294                        Ok(req) => req,
295                        Err(e) => {
296                            error!("failed to receive request: {}", e);
297                            continue;
298                        }
299                    };
300
301                    let mut bat_state = state.lock();
302                    let inject_irq = match req {
303                        BatControlCommand::SetStatus(status) => bat_state.set_status(status.into()),
304                        BatControlCommand::SetHealth(health) => bat_state.set_health(health.into()),
305                        BatControlCommand::SetPresent(present) => {
306                            let v = present != 0;
307                            bat_state.set_present(v.into())
308                        }
309                        BatControlCommand::SetCapacity(capacity) => {
310                            let v = std::cmp::min(capacity, 100);
311                            bat_state.set_capacity(v)
312                        }
313                        BatControlCommand::SetACOnline(ac_online) => {
314                            let v = ac_online != 0;
315                            bat_state.set_ac_online(v.into())
316                        }
317                        BatControlCommand::SetFakeBatConfig(max_capacity) => {
318                            let max_capacity = std::cmp::min(max_capacity, 100);
319                            bat_state.set_bat_config(BatConfig::Fake { max_capacity })
320                        }
321                        BatControlCommand::CancelFakeConfig => {
322                            bat_state.set_bat_config(BatConfig::Real)
323                        }
324                    };
325
326                    if inject_irq {
327                        let _ = irq_evt.trigger();
328                    }
329
330                    if let Err(e) = tube.send(&BatControlResult::Ok) {
331                        error!("failed to send response: {}", e);
332                    }
333                }
334
335                Token::Monitor => {
336                    // Safe because power_monitor must be populated if Token::Monitor is triggered.
337                    let power_monitor = power_monitor.as_mut().unwrap();
338
339                    let data = match power_monitor.read_message() {
340                        Ok(Some(d)) => d,
341                        Ok(None) => continue,
342                        Err(e) => {
343                            error!("failed to read new power data: {}", e);
344                            continue;
345                        }
346                    };
347
348                    let inject_irq = {
349                        // Lock `init_state` before `state` to match the lock order in
350                        // `initialize_battery_state()` and atomically mark initialization as
351                        // `Done` with the `state` update.
352                        let mut init_state = init_state.lock();
353                        let mut bat_state = state.lock();
354
355                        // If `inject_irq` is true after we attempt to update each field, inject
356                        // an interrupt.
357                        let inject_irq = bat_state.update_from_power_data(data);
358                        *init_state = BatInitializationState::Done;
359                        inject_irq
360                    };
361
362                    if inject_irq {
363                        let _ = irq_evt.trigger();
364                    }
365                }
366
367                Token::Resample => {
368                    irq_evt.clear_resample();
369                    if state.lock().int_status() != 0 {
370                        let _ = irq_evt.trigger();
371                    }
372                }
373
374                Token::Kill => break 'poll,
375            }
376        }
377    }
378}
379
380impl GoldfishBattery {
381    /// The interval in milli seconds between DBus requests to powerd.  This is used to rate-limit
382    /// requests to avoid overwhelming the power daemon.
383    pub(crate) const POWERD_REQ_INTERVAL_MS: u64 = 1000;
384
385    /// Create GoldfishBattery device model
386    ///
387    /// * `mmio_base` - The 32-bit mmio base address.
388    /// * `irq_num` - The corresponding interrupt number of the irq_evt which will be put into the
389    ///   ACPI DSDT.
390    /// * `irq_evt` - The interrupt event used to notify driver about the battery properties
391    ///   changing.
392    /// * `socket` - Battery control socket
393    pub fn new(
394        mmio_base: u64,
395        irq_num: u32,
396        irq_evt: IrqLevelEvent,
397        tube: Tube,
398        create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
399        create_powerd_client: Option<Box<dyn CreatePowerClientFn>>,
400    ) -> Result<Self> {
401        if mmio_base + GOLDFISHBAT_MMIO_LEN - 1 > u32::MAX as u64 {
402            return Err(BatteryError::Non32BitMmioAddress);
403        }
404        let state = Arc::new(Mutex::new(GoldfishBatteryState {
405            capacity: 50,
406            health: BATTERY_HEALTH_VAL_UNKNOWN,
407            present: 1,
408            status: BATTERY_STATUS_VAL_UNKNOWN,
409            ac_online: 1,
410            int_enable: 0,
411            int_status: 0,
412            voltage: 0,
413            current: 0,
414            charge_counter: 0,
415            charge_full: 0,
416            bat_config: BatConfig::Real,
417        }));
418
419        Ok(GoldfishBattery {
420            state,
421            mmio_base: mmio_base as u32,
422            irq_num,
423            irq_evt,
424            activated: false,
425            monitor_thread: None,
426            tube: Some(tube),
427            create_power_monitor,
428            create_powerd_client,
429            init_state: Arc::new(Mutex::new(BatInitializationState::NotYet)),
430        })
431    }
432
433    /// return the descriptors used by this device
434    pub fn keep_rds(&self) -> Vec<RawDescriptor> {
435        let mut rds = vec![
436            self.irq_evt.get_trigger().as_raw_descriptor(),
437            self.irq_evt.get_resample().as_raw_descriptor(),
438        ];
439
440        if let Some(tube) = &self.tube {
441            rds.push(tube.as_raw_descriptor());
442        }
443
444        rds
445    }
446
447    /// start a monitor thread to monitor the events from host
448    fn start_monitor(&mut self) {
449        if self.activated {
450            return;
451        }
452
453        if let Some(tube) = self.tube.take() {
454            let irq_evt = self.irq_evt.try_clone().unwrap();
455            let bat_state = self.state.clone();
456            let create_monitor_fn = self.create_power_monitor.take();
457            let init_state = self.init_state.clone();
458            self.monitor_thread = Some(WorkerThread::start(self.debug_label(), move |kill_evt| {
459                command_monitor(
460                    tube,
461                    irq_evt,
462                    kill_evt,
463                    bat_state,
464                    create_monitor_fn,
465                    init_state,
466                )
467            }));
468            self.activated = true;
469        }
470    }
471
472    fn initialize_battery_state(&mut self) -> anyhow::Result<()> {
473        let mut init_state = self.init_state.lock();
474        let power_client = match (init_state.deref_mut(), &self.create_powerd_client) {
475            (BatInitializationState::NotYet, None) => {
476                // No need to initialize the state via DBus.
477                return Ok(());
478            }
479            (BatInitializationState::NotYet, Some(f)) => {
480                // Initialize power_client
481                let client = match f() {
482                    Ok(c) => c,
483                    Err(e) => bail!("failed to connect to the powerd: {:#}", e),
484                };
485                // Save power_client to init_state
486                *init_state = BatInitializationState::Pending(client);
487
488                let power_client = match init_state.deref_mut() {
489                    BatInitializationState::Pending(ref mut power_client) => power_client.as_mut(),
490                    _ => unreachable!("init_state should be Pending"),
491                };
492                power_client
493            }
494            (BatInitializationState::Pending(ref mut power_client), _) => power_client.as_mut(),
495            // `command_monitor()` may mark `init_state` as `Done` after `battery_init_done()`
496            // returns false and before `initialize_battery_state()` acquires `init_state`.
497            (BatInitializationState::Done, _) => return Ok(()),
498        };
499
500        if let Some(prev_call) = power_client.last_request_timestamp() {
501            // Fail if the last request was sent within 1 second.
502            let now = SystemTime::now();
503            let duration = now
504                .duration_since(prev_call)
505                .context("failed to calculate time for dbus request")?;
506            if duration < Duration::from_millis(Self::POWERD_REQ_INTERVAL_MS) {
507                return Ok(());
508            }
509        }
510
511        // Release `init_state` while waiting on the blocking `get_power_data()` D-Bus call so
512        // `command_monitor()` does not block on `init_state` when handling `PowerSupplyPoll`.
513        let BatInitializationState::Pending(mut power_client) =
514            std::mem::replace(&mut *init_state, BatInitializationState::NotYet)
515        else {
516            unreachable!("init_state should be Pending");
517        };
518        drop(init_state);
519
520        let data = match power_client.get_power_data() {
521            Ok(data) => data,
522            Err(e) => {
523                let mut init_state = self.init_state.lock();
524                if matches!(*init_state, BatInitializationState::Done) {
525                    return Ok(());
526                }
527                *init_state = BatInitializationState::Pending(power_client);
528                bail!("failed to get response from powerd: {:#}", e);
529            }
530        };
531
532        drop(power_client);
533
534        // Lock `init_state` before `self.state` to match `command_monitor()`. Hold `init_state`
535        // while updating `self.state` so `command_monitor()` and `initialize_battery_state()`
536        // cannot interleave and overwrite fresher monitor state.
537        let mut init_state = self.init_state.lock();
538        if matches!(*init_state, BatInitializationState::Done) {
539            return Ok(());
540        }
541        *init_state = BatInitializationState::Done;
542
543        self.state.lock().update_from_power_data(data);
544        Ok(())
545    }
546
547    fn battery_init_done(&self) -> bool {
548        matches!(*self.init_state.lock(), BatInitializationState::Done)
549    }
550}
551
552impl Drop for GoldfishBattery {
553    fn drop(&mut self) {
554        if let Err(e) = self.sleep() {
555            error!("{}", e);
556        };
557    }
558}
559
560impl BusDevice for GoldfishBattery {
561    fn device_id(&self) -> DeviceId {
562        PlatformDeviceId::GoldfishBattery.into()
563    }
564
565    fn debug_label(&self) -> String {
566        "GoldfishBattery".to_owned()
567    }
568
569    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
570        if data.len() != std::mem::size_of::<u32>() {
571            warn!(
572                "{}: unsupported read length {}, only support 4bytes read",
573                self.debug_label(),
574                data.len()
575            );
576            return;
577        }
578
579        // Before first read, we try to ask powerd the actual power data to initialize `self.state`.
580        if !self.battery_init_done() {
581            if let Err(e) = self.initialize_battery_state() {
582                error!(
583                    "{}: failed to initialize bettery state (info={:?}): {:#}",
584                    self.debug_label(),
585                    info,
586                    e
587                );
588            }
589        }
590
591        let val = match info.offset as u32 {
592            BATTERY_INT_STATUS => {
593                // read to clear the interrupt status
594                std::mem::replace(&mut self.state.lock().int_status, 0)
595            }
596            BATTERY_INT_ENABLE => self.state.lock().int_enable,
597            BATTERY_AC_ONLINE => {
598                let bat_config = self.state.lock().bat_config;
599                match bat_config {
600                    BatConfig::Real => self.state.lock().ac_online,
601                    BatConfig::Fake { max_capacity: _ } => AC_ONLINE_VAL_OFFLINE,
602                }
603            }
604            BATTERY_STATUS => {
605                let bat_config = self.state.lock().bat_config;
606                match bat_config {
607                    BatConfig::Real => self.state.lock().status,
608                    BatConfig::Fake { max_capacity: _ } => BATTERY_STATUS_VAL_DISCHARGING,
609                }
610            }
611            BATTERY_HEALTH => self.state.lock().health,
612            BATTERY_PRESENT => self.state.lock().present,
613            BATTERY_CAPACITY => {
614                let max_capacity = match self.state.lock().bat_config {
615                    BatConfig::Real => 100,
616                    BatConfig::Fake { max_capacity } => max_capacity,
617                };
618                std::cmp::min(max_capacity, self.state.lock().capacity)
619            }
620            BATTERY_VOLTAGE => self.state.lock().voltage,
621            BATTERY_TEMP => 0,
622            BATTERY_CHARGE_COUNTER => self.state.lock().charge_counter,
623            BATTERY_VOLTAGE_MAX => 0,
624            BATTERY_CURRENT_MAX => 0,
625            BATTERY_CURRENT_NOW => self.state.lock().current,
626            BATTERY_CURRENT_AVG => 0,
627            BATTERY_CHARGE_FULL_UAH => self.state.lock().charge_full,
628            BATTERY_CYCLE_COUNT => 0,
629            _ => {
630                warn!("{}: unsupported read address {}", self.debug_label(), info);
631                return;
632            }
633        };
634
635        let val_arr = val.to_ne_bytes();
636        data.copy_from_slice(&val_arr);
637    }
638
639    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
640        if data.len() != std::mem::size_of::<u32>() {
641            warn!(
642                "{}: unsupported write length {}, only support 4bytes write",
643                self.debug_label(),
644                data.len()
645            );
646            return;
647        }
648
649        let mut val_arr = u32::to_ne_bytes(0u32);
650        val_arr.copy_from_slice(data);
651        let val = u32::from_ne_bytes(val_arr);
652
653        match info.offset as u32 {
654            BATTERY_INT_ENABLE => {
655                self.state.lock().int_enable = val;
656                if (val & BATTERY_INT_MASK) != 0 && !self.activated {
657                    self.start_monitor();
658                }
659            }
660            _ => {
661                warn!("{}: Bad write to address {}", self.debug_label(), info);
662            }
663        };
664    }
665}
666
667impl Aml for GoldfishBattery {
668    fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
669        aml::Device::new(
670            "GFBY".into(),
671            vec![
672                &aml::Name::new("_HID".into(), &"GFSH0001"),
673                &aml::Name::new(
674                    "_CRS".into(),
675                    &aml::ResourceTemplate::new(vec![
676                        &aml::Memory32Fixed::new(true, self.mmio_base, GOLDFISHBAT_MMIO_LEN as u32),
677                        &aml::Interrupt::new(true, false, false, true, self.irq_num),
678                    ]),
679                ),
680            ],
681        )
682        .to_aml_bytes(bytes);
683    }
684}
685
686impl Suspendable for GoldfishBattery {
687    fn sleep(&mut self) -> anyhow::Result<()> {
688        if let Some(thread) = self.monitor_thread.take() {
689            thread.stop();
690        }
691        Ok(())
692    }
693
694    fn wake(&mut self) -> anyhow::Result<()> {
695        if self.activated {
696            // Set activated to false for start_monitor to start monitoring again.
697            self.activated = false;
698            self.start_monitor();
699        }
700        Ok(())
701    }
702
703    fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
704        AnySnapshot::to_any(GoldfishBatterySnapshot {
705            state: self.state.lock().clone(),
706            mmio_base: self.mmio_base,
707            irq_num: self.irq_num,
708            activated: self.activated,
709        })
710        .context("failed to snapshot GoldfishBattery")
711    }
712
713    fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
714        let deser: GoldfishBatterySnapshot =
715            AnySnapshot::from_any(data).context("failed to deserialize GoldfishBattery")?;
716        {
717            let mut locked_state = self.state.lock();
718            *locked_state = deser.state;
719        }
720        self.mmio_base = deser.mmio_base;
721        self.irq_num = deser.irq_num;
722        self.activated = deser.activated;
723        Ok(())
724    }
725}
726
727#[cfg(test)]
728mod tests {
729    use std::time::SystemTime;
730
731    use super::*;
732    use crate::suspendable_tests;
733
734    fn modify_device(battery: &mut GoldfishBattery) {
735        let mut state = battery.state.lock();
736        state.set_capacity(70);
737    }
738
739    suspendable_tests! {
740        battery, GoldfishBattery::new(
741            0,
742            0,
743            IrqLevelEvent::new().unwrap(),
744            Tube::pair().unwrap().1,
745            None,
746            None,
747        ).unwrap(),
748        modify_device
749    }
750
751    // Mock power client for testing rate limiting.
752    struct MockPowerClient {
753        last_request_time: Option<SystemTime>,
754    }
755
756    impl MockPowerClient {
757        fn new(last_request_time: Option<SystemTime>) -> Self {
758            Self { last_request_time }
759        }
760    }
761
762    impl power_monitor::PowerClient for MockPowerClient {
763        fn last_request_timestamp(&self) -> Option<SystemTime> {
764            self.last_request_time
765        }
766
767        fn get_power_data(
768            &mut self,
769        ) -> std::result::Result<power_monitor::PowerData, Box<dyn std::error::Error>> {
770            self.last_request_time = Some(SystemTime::now());
771            Ok(power_monitor::PowerData {
772                ac_online: true,
773                battery: Some(power_monitor::BatteryData {
774                    percent: 50,
775                    status: power_monitor::BatteryStatus::Unknown,
776                    voltage: 0,
777                    current: 0,
778                    charge_counter: 0,
779                    charge_full: 0,
780                }),
781            })
782        }
783    }
784
785    fn create_mock_power_client(last_request_time: Option<SystemTime>) -> MockPowerClient {
786        MockPowerClient::new(last_request_time)
787    }
788
789    #[test]
790    fn test_initialize_battery_state_rate_limiting() {
791        let mmio_base = 0;
792        let irq_num = 0;
793        let irq_evt = IrqLevelEvent::new().unwrap();
794        let tube = Tube::pair().unwrap().1;
795
796        let now = SystemTime::now();
797        let recent_time =
798            now - Duration::from_millis(GoldfishBattery::POWERD_REQ_INTERVAL_MS - 500);
799
800        let mut battery = GoldfishBattery::new(
801            mmio_base,
802            irq_num,
803            irq_evt,
804            tube,
805            None,
806            Some(Box::new(move || {
807                Ok(Box::new(create_mock_power_client(Some(recent_time))))
808            })),
809        )
810        .unwrap();
811
812        assert!(matches!(battery.initialize_battery_state(), Ok(())));
813
814        // First initialization status should be pending due to rate limiting
815        assert!(matches!(
816            *battery.init_state.lock(),
817            BatInitializationState::Pending(_)
818        ));
819
820        *battery.init_state.lock() = BatInitializationState::NotYet;
821        let old_time = now - Duration::from_millis(GoldfishBattery::POWERD_REQ_INTERVAL_MS + 500);
822        // Replace the factory function to simulate an older last_request_time
823        battery.create_powerd_client = Some(Box::new(move || {
824            Ok(Box::new(create_mock_power_client(Some(old_time))))
825        }));
826
827        // Second call with old time should succeed.
828        assert!(matches!(battery.initialize_battery_state(), Ok(())));
829
830        assert!(matches!(
831            *battery.init_state.lock(),
832            BatInitializationState::Done,
833        ));
834
835        // Check if values are correctly updated.
836        let state = battery.state.lock();
837        assert_eq!(state.ac_online, 1);
838        assert_eq!(state.capacity, 50);
839    }
840
841    #[test]
842    fn test_initialize_battery_state_no_powerd_client() {
843        let mmio_base = 0;
844        let irq_num = 0;
845        let irq_evt = IrqLevelEvent::new().unwrap();
846        let tube = Tube::pair().unwrap().1;
847
848        let mut battery =
849            GoldfishBattery::new(mmio_base, irq_num, irq_evt, tube, None, None).unwrap();
850
851        assert!(matches!(battery.initialize_battery_state(), Ok(())));
852        assert!(matches!(
853            *battery.init_state.lock(),
854            BatInitializationState::NotYet,
855        ));
856    }
857
858    struct BlockingPowerMonitor {
859        poll_evt: Event,
860    }
861
862    impl ReadNotifier for BlockingPowerMonitor {
863        fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
864            &self.poll_evt
865        }
866    }
867
868    impl power_monitor::PowerMonitor for BlockingPowerMonitor {
869        fn read_message(
870            &mut self,
871        ) -> std::result::Result<Option<power_monitor::PowerData>, Box<dyn std::error::Error>>
872        {
873            self.poll_evt.wait().unwrap();
874            Ok(Some(power_monitor::PowerData {
875                ac_online: false,
876                battery: Some(power_monitor::BatteryData {
877                    percent: 80,
878                    status: power_monitor::BatteryStatus::Discharging,
879                    voltage: 0,
880                    current: 0,
881                    charge_counter: 0,
882                    charge_full: 0,
883                }),
884            }))
885        }
886    }
887
888    struct RacingPowerClient {
889        poll_evt: Event,
890        irq_trigger_evt: Event,
891        fail: bool,
892    }
893
894    impl power_monitor::PowerClient for RacingPowerClient {
895        fn last_request_timestamp(&self) -> Option<SystemTime> {
896            None
897        }
898
899        fn get_power_data(
900            &mut self,
901        ) -> std::result::Result<power_monitor::PowerData, Box<dyn std::error::Error>> {
902            // Trigger a `PowerSupplyPoll` event in `command_monitor` while `get_power_data()` is
903            // in flight, and wait until `command_monitor` finishes updating `state` and
904            // `init_state` and signals `irq_evt`.
905            self.poll_evt.signal().unwrap();
906            self.irq_trigger_evt.wait().unwrap();
907            if self.fail {
908                return Err("mock powerd error".into());
909            }
910            Ok(power_monitor::PowerData {
911                ac_online: true,
912                battery: Some(power_monitor::BatteryData {
913                    percent: 50,
914                    status: power_monitor::BatteryStatus::Charging,
915                    voltage: 0,
916                    current: 0,
917                    charge_counter: 0,
918                    charge_full: 0,
919                }),
920            })
921        }
922    }
923
924    #[test]
925    fn test_concurrent_monitor_and_initialize_no_deadlock() {
926        let irq_evt = IrqLevelEvent::new().unwrap();
927        let irq_trigger_evt = irq_evt.get_trigger().try_clone().unwrap();
928        let (_control_tube, device_tube) = Tube::pair().unwrap();
929        let poll_evt = Event::new().unwrap();
930
931        let poll_evt_monitor = poll_evt.try_clone().unwrap();
932        let create_monitor: Box<dyn CreatePowerMonitorFn> = Box::new(move || {
933            Ok(Box::new(BlockingPowerMonitor {
934                poll_evt: poll_evt_monitor.try_clone().unwrap(),
935            }))
936        });
937
938        let create_client: Box<dyn CreatePowerClientFn> = Box::new(move || {
939            Ok(Box::new(RacingPowerClient {
940                poll_evt: poll_evt.try_clone().unwrap(),
941                irq_trigger_evt: irq_trigger_evt.try_clone().unwrap(),
942                fail: false,
943            }))
944        });
945
946        let mut battery = GoldfishBattery::new(
947            0,
948            0,
949            irq_evt,
950            device_tube,
951            Some(create_monitor),
952            Some(create_client),
953        )
954        .unwrap();
955
956        // Simulate a prior `None` battery update (`present == 0`), enable interrupts, and start
957        // `command_monitor` as guest `goldfish_battery_probe()` does.
958        battery.state.lock().present = 0;
959        battery.state.lock().int_enable = BATTERY_INT_MASK;
960        battery.start_monitor();
961
962        // Run `initialize_battery_state()` while `command_monitor` concurrently handles
963        // `Token::Monitor`. Previously this caused an ABBA deadlock between `init_state` and
964        // `state`.
965        battery.initialize_battery_state().unwrap();
966        assert!(matches!(
967            *battery.init_state.lock(),
968            BatInitializationState::Done
969        ));
970
971        // Subsequent calls when `init_state` is already `Done` should succeed as a no-op.
972        battery.initialize_battery_state().unwrap();
973
974        // The fresher state from `command_monitor` (capacity 80, ac_online 0, Discharging) must
975        // not be overwritten by the in-flight `get_power_data()` response (capacity 50,
976        // ac_online 1, Charging), and `present` must be restored to 1.
977        let state = battery.state.lock();
978        assert_eq!(state.present, 1);
979        assert_eq!(state.ac_online, 0);
980        assert_eq!(state.capacity, 80);
981        assert_eq!(state.status, BATTERY_STATUS_VAL_DISCHARGING);
982    }
983
984    struct FailingPowerClient {
985        last_request_time: Option<SystemTime>,
986    }
987
988    impl power_monitor::PowerClient for FailingPowerClient {
989        fn last_request_timestamp(&self) -> Option<SystemTime> {
990            self.last_request_time
991        }
992
993        fn get_power_data(
994            &mut self,
995        ) -> std::result::Result<power_monitor::PowerData, Box<dyn std::error::Error>> {
996            self.last_request_time = Some(SystemTime::now());
997            Err("mock powerd failure".into())
998        }
999    }
1000
1001    #[test]
1002    fn test_initialize_battery_state_error_restores_pending_unless_done() {
1003        let irq_evt = IrqLevelEvent::new().unwrap();
1004        let (_control_tube, device_tube) = Tube::pair().unwrap();
1005
1006        let mut battery = GoldfishBattery::new(
1007            0,
1008            0,
1009            irq_evt,
1010            device_tube,
1011            None,
1012            Some(Box::new(|| {
1013                Ok(Box::new(FailingPowerClient {
1014                    last_request_time: None,
1015                }))
1016            })),
1017        )
1018        .unwrap();
1019
1020        // 1. When `get_power_data()` fails and `command_monitor` has not marked `init_state` as
1021        // `Done`, `init_state` must be restored to `Pending(power_client)`.
1022        assert!(battery.initialize_battery_state().is_err());
1023        assert!(matches!(
1024            *battery.init_state.lock(),
1025            BatInitializationState::Pending(ref client) if client.last_request_timestamp().is_some()
1026        ));
1027        // An immediate retry reuses the restored `Pending` client and is rate-limited.
1028        battery.initialize_battery_state().unwrap();
1029
1030        // 2. When `command_monitor` marks `init_state` as `Done` while `get_power_data()` is in
1031        // flight and `get_power_data()` fails, `initialize_battery_state()` should return `Ok(())`
1032        // and `init_state` must remain `Done`.
1033        let irq_evt = IrqLevelEvent::new().unwrap();
1034        let irq_trigger_evt = irq_evt.get_trigger().try_clone().unwrap();
1035        let (_control_tube, device_tube) = Tube::pair().unwrap();
1036        let poll_evt = Event::new().unwrap();
1037
1038        let poll_evt_monitor = poll_evt.try_clone().unwrap();
1039        let create_monitor: Box<dyn CreatePowerMonitorFn> = Box::new(move || {
1040            Ok(Box::new(BlockingPowerMonitor {
1041                poll_evt: poll_evt_monitor.try_clone().unwrap(),
1042            }))
1043        });
1044
1045        let create_client: Box<dyn CreatePowerClientFn> = Box::new(move || {
1046            Ok(Box::new(RacingPowerClient {
1047                poll_evt: poll_evt.try_clone().unwrap(),
1048                irq_trigger_evt: irq_trigger_evt.try_clone().unwrap(),
1049                fail: true,
1050            }))
1051        });
1052
1053        let mut battery = GoldfishBattery::new(
1054            0,
1055            0,
1056            irq_evt,
1057            device_tube,
1058            Some(create_monitor),
1059            Some(create_client),
1060        )
1061        .unwrap();
1062
1063        battery.state.lock().int_enable = BATTERY_INT_MASK;
1064        battery.start_monitor();
1065        assert!(matches!(battery.initialize_battery_state(), Ok(())));
1066        assert!(matches!(
1067            *battery.init_state.lock(),
1068            BatInitializationState::Done
1069        ));
1070        let state = battery.state.lock();
1071        assert_eq!(state.ac_online, 0);
1072        assert_eq!(state.capacity, 80);
1073        assert_eq!(state.status, BATTERY_STATUS_VAL_DISCHARGING);
1074    }
1075}