1#![recursion_limit = "256"]
7
8use anyhow::{Context, Error, anyhow, bail};
9use bstr::BString;
10use fidl_fuchsia_ui_composition as fuicomposition;
11use fidl_fuchsia_ui_input as fuiinput;
12use fidl_fuchsia_ui_input3 as fuiinput3;
13use fidl_fuchsia_ui_policy as fuipolicy;
14use fidl_fuchsia_ui_views as fuiviews;
15use starnix_consent_sync::init as consent_sync_init;
16use starnix_core::bpf::fs::BpfFs;
17use starnix_core::device::kobject::DeviceMetadata;
18use starnix_core::device::mem::{DevRandom, mem_device_init};
19use starnix_core::device::{DeviceMode, simple_device_ops};
20use starnix_core::fs::devtmpfs::dev_tmp_fs;
21use starnix_core::fs::fuchsia::{RemoteBundle, new_remote_fs, new_remote_vol};
22use starnix_core::fs::sysfs::sys_fs;
23use starnix_core::fs::tmpfs::tmp_fs;
24use starnix_core::task::{Kernel, ThreadLockupDetector};
25use starnix_core::vfs::fs_registry::FsRegistry;
26use starnix_core::vfs::pipe::register_pipe_fs;
27use starnix_logging::log_error;
28use starnix_modules_android_usb::usb_device_init;
29use starnix_modules_ashmem::ashmem_device_init;
30use starnix_modules_binderfs::BinderFs;
31use starnix_modules_cgroupfs::{CgroupV1Fs, cgroup2_fs};
32use starnix_modules_debugfs::debug_fs;
33use starnix_modules_device_mapper::{create_device_mapper, device_mapper_init};
34pub use starnix_modules_devpts::create_main_and_replica;
35use starnix_modules_devpts::{dev_pts_fs, tty_device_init};
36use starnix_modules_ext4::ExtFilesystem;
37use starnix_modules_fastrpc::fastrpc_device_init;
38pub use starnix_modules_framebuffer::Framebuffer;
39use starnix_modules_functionfs::FunctionFs;
40use starnix_modules_fuse::{new_fuse_fs, new_fusectl_fs, open_fuse_device};
41use starnix_modules_gpu::gpu_device_init;
42use starnix_modules_gralloc::gralloc_device_init;
43use starnix_modules_hvdcp_opti::hvdcp_opti_init;
44use starnix_modules_inotify::inotify::inotify_init;
45use starnix_modules_input::uinput::register_uinput_device;
46use starnix_modules_input::{EventProxyMode, StartRelaysArgs, new_input_relay};
47use starnix_modules_kgsl::kgsl_device_init;
48pub use starnix_modules_layeredfs::{LayeredFsBuilder, LayeredFsMounts};
49use starnix_modules_loop::{create_loop_control_device, loop_device_init};
50use starnix_modules_nanohub::nanohub_device_init;
51use starnix_modules_nmfs::nmfs_init;
52use starnix_modules_odpm::odpm_device_init;
53pub use starnix_modules_overlayfs::OverlayStack;
54use starnix_modules_overlayfs::new_overlay_fs;
55use starnix_modules_power_residency::init_power_residency_device;
56use starnix_modules_procfs::proc_fs;
57use starnix_modules_pstore::pstore_fs;
58use starnix_modules_rtc::rtc_device_init;
59use starnix_modules_selinuxfs::selinux_fs;
60use starnix_modules_touch_power_policy::TouchPowerPolicyDevice;
61use starnix_modules_tracefs::trace_fs;
62use starnix_modules_tun::DevTun;
63use starnix_modules_wakeup_test::register_wakeup_test_device;
64use starnix_modules_zram::zram_device_init;
65use starnix_uapi::device_id::DeviceId;
66use starnix_uapi::errors::Errno;
67use starnix_uapi::fs_type::FileSystemTypeFlags;
68use std::collections::BTreeMap;
69use std::sync::Arc;
70
71const DEFAULT_MODULES: &[&str] =
74 &["device_mapper", "hw_random", "loop", "power_residency", "rtc", "tun", "zram"];
75
76pub fn validate_module(name: &str, args: Option<&[&str]>) -> Result<(), Error> {
79 let validator: Option<fn(&[&str]) -> Result<(), Error>> = match name {
80 "boot_notifier" => Some(starnix_modules_boot::validate_args),
81 "framebuffer" => Some(starnix_modules_framebuffer::validate_args),
82 "magma" => Some(starnix_modules_magma::validate_args),
83 "perfetto" => Some(starnix_modules_perfetto_consumer::validate_args),
84 "thermal" => Some(starnix_modules_thermal::validate_args),
85 "android_usb"
86 | "ashmem"
87 | "data_collection_consent_sync"
88 | "device_mapper"
89 | "fastrpc"
90 | "gfxstream"
91 | "google_odpm"
92 | "gralloc"
93 | "hvdcp_opti"
94 | "hw_random"
95 | "kgsl"
96 | "loop"
97 | "nanohub"
98 | "network_manager"
99 | "power_residency"
100 | "rtc"
101 | "tun"
102 | "wakeup_test"
103 | "zram" => None,
104 _ => bail!("unsupported module: {name}"),
105 };
106 if let Some(args) = args {
107 match validator {
108 Some(validate) => validate(args)?,
109 None if !args.is_empty() => {
110 bail!("module '{name}' does not accept arguments: {args:?}");
111 }
112 None => {}
113 }
114 }
115 Ok(())
116}
117
118impl Modules {
119 fn init_module(&self, name: &str, kernel: &Arc<Kernel>, args: &[&str]) -> Result<(), Error> {
120 validate_module(name, Some(args))?;
121 let registry = &kernel.device_registry;
122 match name {
123 "android_usb" => {
124 usb_device_init(kernel).context("Failed to add android usb device nodes")?;
125 }
126 "ashmem" => ashmem_device_init(kernel),
127 "boot_notifier" => starnix_modules_boot::module_init(kernel, args)?,
128 "data_collection_consent_sync" => consent_sync_init(kernel),
129 "device_mapper" => {
130 registry.register_device(
131 kernel,
132 "device-mapper".into(),
133 DeviceMetadata::new(
134 "mapper/control".into(),
135 DeviceId::DEVICE_MAPPER,
136 DeviceMode::Char,
137 ),
138 registry.objects.misc_class(),
139 create_device_mapper,
140 )?;
141 device_mapper_init(kernel)?;
142 }
143 "fastrpc" => fastrpc_device_init(kernel),
144 "framebuffer" => init_framebuffer_module(
145 kernel,
146 args,
147 self.enable_visual_debugging,
148 &self.initial_view_id_annotation,
149 )?,
150 "gfxstream" => gpu_device_init(kernel),
151 "google_odpm" => odpm_device_init(kernel),
154 "gralloc" => gralloc_device_init(kernel),
162 "hvdcp_opti" => hvdcp_opti_init(kernel),
163 "hw_random" => {
164 registry.register_device(
165 kernel,
166 "hw_random".into(),
167 DeviceMetadata::new("hwrng".into(), DeviceId::HW_RANDOM, DeviceMode::Char),
168 registry.objects.misc_class(),
169 simple_device_ops::<DevRandom>,
170 )?;
171 }
172 "kgsl" => kgsl_device_init(kernel),
173 "loop" => {
174 registry.register_device(
175 kernel,
176 "loop-control".into(),
177 DeviceMetadata::new(
178 "loop-control".into(),
179 DeviceId::LOOP_CONTROL,
180 DeviceMode::Char,
181 ),
182 registry.objects.misc_class(),
183 create_loop_control_device,
184 )?;
185 loop_device_init(kernel)?;
186 }
187 "magma" => starnix_modules_magma::module_init(kernel, args)?,
188 "nanohub" => nanohub_device_init(kernel),
189 "network_manager" => {
190 if let Err(e) = nmfs_init(kernel) {
191 log_error!("Network manager initialization failed: ({e:?})");
192 }
193 }
194 "perfetto" => starnix_modules_perfetto_consumer::module_init(kernel, args)?,
195 "power_residency" => init_power_residency_device(kernel),
196 "rtc" => rtc_device_init(kernel)?,
197 "thermal" => starnix_modules_thermal::module_init(kernel, args)?,
198 "tun" => {
199 registry.register_device(
200 kernel,
201 "tun".into(),
202 DeviceMetadata::new("tun".into(), DeviceId::TUN, DeviceMode::Char),
203 registry.objects.misc_class(),
204 simple_device_ops::<DevTun>,
205 )?;
206 }
207 "wakeup_test" => register_wakeup_test_device(kernel)?,
208 "zram" => zram_device_init(kernel)?,
209 _ => bail!("unsupported module: {name}"),
210 }
211 Ok(())
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
217pub struct Modules {
218 entries: BTreeMap<String, Option<Vec<String>>>,
219 enable_visual_debugging: bool,
220 initial_view_id_annotation: String,
221}
222
223impl Default for Modules {
224 fn default() -> Self {
225 let entries =
226 DEFAULT_MODULES.iter().map(|&module| (module.to_string(), Some(Vec::new()))).collect();
227 Self { entries, enable_visual_debugging: false, initial_view_id_annotation: String::new() }
228 }
229}
230
231impl Modules {
232 pub fn set_framebuffer_config(
235 &mut self,
236 enable_visual_debugging: bool,
237 initial_view_id_annotation: String,
238 ) {
239 self.enable_visual_debugging = enable_visual_debugging;
240 self.initial_view_id_annotation = initial_view_id_annotation;
241 }
242
243 pub fn add_spec(&mut self, spec: &str) -> Result<(), Error> {
246 let mut tokens = spec.split_whitespace();
247 let name = tokens.next().ok_or_else(|| anyhow!("empty module specification"))?;
248 if let Some(disabled_module) = name.strip_prefix('-') {
249 if disabled_module.is_empty() || disabled_module.starts_with('-') {
250 bail!("invalid module specification: {spec}");
251 }
252 if tokens.next().is_some() {
253 bail!("cannot specify arguments when disabling module '{disabled_module}'");
254 }
255 self.disable(disabled_module);
256 return Ok(());
257 }
258 let mut args = Vec::new();
259 for token in tokens {
260 if token.starts_with('-')
262 && let Some((flag, value)) = token.split_once('=')
263 {
264 args.push(flag.to_string());
265 args.push(value.to_string());
266 } else {
267 args.push(token.to_string());
268 }
269 }
270 self.add_with_args(name, args);
271 Ok(())
272 }
273
274 fn disable(&mut self, module: &str) {
277 self.entries.insert(module.to_string(), None);
278 }
279
280 pub fn enable(&mut self, module: &str) {
283 self.add_with_args(module, Vec::new());
284 }
285
286 pub fn add_with_args(&mut self, module: &str, args: Vec<String>) {
292 match self.entries.get_mut(module) {
293 Some(None) => {}
294 Some(Some(existing_args)) => {
295 if !args.is_empty() {
296 *existing_args = args;
297 }
298 }
299 None => {
300 self.entries.insert(module.to_string(), Some(args));
301 }
302 }
303 }
304
305 pub fn is_enabled(&self, module: &str) -> bool {
307 matches!(self.entries.get(module), Some(Some(_)))
308 }
309
310 pub fn args(&self, module: &str) -> Option<&[String]> {
312 self.entries.get(module).and_then(Option::as_deref)
313 }
314
315 pub fn validate(&self) -> Result<(), Error> {
317 for (module, args) in &self.entries {
318 let arg_refs: Option<Vec<&str>> =
319 args.as_ref().map(|a| a.iter().map(String::as_str).collect());
320 validate_module(module, arg_refs.as_deref())?;
321 }
322 if self.is_enabled("google_odpm") && self.is_enabled("hvdcp_opti") {
323 bail!("modules 'google_odpm' and 'hvdcp_opti' cannot be enabled simultaneously");
324 }
325 Ok(())
326 }
327
328 pub fn extra_cmdline_params(&self) -> Result<Option<BString>, Error> {
330 if let Some(args) = self.args("magma") {
331 let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect();
332 return Ok(Some(starnix_modules_magma::cmdline_params(&arg_refs)?));
333 }
334 Ok(None)
335 }
336
337 pub fn record_inspect(&self, parent_node: &fuchsia_inspect::Node) {
339 parent_node.record_child("modules", |inspect_node| {
340 for (module, args) in &self.entries {
341 if let Some(args) = args {
342 inspect_node.record_string(module, args.join(" "));
343 }
344 }
345 });
346 }
347
348 pub fn init_modules(&self, kernel: &Arc<Kernel>) -> Result<(), Error> {
350 for (module, args) in &self.entries {
351 if let Some(args) = args {
352 let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect();
353 self.init_module(module, kernel, &arg_refs)?;
354 }
355 }
356 Ok(())
357 }
358}
359
360fn init_framebuffer_module(
361 kernel: &Kernel,
362 args: &[&str],
363 enable_visual_debugging: bool,
364 initial_view_id_annotation: &str,
365) -> Result<(), Error> {
366 let framebuffer = Framebuffer::device_init(
367 kernel,
368 args,
369 enable_visual_debugging,
370 initial_view_id_annotation.to_string(),
371 )
372 .context("initializing framebuffer")?;
373
374 let (touch_source_client, touch_source_server) = fidl::endpoints::create_endpoints();
375 let (mouse_source_client, mouse_source_server) = fidl::endpoints::create_endpoints();
376 let view_bound_protocols = fuicomposition::ViewBoundProtocols {
377 touch_source_v2: Some(touch_source_server),
378 mouse_source_v2: Some(mouse_source_server),
379 ..Default::default()
380 };
381 let view_identity = fuiviews::ViewIdentityOnCreation::from(
382 fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair"),
383 );
384 let view_ref = fuchsia_scenic::duplicate_view_ref(&view_identity.view_ref)
385 .expect("Failed to dup view ref.");
386 let keyboard =
387 fuchsia_component::client::connect_to_protocol_sync::<fuiinput3::KeyboardMarker>()
388 .expect("Failed to connect to keyboard");
389 let registry_proxy = fuchsia_component::client::connect_to_protocol_sync::<
390 fuipolicy::DeviceListenerRegistryMarker,
391 >()
392 .context("Failed to connect to policy device listener registry")?;
393 let device_listener_registry = fuchsia_component::client::connect_to_protocol_sync::<
394 fuiinput::DeviceListenerRegistryMarker,
395 >()
396 .context("Failed to connect to device listener registry")?;
397
398 *framebuffer.view_identity.lock() = Some(view_identity);
401 *framebuffer.view_bound_protocols.lock() = Some(view_bound_protocols);
402
403 let (display_width, display_height) = {
404 let framebuffer_info = framebuffer.info.read();
405 (framebuffer_info.xres as i32, framebuffer_info.yres as i32)
406 };
407
408 let (input_events_relay, input_events_relay_handle) = new_input_relay();
409 input_events_relay.start_relays(
410 kernel,
411 StartRelaysArgs {
412 event_proxy_mode: EventProxyMode::WakeContainer,
413 touch_source_client_end: touch_source_client,
414 keyboard_proxy: keyboard,
415 mouse_source_client_end: mouse_source_client,
416 view_ref,
417 registry_proxy,
418 device_listener_registry: Some(device_listener_registry),
419 display_width,
420 display_height,
421 },
422 );
423
424 register_uinput_device(kernel, input_events_relay_handle)?;
425
426 let (touch_standby_sender, touch_standby_receiver) =
428 ThreadLockupDetector::tracked_channel::<bool>();
429 let touch_policy_device = TouchPowerPolicyDevice::new(touch_standby_sender);
430 touch_policy_device.clone().register(kernel);
431 touch_policy_device.start_relay(kernel, touch_standby_receiver);
432
433 framebuffer.start_server(kernel, None);
434 Ok(())
435}
436
437pub fn init_common_devices(kernel: &Kernel) -> Result<(), Errno> {
443 let registry = &kernel.device_registry;
444 registry.register_device(
445 kernel,
446 "fuse".into(),
447 DeviceMetadata::new("fuse".into(), DeviceId::FUSE, DeviceMode::Char),
448 registry.objects.misc_class(),
449 open_fuse_device,
450 )?;
451 mem_device_init(kernel)?;
452 tty_device_init(kernel)?;
453 Ok(())
454}
455
456pub fn register_common_file_systems(kernel: &Kernel) {
457 let registry = kernel.expando.get::<FsRegistry>();
458 registry.register(b"binder".into(), FileSystemTypeFlags::empty(), BinderFs::new_fs);
459 registry.register(b"bpf".into(), FileSystemTypeFlags::empty(), BpfFs::new_fs);
460 registry.register(b"cgroup".into(), FileSystemTypeFlags::empty(), CgroupV1Fs::new_fs);
461 registry.register(b"cgroup2".into(), FileSystemTypeFlags::empty(), cgroup2_fs);
462 registry.register(b"cpuset".into(), FileSystemTypeFlags::empty(), CgroupV1Fs::new_fs_cpuset);
465 registry.register(b"debugfs".into(), FileSystemTypeFlags::empty(), debug_fs);
466 registry.register(b"devpts".into(), FileSystemTypeFlags::empty(), dev_pts_fs);
467 registry.register(b"devtmpfs".into(), FileSystemTypeFlags::empty(), dev_tmp_fs);
468 registry.register(b"erofs".into(), FileSystemTypeFlags::empty(), starnix_modules_erofs::new_fs);
469 registry.register(b"ext4".into(), FileSystemTypeFlags::REQUIRES_DEV, ExtFilesystem::new_fs);
470 registry.register(b"functionfs".into(), FileSystemTypeFlags::empty(), FunctionFs::new_fs);
471 registry.register(b"fuse".into(), FileSystemTypeFlags::empty(), new_fuse_fs);
472 registry.register(b"fusectl".into(), FileSystemTypeFlags::empty(), new_fusectl_fs);
473 registry.register(b"overlay".into(), FileSystemTypeFlags::empty(), new_overlay_fs);
474 register_pipe_fs(registry.as_ref());
475 registry.register(b"proc".into(), FileSystemTypeFlags::empty(), proc_fs);
476 registry.register(b"pstore".into(), FileSystemTypeFlags::empty(), pstore_fs);
477 registry.register(b"remotefs".into(), FileSystemTypeFlags::empty(), new_remote_fs);
478 registry.register(b"remotevol".into(), FileSystemTypeFlags::empty(), new_remote_vol);
479 registry.register(b"remote_bundle".into(), FileSystemTypeFlags::empty(), RemoteBundle::new_fs);
480 registry.register(b"selinuxfs".into(), FileSystemTypeFlags::empty(), selinux_fs);
481 registry.register(b"sysfs".into(), FileSystemTypeFlags::empty(), sys_fs);
482 registry.register(b"tmpfs".into(), FileSystemTypeFlags::empty(), tmp_fs);
483 registry.register(b"tracefs".into(), FileSystemTypeFlags::empty(), trace_fs);
484}
485
486pub fn register_common_syscalls(kernel: &Kernel) {
487 inotify_init(kernel);
488}