Skip to main content

starnix_core/power/
state.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::task::CurrentTask;
6use crate::vfs::FsNodeOps;
7use crate::vfs::pseudo::simple_file::{BytesFile, BytesFileOps};
8use fidl_fuchsia_power_broker::PowerLevel;
9use starnix_logging::{log_info, log_warn};
10use starnix_uapi::errors::Errno;
11use starnix_uapi::{errno, error};
12use std::borrow::Cow;
13
14#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
15pub enum SuspendState {
16    /// Suspend-to-disk
17    ///
18    /// This state offers the greatest energy savings.
19    Disk,
20    /// Suspend-to-Ram
21    ///
22    /// This state, if supported, offers significant power savings as everything in the system is
23    /// put into a low-power state, except for memory.
24    Ram,
25    /// Standby
26    ///
27    /// This state, if supported, offers moderate, but real, energy savings, while providing a
28    /// relatively straightforward transition back to the working state.
29    ///
30    Standby,
31    /// Suspend-To-Idle
32    ///
33    /// This state is a generic, pure software, light-weight, system sleep state.
34    Idle,
35}
36
37impl std::fmt::Display for SuspendState {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        match self {
40            SuspendState::Disk => write!(f, "disk"),
41            SuspendState::Ram => write!(f, "ram"),
42            SuspendState::Standby => write!(f, "standby"),
43            SuspendState::Idle => write!(f, "freeze"),
44        }
45    }
46}
47
48impl From<SuspendState> for PowerLevel {
49    fn from(value: SuspendState) -> Self {
50        match value {
51            SuspendState::Disk => 0,
52            SuspendState::Ram => 1,
53            SuspendState::Standby => 2,
54            SuspendState::Idle => 3,
55        }
56    }
57}
58
59pub struct PowerStateFile;
60
61impl PowerStateFile {
62    pub fn new_node() -> impl FsNodeOps {
63        BytesFile::new_node(Self {})
64    }
65}
66
67impl BytesFileOps for PowerStateFile {
68    fn write(&self, current_task: &CurrentTask, data: Vec<u8>) -> Result<(), Errno> {
69        let state_str = std::str::from_utf8(&data).map_err(|_| errno!(EINVAL))?;
70        let clean_state_str = state_str.split('\n').next().unwrap_or("");
71        let state = match clean_state_str {
72            "disk" => SuspendState::Disk,
73            "standby" => SuspendState::Standby,
74            // TODO(https://fxbug.dev/368394556): Check on mem_file to see what suspend state
75            // "mem" represents
76            "freeze" | "mem" => SuspendState::Idle,
77            _ => return error!(EINVAL),
78        };
79        let power_manager = &current_task.kernel().suspend_resume_manager;
80        let supported_states = power_manager.suspend_states();
81        if !supported_states.contains(&state) {
82            return error!(EINVAL);
83        }
84        log_info!(state:?; "Received write to power state file.");
85        // LINT.IfChange
86        fuchsia_trace::duration!("power", "starnix-sysfs:suspend");
87        // LINT.ThenChange(//src/performance/lib/trace_processing/metrics/suspend.py)
88        power_manager.suspend(state).inspect_err(|e| log_warn!("Suspend failed: {e}"))?;
89
90        Ok(())
91    }
92
93    fn read(&self, current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
94        let states = current_task.kernel().suspend_resume_manager.suspend_states();
95        let mut states_array: Vec<String> = states.iter().map(SuspendState::to_string).collect();
96        // TODO(https://fxbug.dev/368394556): The “mem” string is interpreted in accordance with
97        // the contents of the mem_sleep file.
98        states_array.push("mem".to_string());
99        states_array.sort();
100        let content = states_array.join(" ") + "\n";
101        Ok(content.as_bytes().to_owned().into())
102    }
103}