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