1use crate::ContainerStartInfo;
6use anyhow::{Context, Error, anyhow};
7use fidl_fuchsia_ui_composition as fuicomposition;
8use fidl_fuchsia_ui_input3 as fuiinput;
9use fidl_fuchsia_ui_policy as fuipolicy;
10use fidl_fuchsia_ui_views as fuiviews;
11use starnix_consent_sync::init as consent_sync_init;
12use starnix_container_structured_config::Config as ContainerStructuredConfig;
13use starnix_core::device::block::add_mmc_block_device;
14use starnix_core::mm::MlockPinFlavor;
15use starnix_core::task::{CurrentTask, Kernel, KernelFeatures, SystemLimits};
16use starnix_core::vfs::FsString;
17use starnix_features::Feature;
18use starnix_logging::log_error;
19use starnix_modules_android_usb::usb_device_init;
20use starnix_modules_ashmem::ashmem_device_init;
21use starnix_modules_boot::booted_device_init;
22use starnix_modules_fastrpc::fastrpc_device_init;
23use starnix_modules_framebuffer::{AspectRatio, Framebuffer};
24use starnix_modules_gpu::gpu_device_init;
25use starnix_modules_gralloc::gralloc_device_init;
26use starnix_modules_hvdcp_opti::hvdcp_opti_init;
27use starnix_modules_input::uinput::register_uinput_device;
28use starnix_modules_input::{
29 DEFAULT_KEYBOARD_DEVICE_ID, DEFAULT_MOUSE_DEVICE_ID, DEFAULT_TOUCH_DEVICE_ID, EventProxyMode,
30 InputDevice, new_input_relay,
31};
32use starnix_modules_kgsl::kgsl_device_init;
33use starnix_modules_magma::magma_device_init;
34use starnix_modules_nanohub::nanohub_device_init;
35use starnix_modules_nmfs::nmfs_init;
36use starnix_modules_perfetto_consumer::start_perfetto_consumer_thread;
37use starnix_modules_thermal::{cooling_device_init, thermal_device_init};
38use starnix_modules_touch_power_policy::TouchPowerPolicyDevice;
39use starnix_modules_wakeup_test::register_wakeup_test_device;
40use starnix_sync::{Locked, Unlocked};
41use starnix_uapi::error;
42use starnix_uapi::errors::Errno;
43use std::sync::mpsc::channel;
44
45#[derive(Default, Debug)]
47pub struct Features {
48 pub kernel: KernelFeatures,
50
51 pub selinux: SELinuxFeature,
53
54 pub system_limits: SystemLimits,
56
57 pub ashmem: bool,
59
60 pub boot_notifier: bool,
62
63 pub data_collection_consent_sync: bool,
65
66 pub boot_notifier_cpu_boost: Option<zx::MonotonicDuration>,
68
69 pub framebuffer: bool,
71
72 pub aspect_ratio: Option<AspectRatio>,
74
75 pub enable_visual_debugging: bool,
78
79 pub gralloc: bool,
81
82 pub kgsl: bool,
84
85 pub magma_supported_vendors: Option<Vec<u16>>,
87
88 pub gfxstream: bool,
90
91 pub container: bool,
93
94 pub test_data: bool,
96
97 pub custom_artifacts: bool,
99
100 pub android_serialno: bool,
102
103 pub perfetto: Option<FsString>,
105
106 pub rootfs_rw: bool,
108
109 pub network_manager: bool,
111
112 pub nanohub: bool,
114
115 pub fastrpc: bool,
117
118 pub enable_utc_time_adjustment: bool,
119
120 pub thermal: bool,
121
122 pub cooling: Option<Vec<String>>,
125
126 pub android_bootreason: bool,
128
129 pub hvdcp_opti: bool,
130
131 pub additional_mounts: Option<Vec<String>>,
132
133 pub wakeup_test: bool,
135
136 pub mmcblk_stub: bool,
139
140 pub android_usb: bool,
142}
143
144#[derive(Default, Debug, PartialEq)]
145pub struct SELinuxFeature {
146 pub enabled: bool,
148
149 pub options: String,
151
152 pub exceptions: Vec<String>,
154}
155
156impl Features {
157 pub fn record_inspect(&self, parent_node: &fuchsia_inspect::Node) {
158 parent_node.record_child("features", |inspect_node| match self {
159 Features {
160 kernel:
161 KernelFeatures {
162 bpf_v2,
163 enable_suid,
164 io_uring,
165 error_on_failed_reboot,
166 default_uid,
167 default_seclabel,
168 selinux_test_suite,
169 default_ns_mount_options,
170 mlock_always_onfault,
171 mlock_pin_flavor,
172 crash_report_throttling,
173 wifi,
174 cached_zx_map_info_bytes,
175 dirent_cache_size,
176 fake_ion,
177 },
178 system_limits,
179 selinux,
180 ashmem,
181 boot_notifier,
182 boot_notifier_cpu_boost,
183 data_collection_consent_sync,
184 framebuffer,
185 aspect_ratio,
186 enable_visual_debugging,
187 gralloc,
188 kgsl,
189 magma_supported_vendors,
190 gfxstream,
191 container,
192 test_data,
193 custom_artifacts,
194 android_serialno,
195 perfetto,
196 rootfs_rw,
197 network_manager,
198 nanohub,
199 fastrpc,
200 enable_utc_time_adjustment,
201 thermal,
202 cooling,
203 android_bootreason,
204 hvdcp_opti,
205 additional_mounts,
206 wakeup_test,
207 mmcblk_stub,
208 android_usb,
209 } => {
210 inspect_node.record_bool("selinux", selinux.enabled);
211 inspect_node.record_bool("ashmem", *ashmem);
212 inspect_node.record_bool("boot_notifier", *boot_notifier);
213 inspect_node
214 .record_bool("data_collection_consent_sync", *data_collection_consent_sync);
215 inspect_node.record_string(
216 "boot_notifier_cpu_boost",
217 boot_notifier_cpu_boost
218 .map(|d| format!("{}s", d.into_seconds()))
219 .unwrap_or_else(|| "none".to_string()),
220 );
221 inspect_node.record_bool("framebuffer", *framebuffer);
222 inspect_node.record_bool("gralloc", *gralloc);
223 inspect_node.record_bool("kgsl", *kgsl);
224 inspect_node.record_string(
225 "magma_supported_vendors",
226 match magma_supported_vendors {
227 Some(vendors) => vendors
228 .iter()
229 .map(|vendor| format!("0x{:x}", vendor))
230 .collect::<Vec<String>>()
231 .join(","),
232 None => "".to_string(),
233 },
234 );
235 inspect_node.record_bool("gfxstream", *gfxstream);
236 inspect_node.record_bool("container", *container);
237 inspect_node.record_bool("test_data", *test_data);
238 inspect_node.record_bool("custom_artifacts", *custom_artifacts);
239 inspect_node.record_bool("android_serialno", *android_serialno);
240 inspect_node.record_string(
241 "aspect_ratio",
242 aspect_ratio
243 .as_ref()
244 .map(|aspect_ratio| {
245 format!("width: {} height: {}", aspect_ratio.width, aspect_ratio.height)
246 })
247 .unwrap_or_default(),
248 );
249 inspect_node.record_string(
250 "perfetto",
251 perfetto.as_ref().map(|p| p.to_string()).unwrap_or_default(),
252 );
253 inspect_node.record_bool("rootfs_rw", *rootfs_rw);
254 inspect_node.record_bool("network_manager", *network_manager);
255 inspect_node.record_bool("nanohub", *nanohub);
256 inspect_node.record_bool("fastrpc", *fastrpc);
257 inspect_node.record_bool("thermal", *thermal);
258 inspect_node.record_string(
259 "cooling",
260 match cooling {
261 Some(devices) => devices.join(","),
262 None => "".to_string(),
263 },
264 );
265 inspect_node.record_bool("android_bootreason", *android_bootreason);
266 inspect_node.record_bool("hvdcp_opti", *hvdcp_opti);
267 inspect_node.record_string("ping_group_range", {
268 let range = system_limits.socket.icmp_ping_gids.lock();
269 std::format!("{},{}", range.start, range.end - 1)
270 });
271
272 inspect_node.record_child("kernel", |kernel_node| {
273 kernel_node.record_bool("bpf_v2", *bpf_v2);
274 kernel_node.record_bool("enable_suid", *enable_suid);
275 kernel_node.record_bool("io_uring", *io_uring);
276 kernel_node.record_bool("error_on_failed_reboot", *error_on_failed_reboot);
277 kernel_node.record_bool("enable_visual_debugging", *enable_visual_debugging);
278 kernel_node.record_int("default_uid", (*default_uid).into());
279 kernel_node.record_string(
280 "default_seclabel",
281 default_seclabel.as_deref().unwrap_or_default(),
282 );
283 kernel_node.record_bool("selinux_test_suite", *selinux_test_suite);
284 kernel_node.record_bool("crash_report_throttling", *crash_report_throttling);
285 kernel_node
286 .record_uint("cached_zx_map_info_bytes", *cached_zx_map_info_bytes as u64);
287 inspect_node.record_string(
288 "default_ns_mount_options",
289 format!("{:?}", default_ns_mount_options),
290 );
291 inspect_node
292 .record_bool("enable_utc_time_adjustment", *enable_utc_time_adjustment);
293 inspect_node.record_bool("mlock_always_onfault", *mlock_always_onfault);
294 inspect_node
295 .record_string("mlock_pin_flavor", format!("{:?}", mlock_pin_flavor));
296 inspect_node.record_bool("wifi", *wifi);
297 inspect_node
298 .record_string("additional_mounts", format!("{:?}", additional_mounts));
299 inspect_node.record_uint("dirent_cache_size", *dirent_cache_size as u64);
300 inspect_node.record_bool("wakeup_test", *wakeup_test);
301 inspect_node.record_bool("mmcblk_stub", *mmcblk_stub);
302 inspect_node.record_bool("android_usb", *android_usb);
303 inspect_node.record_bool("fake_ion", *fake_ion);
304 });
305 }
306 });
307 }
308}
309
310pub fn parse_features(
314 start_info: &ContainerStartInfo,
315 kernel_extra_features: &[String],
316) -> Result<Features, Error> {
317 let ContainerStructuredConfig {
318 crash_report_throttling,
319 enable_utc_time_adjustment,
320 extra_features,
321 cached_zx_map_info_bytes,
322 mlock_always_onfault,
323 mlock_pin_flavor,
324 selinux_exceptions,
325 ui_visual_debugging_level,
326 additional_mounts,
327 dirent_cache_size,
328 } = &start_info.config;
329
330 let mut features = Features::default();
331 for entry in start_info
332 .program
333 .features
334 .iter()
335 .chain(kernel_extra_features.iter())
336 .chain(extra_features.iter())
337 {
338 let (feature, raw_args) = Feature::try_parse_feature_and_args(entry)?;
339 match (feature, raw_args) {
340 (Feature::AndroidSerialno, _) => features.android_serialno = true,
341 (Feature::AndroidBootreason, _) => features.android_bootreason = true,
342 (Feature::AspectRatio, Some(args)) => {
343 let e = anyhow!("Invalid aspect_ratio: {:?}", args);
344 let components: Vec<_> = args.split(':').collect();
345 if components.len() != 2 {
346 return Err(e);
347 }
348 let width: u32 =
349 components[0].parse().map_err(|_| anyhow!("Invalid aspect ratio width"))?;
350 let height: u32 =
351 components[1].parse().map_err(|_| anyhow!("Invalid aspect ratio height"))?;
352 features.aspect_ratio = Some(AspectRatio { width, height });
353 }
354 (Feature::AspectRatio, None) => {
355 return Err(anyhow!(
356 "Aspect ratio feature must contain the aspect ratio in the format: aspect_ratio:w:h"
357 ));
358 }
359 (Feature::Container, _) => features.container = true,
360 (Feature::CustomArtifacts, _) => features.custom_artifacts = true,
361 (Feature::Ashmem, _) => features.ashmem = true,
362 (Feature::BootNotifier, _) => features.boot_notifier = true,
363 (Feature::DataCollectionConsentSync, _) => features.data_collection_consent_sync = true,
364 (Feature::BootNotifierCpuBoost, Some(arg)) => {
365 let duration = zx::MonotonicDuration::from_seconds(arg.parse::<i64>()?);
366 features.boot_notifier_cpu_boost = Some(duration);
367 }
368 (Feature::BootNotifierCpuBoost, None) => {
369 return Err(anyhow!(
370 "boot_notifier_cpu_boost feature must have an argument (e.g. \"boot_notifier_cpu_boost:60\")"
371 ));
372 }
373 (Feature::Framebuffer, _) => features.framebuffer = true,
374 (Feature::Gralloc, _) => features.gralloc = true,
375 (Feature::Kgsl, _) => features.kgsl = true,
376 (Feature::Magma, _) => {
377 if features.magma_supported_vendors.is_none() {
378 const VENDOR_ARM: u16 = 0x13B5;
379 const VENDOR_INTEL: u16 = 0x8086;
380 features.magma_supported_vendors = Some(vec![VENDOR_ARM, VENDOR_INTEL])
381 }
382 }
383 (Feature::MagmaSupportedVendors, Some(arg)) => {
384 features.magma_supported_vendors = Some(
385 arg.split(',')
386 .map(|s| {
387 let err = anyhow!(
388 "Feature format must be: magma_supported_vendors:0x1234[,0xabcd]"
389 );
390 let trimmed = s.trim_start_matches("0x");
391 u16::from_str_radix(trimmed, 16).map_err(|_| err)
392 })
393 .collect::<Result<Vec<u16>, Error>>()?,
394 );
395 }
396 (Feature::MagmaSupportedVendors, None) => {
397 return Err(anyhow!(
398 "Feature format must be: magma_supported_vendors:0x1234[,0xabcd]"
399 ));
400 }
401 (Feature::Nanohub, _) => features.nanohub = true,
402 (Feature::Fastrpc, _) => features.fastrpc = true,
403 (Feature::NetworkManager, _) => features.network_manager = true,
404 (Feature::Gfxstream, _) => features.gfxstream = true,
405 (Feature::Bpf, Some(version)) => features.kernel.bpf_v2 = version == "v2",
406 (Feature::Bpf, None) => {
407 return Err(anyhow!("bpf feature must have an argument (e.g. \"bpf:v2\")"));
408 }
409 (Feature::EnableSuid, _) => features.kernel.enable_suid = true,
410 (Feature::IoUring, _) => features.kernel.io_uring = true,
411 (Feature::ErrorOnFailedReboot, _) => features.kernel.error_on_failed_reboot = true,
412 (Feature::Perfetto, Some(socket_path)) => {
413 features.perfetto = Some(socket_path.into());
414 }
415 (Feature::Perfetto, None) => {
416 return Err(anyhow!("Perfetto feature must contain a socket path"));
417 }
418 (Feature::PingGroupRange, Some(arg)) => {
419 let mut args = arg.split(',');
420 let (min, max) = (|| {
421 let min = args.next()?.trim_ascii().parse::<u32>().ok()?;
422 let max = args.next()?.trim_ascii().parse::<u32>().ok()?.checked_add(1)?;
423 if args.next().is_some() {
424 return None;
425 }
426 Some((min, max))
427 })()
428 .ok_or_else(|| anyhow!("Feature format must be: ping_group_range:0,100"))?;
429 *features.system_limits.socket.icmp_ping_gids.lock() = min..max;
430 }
431 (Feature::PingGroupRange, None) => {
432 return Err(anyhow!("Feature format must be: ping_group_range:0,100"));
433 }
434 (Feature::RootfsRw, _) => features.rootfs_rw = true,
435 (Feature::Selinux, arg) => {
436 features.selinux = SELinuxFeature {
437 enabled: true,
438 options: arg.unwrap_or_default(),
439 exceptions: selinux_exceptions.clone(),
440 };
441 }
442 (Feature::SelinuxTestSuite, _) => features.kernel.selinux_test_suite = true,
443 (Feature::TestData, _) => features.test_data = true,
444 (Feature::Thermal, _) => features.thermal = true,
445 (Feature::Cooling, Some(arg)) => {
446 features.cooling = Some(arg.split(',').map(String::from).collect::<Vec<String>>())
447 }
448 (Feature::Cooling, None) => {
449 return Err(anyhow!("cooling feature must have an argument"));
450 }
451 (Feature::HvdcpOpti, _) => features.hvdcp_opti = true,
452 (Feature::Wifi, _) => features.kernel.wifi = true,
453 (Feature::AdditionalMounts, _) => {
454 features.additional_mounts = Some(additional_mounts.clone())
455 }
456 (Feature::WakeupTest, _) => features.wakeup_test = true,
457 (Feature::MmcblkStub, _) => features.mmcblk_stub = true,
458 (Feature::FakeIon, _) => features.kernel.fake_ion = true,
459 (Feature::AndroidUsb, _) => features.android_usb = true,
460 };
461 }
462
463 if features.boot_notifier_cpu_boost.is_some() && !features.boot_notifier {
464 return Err(anyhow!("boot_notifier_cpu_boost feature requires boot_notifier"));
465 }
466
467 if *ui_visual_debugging_level > 0 {
468 features.enable_visual_debugging = true;
469 }
470 features.enable_utc_time_adjustment = *enable_utc_time_adjustment;
471
472 features.kernel.default_uid = start_info.program.default_uid.0;
473 features.kernel.default_seclabel = start_info.program.default_seclabel.clone();
474 features.kernel.default_ns_mount_options =
475 if let Some(mount_options) = &start_info.program.default_ns_mount_options {
476 let options = mount_options
477 .iter()
478 .map(|item| {
479 let mut splitter = item.splitn(2, ":");
480 let key = splitter.next().expect("Failed to parse mount options");
481 let value = splitter.next().expect("Failed to parse mount options");
482 (key.to_string(), value.to_string())
483 })
484 .collect();
485 Some(options)
486 } else {
487 None
488 };
489
490 features.kernel.mlock_always_onfault = *mlock_always_onfault;
491 features.kernel.mlock_pin_flavor = MlockPinFlavor::parse(mlock_pin_flavor.as_str())?;
492 features.kernel.crash_report_throttling = *crash_report_throttling;
493 features.kernel.cached_zx_map_info_bytes = *cached_zx_map_info_bytes;
494 features.kernel.dirent_cache_size = *dirent_cache_size;
495
496 Ok(features)
497}
498
499pub fn run_container_features(
502 locked: &mut Locked<Unlocked>,
503 system_task: &CurrentTask,
504 features: &Features,
505) -> Result<(), Error> {
506 let kernel = system_task.kernel();
507
508 if features.framebuffer {
509 let framebuffer = Framebuffer::device_init(
510 locked,
511 system_task,
512 features.aspect_ratio,
513 features.enable_visual_debugging,
514 )
515 .context("initializing framebuffer")?;
516
517 let (touch_source_client, touch_source_server) = fidl::endpoints::create_endpoints();
518 let (mouse_source_client, mouse_source_server) = fidl::endpoints::create_endpoints();
519 let view_bound_protocols = fuicomposition::ViewBoundProtocols {
520 touch_source: Some(touch_source_server),
521 mouse_source: Some(mouse_source_server),
522 ..Default::default()
523 };
524 let view_identity = fuiviews::ViewIdentityOnCreation::from(
525 fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair"),
526 );
527 let view_ref = fuchsia_scenic::duplicate_view_ref(&view_identity.view_ref)
528 .expect("Failed to dup view ref.");
529 let keyboard =
530 fuchsia_component::client::connect_to_protocol_sync::<fuiinput::KeyboardMarker>()
531 .expect("Failed to connect to keyboard");
532 let registry_proxy = fuchsia_component::client::connect_to_protocol_sync::<
533 fuipolicy::DeviceListenerRegistryMarker,
534 >()
535 .expect("Failed to connect to device listener registry");
536
537 *framebuffer.view_identity.lock() = Some(view_identity);
546 *framebuffer.view_bound_protocols.lock() = Some(view_bound_protocols);
547
548 let framebuffer_info = framebuffer.info.read();
549
550 let display_width = framebuffer_info.xres as i32;
551 let display_height = framebuffer_info.yres as i32;
552
553 let touch_device =
554 InputDevice::new_touch(display_width, display_height, &kernel.inspect_node);
555 let keyboard_device = InputDevice::new_keyboard(&kernel.inspect_node);
556 let mouse_device = InputDevice::new_mouse(&kernel.inspect_node);
557
558 touch_device.clone().register(
559 locked,
560 &kernel.kthreads.system_task(),
561 DEFAULT_TOUCH_DEVICE_ID,
562 )?;
563 keyboard_device.clone().register(
564 locked,
565 &kernel.kthreads.system_task(),
566 DEFAULT_KEYBOARD_DEVICE_ID,
567 )?;
568 mouse_device.clone().register(
569 locked,
570 &kernel.kthreads.system_task(),
571 DEFAULT_MOUSE_DEVICE_ID,
572 )?;
573
574 let (input_events_relay, input_events_relay_handle) = new_input_relay();
575 input_events_relay.start_relays(
576 &kernel,
577 EventProxyMode::WakeContainer,
578 touch_source_client,
579 keyboard,
580 mouse_source_client,
581 view_ref,
582 registry_proxy,
583 touch_device.open_files.clone(),
584 keyboard_device.open_files.clone(),
585 mouse_device.open_files.clone(),
586 Some(touch_device.inspect_status),
587 Some(keyboard_device.inspect_status),
588 Some(mouse_device.inspect_status),
589 );
590
591 register_uinput_device(locked, &kernel.kthreads.system_task(), input_events_relay_handle)?;
592
593 let (touch_standby_sender, touch_standby_receiver) = channel::<bool>();
595 let touch_policy_device = TouchPowerPolicyDevice::new(touch_standby_sender);
596 touch_policy_device.clone().register(locked, &kernel.kthreads.system_task());
597 touch_policy_device.start_relay(&kernel, touch_standby_receiver);
598
599 framebuffer.start_server(kernel, None);
600 }
601 if features.gralloc {
602 gralloc_device_init(locked, system_task);
612 }
613 if features.kgsl {
614 kgsl_device_init(locked, system_task);
615 }
616 if let Some(supported_vendors) = &features.magma_supported_vendors {
617 magma_device_init(locked, system_task, supported_vendors.clone());
618 }
619 if features.gfxstream {
620 gpu_device_init(locked, system_task);
621 }
622 if let Some(socket_path) = features.perfetto.clone() {
623 start_perfetto_consumer_thread(kernel, socket_path)
624 .context("Failed to start perfetto consumer thread")?;
625 }
626 if features.ashmem {
627 ashmem_device_init(locked, system_task);
628 }
629 if features.boot_notifier {
630 booted_device_init(locked, system_task, features.boot_notifier_cpu_boost);
631 }
632 if features.data_collection_consent_sync {
633 consent_sync_init(locked, system_task);
634 }
635 if features.network_manager {
636 if let Err(e) = nmfs_init(system_task) {
637 log_error!("Network manager initialization failed: ({e:?})");
638 }
639 }
640 if features.nanohub {
641 nanohub_device_init(locked, system_task);
642 }
643 if features.thermal {
644 thermal_device_init(locked, kernel)?;
645 }
646 if let Some(devices) = &features.cooling {
647 cooling_device_init(locked, kernel, devices.clone())?;
648 }
649 if features.hvdcp_opti {
650 hvdcp_opti_init(locked, system_task)?;
651 }
652 if features.fastrpc {
653 fastrpc_device_init(locked, system_task);
654 }
655 if features.wakeup_test {
656 register_wakeup_test_device(locked, system_task)?;
657 }
658 if features.mmcblk_stub {
659 let _device = add_mmc_block_device(locked, system_task)
660 .context("Failed to add stub mmcblk0 device")?;
661 }
662 if features.android_usb {
663 usb_device_init(locked, system_task).context("Failed to add android usb device nodes")?;
664 }
665 Ok(())
666}
667
668pub fn run_component_features(
670 kernel: &Kernel,
671 entries: &Vec<String>,
672 mut incoming_dir: Option<fidl_fuchsia_io::DirectoryProxy>,
673) -> Result<(), Errno> {
674 for entry in entries {
675 match entry.as_str() {
676 "framebuffer" => {
677 Framebuffer::get(kernel)?.start_server(kernel, incoming_dir.take());
678 }
679 feature => {
680 return error!(ENOSYS, format!("Unsupported feature: {}", feature));
681 }
682 }
683 }
684 Ok(())
685}