starnix_modules_wakeup_test/
device.rs1use crate::input::{create_media_buttons_proxy, schedule_wakeup_power_button};
6use crate::ioctl::{CommandCode, WakeupMethod, WakeupTestType, WakeupTimerInfo};
7use crate::tracing;
8use anyhow::{Result, anyhow};
9use starnix_core::device::DeviceOps;
10use starnix_core::mm::MemoryAccessorExt;
11use starnix_core::perf::TraceEventQueueList;
12use starnix_core::task::{CurrentTask, Kernel};
13use starnix_core::vfs::{CloseFreeSafe, FileObject, FileOps, NamespaceNode};
14use starnix_core::{fileops_impl_dataless, fileops_impl_noop_sync, fileops_impl_seekless};
15use starnix_logging::{log_error, log_info};
16
17use starnix_syscalls::{SUCCESS, SyscallResult};
18use starnix_uapi::errors::Errno;
19use starnix_uapi::open_flags::OpenFlags;
20use starnix_uapi::user_address::UserRef;
21use starnix_uapi::{device_id, error};
22use std::sync::{Arc, Weak};
23use zx;
24
25#[derive(Clone)]
26pub struct WakeupTestDevice {
27 commands: Commands,
28}
29
30impl CloseFreeSafe for WakeupTestDevice {}
31
32impl WakeupTestDevice {
33 pub fn new(kernel: &Arc<Kernel>) -> Self {
34 Self { commands: Commands { kernel: Arc::downgrade(kernel) } }
35 }
36}
37
38impl DeviceOps for WakeupTestDevice {
39 fn open(
40 &self,
41 current_task: &CurrentTask,
42 _id: device_id::DeviceId,
43 _node: &NamespaceNode,
44 _flags: OpenFlags,
45 ) -> Result<Box<dyn FileOps>, Errno> {
46 Ok(Box::new(WakeupTestDevice::new(current_task.kernel())))
47 }
48}
49
50#[derive(Clone)]
51struct Commands {
52 kernel: Weak<Kernel>,
53}
54
55impl Commands {
56 fn schedule_wakeup(&self, time_ns: i64) -> Result<()> {
57 log_info!("WakeupTestDevice::schedule_wakeup creating async task for time_ns: {time_ns}");
58 let kernel = self.kernel.upgrade().expect("kernel should exist");
59
60 kernel.kthreads.spawn_future(
61 move || async move {
62 let media_button_proxy = match create_media_buttons_proxy().await {
63 Ok(proxy) => proxy,
64 Err(e) => {
65 log_error!("Failed to create media buttons proxy: {:?}", e);
66 return;
67 }
68 };
69 schedule_wakeup_power_button(
70 &media_button_proxy,
71 zx::Duration::from_nanos(time_ns),
72 )
73 .await;
74 let deadline = fuchsia_async::MonotonicInstant::after(
82 zx::Duration::from_seconds(5) + zx::Duration::from_nanos(time_ns),
83 );
84 fuchsia_async::Timer::new(deadline).await;
85 log_info!("media_button proxy dropped.")
86 },
87 "wakeup_test",
88 );
89 Ok(())
90 }
91
92 fn run_wakeup_set_timers(
93 &self,
94 current_task: &CurrentTask,
95 timer_info: WakeupTimerInfo,
96 ) -> Result<()> {
97 let method = WakeupMethod::from(timer_info.method);
98
99 match method {
101 WakeupMethod::PowerButton => (),
102 _ => {
103 return Err(anyhow!(
104 "Only PowerButton wakeup method is currently supported: b/458389823"
105 ));
106 }
107 };
108
109 let test_type = WakeupTestType::from(timer_info.test_type);
110 log_info!(
111 "WakeupTestDevice::WakeupSetTimers test_type: {test_type:?} Setting {} timers for {:?}, interval {} ns, starting {} ns",
112 timer_info.num_events,
113 method,
114 timer_info.interval,
115 timer_info.offset
116 );
117 tracing::trace_wakeup_test_type(
118 self.get_trace_event_queues(),
119 current_task.get_tid(),
120 test_type,
121 );
122 for index in 0..timer_info.num_events {
123 let time = (timer_info.interval * (index as i64)) + timer_info.offset;
124 log_info!("WakeupTestDevice::set_timer i: {index} for {time}");
125 self.schedule_wakeup(time)?;
126 }
127 Ok(())
128 }
129
130 fn get_trace_event_queues(&self) -> Option<Arc<TraceEventQueueList>> {
132 if let Some(k) = self.kernel.upgrade() {
133 let queues = TraceEventQueueList::from(&k);
134 if queues.is_enabled() {
135 Some(TraceEventQueueList::from(&k))
136 } else {
137 log_error!("Trace is not enabled");
138 None
139 }
140 } else {
141 None
142 }
143 }
144}
145
146impl FileOps for WakeupTestDevice {
147 fileops_impl_seekless!();
148 fileops_impl_dataless!();
149 fileops_impl_noop_sync!();
150
151 fn ioctl(
152 &self,
153 _file: &FileObject,
154 current_task: &CurrentTask,
155 request: u32,
156 arg: starnix_syscalls::SyscallArg,
157 ) -> Result<SyscallResult, Errno> {
158 let cmd_num = CommandCode::from(request);
159 log_info!("WakeupTestDevice::ioctl cmd_num {cmd_num:?}, arg: {arg:?}");
160
161 match cmd_num {
162 CommandCode::WakeupSetTimers => {
163 let timer_ref = UserRef::<WakeupTimerInfo>::new(arg.into());
164 let timer_info = current_task.read_object(timer_ref)?;
165 log_info!("WakeupTestDevice::WakeupSetTimers {timer_info:?}");
166 log_info!("WakeupTestDevice::WakeupSetTimers version 0x{:x}", timer_info.version);
167
168 match self.commands.run_wakeup_set_timers(current_task, timer_info) {
169 Ok(_) => Ok(SUCCESS),
170 Err(e) => {
171 log_error!("WakeupTestDevice::WakeupSetTimers failed: {:?}", e);
172 return error!(EINVAL);
173 }
174 }
175 }
176 CommandCode::WakeupTest => error!(ENOSYS),
177 CommandCode::WakeupHowManyTimers => error!(ENOSYS),
178 CommandCode::WakeupCancelTimers => error!(ENOSYS),
179 _ => error!(ENOTTY),
180 }
181 }
182}