starnix_core/power/
wake_lock.rs1use crate::power::WakeupSourceOrigin;
6use crate::security;
7use crate::task::CurrentTask;
8use crate::vfs::FsNodeOps;
9use crate::vfs::pseudo::simple_file::{BytesFile, BytesFileOps};
10use itertools::Itertools;
11use starnix_uapi::auth::CAP_BLOCK_SUSPEND;
12use starnix_uapi::errors::Errno;
13use starnix_uapi::{errno, error};
14use std::borrow::Cow;
15
16pub struct PowerWakeLockFile;
17
18impl PowerWakeLockFile {
19 pub fn new_node() -> impl FsNodeOps {
20 BytesFile::new_node(Self {})
21 }
22}
23
24impl BytesFileOps for PowerWakeLockFile {
25 fn write(&self, current_task: &CurrentTask, data: Vec<u8>) -> Result<(), Errno> {
33 security::check_task_capable(current_task, CAP_BLOCK_SUSPEND)?;
34 let lock_str = std::str::from_utf8(&data).map_err(|_| errno!(EINVAL))?;
35 let clean_str = lock_str.trim_end_matches('\n');
36 let mut clean_str_split = clean_str.split(' ');
37 let Some(clean_lock_str) = clean_str_split.next() else {
38 return error!(EINVAL);
39 };
40
41 let target_monotonic = match clean_str_split.next() {
43 Some(timeout_str) => Some(
44 zx::MonotonicInstant::get() + zx::MonotonicDuration::from_nanos(
46 timeout_str
47 .parse()
48 .map_err(|_| errno!(EINVAL, "Failed to parse the timeout string"))?,
49 ),
50 ),
51 None => None,
52 };
53
54 current_task
55 .kernel()
56 .suspend_resume_manager
57 .activate_wakeup_source(WakeupSourceOrigin::WakeLock(clean_lock_str.to_owned()));
58
59 if let Some(target_monotonic) = target_monotonic {
61 let kernel_ref = current_task.kernel().clone();
62 let clean_lock_string = clean_lock_str.to_string();
63 current_task.kernel().kthreads.spawn_future(
64 move || async move {
65 fuchsia_async::Timer::new(target_monotonic).await;
66 kernel_ref
67 .suspend_resume_manager
68 .timeout_wakeup_source(&WakeupSourceOrigin::WakeLock(clean_lock_string));
69 },
70 "wake-lock-timeout",
71 );
72 }
73
74 Ok(())
75 }
76
77 fn read(&self, current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
78 let wake_locks = current_task.kernel().suspend_resume_manager.lock().active_wake_locks();
79 let content = wake_locks.iter().map(|o| o.to_string()).join(" ") + "\n";
80 Ok(content.as_bytes().to_owned().into())
81 }
82}
83
84pub struct PowerWakeUnlockFile;
85
86impl PowerWakeUnlockFile {
87 pub fn new_node() -> impl FsNodeOps {
88 BytesFile::new_node(Self {})
89 }
90}
91
92impl BytesFileOps for PowerWakeUnlockFile {
93 fn write(&self, current_task: &CurrentTask, data: Vec<u8>) -> Result<(), Errno> {
95 security::check_task_capable(current_task, CAP_BLOCK_SUSPEND)?;
96 let lock_str = std::str::from_utf8(&data).map_err(|_| errno!(EINVAL))?;
97 let clean_lock_str = lock_str.trim_end_matches('\n').to_string();
98 if !current_task
99 .kernel()
100 .suspend_resume_manager
101 .deactivate_wakeup_source(&WakeupSourceOrigin::WakeLock(clean_lock_str))
102 {
103 return error!(EPERM);
104 }
105 Ok(())
106 }
107
108 fn read(&self, current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
111 let wake_locks = current_task.kernel().suspend_resume_manager.lock().inactive_wake_locks();
112 let content = wake_locks.iter().map(|o| o.to_string()).join(" ") + "\n";
113 Ok(content.as_bytes().to_owned().into())
114 }
115}