Skip to main content

starnix_kernel_runner/
features.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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_ashmem::ashmem_device_init;
20use starnix_modules_boot::booted_device_init;
21use starnix_modules_fastrpc::fastrpc_device_init;
22use starnix_modules_framebuffer::{AspectRatio, Framebuffer};
23use starnix_modules_gpu::gpu_device_init;
24use starnix_modules_gralloc::gralloc_device_init;
25use starnix_modules_hvdcp_opti::hvdcp_opti_init;
26use starnix_modules_input::uinput::register_uinput_device;
27use starnix_modules_input::{
28    DEFAULT_KEYBOARD_DEVICE_ID, DEFAULT_MOUSE_DEVICE_ID, DEFAULT_TOUCH_DEVICE_ID, EventProxyMode,
29    InputDevice, new_input_relay,
30};
31use starnix_modules_kgsl::kgsl_device_init;
32use starnix_modules_magma::magma_device_init;
33use starnix_modules_nanohub::nanohub_device_init;
34use starnix_modules_nmfs::nmfs_init;
35use starnix_modules_perfetto_consumer::start_perfetto_consumer_thread;
36use starnix_modules_thermal::{cooling_device_init, thermal_device_init};
37use starnix_modules_touch_power_policy::TouchPowerPolicyDevice;
38use starnix_modules_wakeup_test::register_wakeup_test_device;
39use starnix_sync::{Locked, Unlocked};
40use starnix_uapi::error;
41use starnix_uapi::errors::Errno;
42use std::sync::mpsc::channel;
43
44/// A collection of parsed features, and their arguments.
45#[derive(Default, Debug)]
46pub struct Features {
47    /// Features that must be available to the kernel after initialization.
48    pub kernel: KernelFeatures,
49
50    /// SELinux configuration.
51    pub selinux: SELinuxFeature,
52
53    /// Limits value passed to the kernel during the initialization.
54    pub system_limits: SystemLimits,
55
56    /// Whether to enable ashmem.
57    pub ashmem: bool,
58
59    /// Whether to enable a boot notifier device.
60    pub boot_notifier: bool,
61
62    /// Whether to enable consent sync.
63    pub data_collection_consent_sync: bool,
64
65    /// Whether to boost CPU for a fixed duration.
66    pub boot_notifier_cpu_boost: Option<zx::MonotonicDuration>,
67
68    /// Whether to enable a framebuffer device.
69    pub framebuffer: bool,
70
71    /// Display aspect ratio.
72    pub aspect_ratio: Option<AspectRatio>,
73
74    /// This controls whether or not the default framebuffer background is black or colorful, to
75    /// aid debugging.
76    pub enable_visual_debugging: bool,
77
78    /// Whether to enable gralloc.
79    pub gralloc: bool,
80
81    /// Whether to enable the Kernel Graphics Support Layer (kgsl) device used by Adreno GPUs.
82    pub kgsl: bool,
83
84    /// Supported magma vendor IDs.
85    pub magma_supported_vendors: Option<Vec<u16>>,
86
87    /// Whether to enable gfxstream.
88    pub gfxstream: bool,
89
90    /// Include the /container directory in the root file system.
91    pub container: bool,
92
93    /// Include the /test_data directory in the root file system.
94    pub test_data: bool,
95
96    /// Include the /custom_artifacts directory in the root file system.
97    pub custom_artifacts: bool,
98
99    /// Whether to provide android with a serial number.
100    pub android_serialno: bool,
101
102    /// Optional perfetto configuration.
103    pub perfetto: Option<FsString>,
104
105    /// Whether to allow the root filesystem to be read/write.
106    pub rootfs_rw: bool,
107
108    /// Whether to enable network manager and its filesystem.
109    pub network_manager: bool,
110
111    /// Whether to enable the nanohub module.
112    pub nanohub: bool,
113
114    /// Whether to enable the fastrpc module.
115    pub fastrpc: bool,
116
117    pub enable_utc_time_adjustment: bool,
118
119    pub thermal: bool,
120
121    /// Optional cooling features to enable. See [`cooling_device_init`] for a list of possible
122    /// values and their parameters.
123    pub cooling: Option<Vec<String>>,
124
125    /// Whether to add android bootreason to kernel cmdline.
126    pub android_bootreason: bool,
127
128    pub hvdcp_opti: bool,
129
130    pub additional_mounts: Option<Vec<String>>,
131
132    /// Support kernel level suspend/resume tests.
133    pub wakeup_test: bool,
134
135    /// Add a stub block device entry for mmcblk0. This is required for certain containers that
136    /// query certain functionality based on block device naming.
137    pub mmcblk_stub: bool,
138}
139
140#[derive(Default, Debug, PartialEq)]
141pub struct SELinuxFeature {
142    /// True if SELinux should be enabled in the container.
143    pub enabled: bool,
144
145    /// Optional set of options to pass to the SELinux module.
146    pub options: String,
147
148    /// Optional set of access-check exceptions to pass to the SELinux module.
149    pub exceptions: Vec<String>,
150}
151
152impl Features {
153    pub fn record_inspect(&self, parent_node: &fuchsia_inspect::Node) {
154        parent_node.record_child("features", |inspect_node| match self {
155            Features {
156                kernel:
157                    KernelFeatures {
158                        bpf_v2,
159                        enable_suid,
160                        io_uring,
161                        error_on_failed_reboot,
162                        default_uid,
163                        default_seclabel,
164                        selinux_test_suite,
165                        default_ns_mount_options,
166                        mlock_always_onfault,
167                        mlock_pin_flavor,
168                        crash_report_throttling,
169                        wifi,
170                        cached_zx_map_info_bytes,
171                        dirent_cache_size,
172                        fake_ion,
173                    },
174                system_limits,
175                selinux,
176                ashmem,
177                boot_notifier,
178                boot_notifier_cpu_boost,
179                data_collection_consent_sync,
180                framebuffer,
181                aspect_ratio,
182                enable_visual_debugging,
183                gralloc,
184                kgsl,
185                magma_supported_vendors,
186                gfxstream,
187                container,
188                test_data,
189                custom_artifacts,
190                android_serialno,
191                perfetto,
192                rootfs_rw,
193                network_manager,
194                nanohub,
195                fastrpc,
196                enable_utc_time_adjustment,
197                thermal,
198                cooling,
199                android_bootreason,
200                hvdcp_opti,
201                additional_mounts,
202                wakeup_test,
203                mmcblk_stub,
204            } => {
205                inspect_node.record_bool("selinux", selinux.enabled);
206                inspect_node.record_bool("ashmem", *ashmem);
207                inspect_node.record_bool("boot_notifier", *boot_notifier);
208                inspect_node
209                    .record_bool("data_collection_consent_sync", *data_collection_consent_sync);
210                inspect_node.record_string(
211                    "boot_notifier_cpu_boost",
212                    boot_notifier_cpu_boost
213                        .map(|d| format!("{}s", d.into_seconds()))
214                        .unwrap_or_else(|| "none".to_string()),
215                );
216                inspect_node.record_bool("framebuffer", *framebuffer);
217                inspect_node.record_bool("gralloc", *gralloc);
218                inspect_node.record_bool("kgsl", *kgsl);
219                inspect_node.record_string(
220                    "magma_supported_vendors",
221                    match magma_supported_vendors {
222                        Some(vendors) => vendors
223                            .iter()
224                            .map(|vendor| format!("0x{:x}", vendor))
225                            .collect::<Vec<String>>()
226                            .join(","),
227                        None => "".to_string(),
228                    },
229                );
230                inspect_node.record_bool("gfxstream", *gfxstream);
231                inspect_node.record_bool("container", *container);
232                inspect_node.record_bool("test_data", *test_data);
233                inspect_node.record_bool("custom_artifacts", *custom_artifacts);
234                inspect_node.record_bool("android_serialno", *android_serialno);
235                inspect_node.record_string(
236                    "aspect_ratio",
237                    aspect_ratio
238                        .as_ref()
239                        .map(|aspect_ratio| {
240                            format!("width: {} height: {}", aspect_ratio.width, aspect_ratio.height)
241                        })
242                        .unwrap_or_default(),
243                );
244                inspect_node.record_string(
245                    "perfetto",
246                    perfetto.as_ref().map(|p| p.to_string()).unwrap_or_default(),
247                );
248                inspect_node.record_bool("rootfs_rw", *rootfs_rw);
249                inspect_node.record_bool("network_manager", *network_manager);
250                inspect_node.record_bool("nanohub", *nanohub);
251                inspect_node.record_bool("fastrpc", *fastrpc);
252                inspect_node.record_bool("thermal", *thermal);
253                inspect_node.record_string(
254                    "cooling",
255                    match cooling {
256                        Some(devices) => devices.join(","),
257                        None => "".to_string(),
258                    },
259                );
260                inspect_node.record_bool("android_bootreason", *android_bootreason);
261                inspect_node.record_bool("hvdcp_opti", *hvdcp_opti);
262                inspect_node.record_string("ping_group_range", {
263                    let range = system_limits.socket.icmp_ping_gids.lock();
264                    std::format!("{},{}", range.start, range.end - 1)
265                });
266
267                inspect_node.record_child("kernel", |kernel_node| {
268                    kernel_node.record_bool("bpf_v2", *bpf_v2);
269                    kernel_node.record_bool("enable_suid", *enable_suid);
270                    kernel_node.record_bool("io_uring", *io_uring);
271                    kernel_node.record_bool("error_on_failed_reboot", *error_on_failed_reboot);
272                    kernel_node.record_bool("enable_visual_debugging", *enable_visual_debugging);
273                    kernel_node.record_int("default_uid", (*default_uid).into());
274                    kernel_node.record_string(
275                        "default_seclabel",
276                        default_seclabel.as_deref().unwrap_or_default(),
277                    );
278                    kernel_node.record_bool("selinux_test_suite", *selinux_test_suite);
279                    kernel_node.record_bool("crash_report_throttling", *crash_report_throttling);
280                    kernel_node
281                        .record_uint("cached_zx_map_info_bytes", *cached_zx_map_info_bytes as u64);
282                    inspect_node.record_string(
283                        "default_ns_mount_options",
284                        format!("{:?}", default_ns_mount_options),
285                    );
286                    inspect_node
287                        .record_bool("enable_utc_time_adjustment", *enable_utc_time_adjustment);
288                    inspect_node.record_bool("mlock_always_onfault", *mlock_always_onfault);
289                    inspect_node
290                        .record_string("mlock_pin_flavor", format!("{:?}", mlock_pin_flavor));
291                    inspect_node.record_bool("wifi", *wifi);
292                    inspect_node
293                        .record_string("additional_mounts", format!("{:?}", additional_mounts));
294                    inspect_node.record_uint("dirent_cache_size", *dirent_cache_size as u64);
295                    inspect_node.record_bool("wakeup_test", *wakeup_test);
296                    inspect_node.record_bool("mmcblk_stub", *mmcblk_stub);
297                    inspect_node.record_bool("fake_ion", *fake_ion);
298                });
299            }
300        });
301    }
302}
303
304/// Parses all the featurse in `entries`.
305///
306/// Returns an error if parsing fails, or if an unsupported feature is present in `features`.
307pub fn parse_features(
308    start_info: &ContainerStartInfo,
309    kernel_extra_features: &[String],
310) -> Result<Features, Error> {
311    let ContainerStructuredConfig {
312        crash_report_throttling,
313        enable_utc_time_adjustment,
314        extra_features,
315        cached_zx_map_info_bytes,
316        mlock_always_onfault,
317        mlock_pin_flavor,
318        selinux_exceptions,
319        ui_visual_debugging_level,
320        additional_mounts,
321        dirent_cache_size,
322    } = &start_info.config;
323
324    let mut features = Features::default();
325    for entry in start_info
326        .program
327        .features
328        .iter()
329        .chain(kernel_extra_features.iter())
330        .chain(extra_features.iter())
331    {
332        let (feature, raw_args) = Feature::try_parse_feature_and_args(entry)?;
333        match (feature, raw_args) {
334            (Feature::AndroidSerialno, _) => features.android_serialno = true,
335            (Feature::AndroidBootreason, _) => features.android_bootreason = true,
336            (Feature::AspectRatio, Some(args)) => {
337                let e = anyhow!("Invalid aspect_ratio: {:?}", args);
338                let components: Vec<_> = args.split(':').collect();
339                if components.len() != 2 {
340                    return Err(e);
341                }
342                let width: u32 =
343                    components[0].parse().map_err(|_| anyhow!("Invalid aspect ratio width"))?;
344                let height: u32 =
345                    components[1].parse().map_err(|_| anyhow!("Invalid aspect ratio height"))?;
346                features.aspect_ratio = Some(AspectRatio { width, height });
347            }
348            (Feature::AspectRatio, None) => {
349                return Err(anyhow!(
350                    "Aspect ratio feature must contain the aspect ratio in the format: aspect_ratio:w:h"
351                ));
352            }
353            (Feature::Container, _) => features.container = true,
354            (Feature::CustomArtifacts, _) => features.custom_artifacts = true,
355            (Feature::Ashmem, _) => features.ashmem = true,
356            (Feature::BootNotifier, _) => features.boot_notifier = true,
357            (Feature::DataCollectionConsentSync, _) => features.data_collection_consent_sync = true,
358            (Feature::BootNotifierCpuBoost, Some(arg)) => {
359                let duration = zx::MonotonicDuration::from_seconds(arg.parse::<i64>()?);
360                features.boot_notifier_cpu_boost = Some(duration);
361            }
362            (Feature::BootNotifierCpuBoost, None) => {
363                return Err(anyhow!(
364                    "boot_notifier_cpu_boost feature must have an argument (e.g. \"boot_notifier_cpu_boost:60\")"
365                ));
366            }
367            (Feature::Framebuffer, _) => features.framebuffer = true,
368            (Feature::Gralloc, _) => features.gralloc = true,
369            (Feature::Kgsl, _) => features.kgsl = true,
370            (Feature::Magma, _) => {
371                if features.magma_supported_vendors.is_none() {
372                    const VENDOR_ARM: u16 = 0x13B5;
373                    const VENDOR_INTEL: u16 = 0x8086;
374                    features.magma_supported_vendors = Some(vec![VENDOR_ARM, VENDOR_INTEL])
375                }
376            }
377            (Feature::MagmaSupportedVendors, Some(arg)) => {
378                features.magma_supported_vendors = Some(
379                    arg.split(',')
380                        .map(|s| {
381                            let err = anyhow!(
382                                "Feature format must be: magma_supported_vendors:0x1234[,0xabcd]"
383                            );
384                            let trimmed = s.trim_start_matches("0x");
385                            u16::from_str_radix(trimmed, 16).map_err(|_| err)
386                        })
387                        .collect::<Result<Vec<u16>, Error>>()?,
388                );
389            }
390            (Feature::MagmaSupportedVendors, None) => {
391                return Err(anyhow!(
392                    "Feature format must be: magma_supported_vendors:0x1234[,0xabcd]"
393                ));
394            }
395            (Feature::Nanohub, _) => features.nanohub = true,
396            (Feature::Fastrpc, _) => features.fastrpc = true,
397            (Feature::NetworkManager, _) => features.network_manager = true,
398            (Feature::Gfxstream, _) => features.gfxstream = true,
399            (Feature::Bpf, Some(version)) => features.kernel.bpf_v2 = version == "v2",
400            (Feature::Bpf, None) => {
401                return Err(anyhow!("bpf feature must have an argument (e.g. \"bpf:v2\")"));
402            }
403            (Feature::EnableSuid, _) => features.kernel.enable_suid = true,
404            (Feature::IoUring, _) => features.kernel.io_uring = true,
405            (Feature::ErrorOnFailedReboot, _) => features.kernel.error_on_failed_reboot = true,
406            (Feature::Perfetto, Some(socket_path)) => {
407                features.perfetto = Some(socket_path.into());
408            }
409            (Feature::Perfetto, None) => {
410                return Err(anyhow!("Perfetto feature must contain a socket path"));
411            }
412            (Feature::PingGroupRange, Some(arg)) => {
413                let mut args = arg.split(',');
414                let (min, max) = (|| {
415                    let min = args.next()?.trim_ascii().parse::<u32>().ok()?;
416                    let max = args.next()?.trim_ascii().parse::<u32>().ok()?.checked_add(1)?;
417                    if args.next().is_some() {
418                        return None;
419                    }
420                    Some((min, max))
421                })()
422                .ok_or_else(|| anyhow!("Feature format must be: ping_group_range:0,100"))?;
423                *features.system_limits.socket.icmp_ping_gids.lock() = min..max;
424            }
425            (Feature::PingGroupRange, None) => {
426                return Err(anyhow!("Feature format must be: ping_group_range:0,100"));
427            }
428            (Feature::RootfsRw, _) => features.rootfs_rw = true,
429            (Feature::Selinux, arg) => {
430                features.selinux = SELinuxFeature {
431                    enabled: true,
432                    options: arg.unwrap_or_default(),
433                    exceptions: selinux_exceptions.clone(),
434                };
435            }
436            (Feature::SelinuxTestSuite, _) => features.kernel.selinux_test_suite = true,
437            (Feature::TestData, _) => features.test_data = true,
438            (Feature::Thermal, _) => features.thermal = true,
439            (Feature::Cooling, Some(arg)) => {
440                features.cooling = Some(arg.split(',').map(String::from).collect::<Vec<String>>())
441            }
442            (Feature::Cooling, None) => {
443                return Err(anyhow!("cooling feature must have an argument"));
444            }
445            (Feature::HvdcpOpti, _) => features.hvdcp_opti = true,
446            (Feature::Wifi, _) => features.kernel.wifi = true,
447            (Feature::AdditionalMounts, _) => {
448                features.additional_mounts = Some(additional_mounts.clone())
449            }
450            (Feature::WakeupTest, _) => features.wakeup_test = true,
451            (Feature::MmcblkStub, _) => features.mmcblk_stub = true,
452            (Feature::FakeIon, _) => features.kernel.fake_ion = true,
453        };
454    }
455
456    if features.boot_notifier_cpu_boost.is_some() && !features.boot_notifier {
457        return Err(anyhow!("boot_notifier_cpu_boost feature requires boot_notifier"));
458    }
459
460    if *ui_visual_debugging_level > 0 {
461        features.enable_visual_debugging = true;
462    }
463    features.enable_utc_time_adjustment = *enable_utc_time_adjustment;
464
465    features.kernel.default_uid = start_info.program.default_uid.0;
466    features.kernel.default_seclabel = start_info.program.default_seclabel.clone();
467    features.kernel.default_ns_mount_options =
468        if let Some(mount_options) = &start_info.program.default_ns_mount_options {
469            let options = mount_options
470                .iter()
471                .map(|item| {
472                    let mut splitter = item.splitn(2, ":");
473                    let key = splitter.next().expect("Failed to parse mount options");
474                    let value = splitter.next().expect("Failed to parse mount options");
475                    (key.to_string(), value.to_string())
476                })
477                .collect();
478            Some(options)
479        } else {
480            None
481        };
482
483    features.kernel.mlock_always_onfault = *mlock_always_onfault;
484    features.kernel.mlock_pin_flavor = MlockPinFlavor::parse(mlock_pin_flavor.as_str())?;
485    features.kernel.crash_report_throttling = *crash_report_throttling;
486    features.kernel.cached_zx_map_info_bytes = *cached_zx_map_info_bytes;
487    features.kernel.dirent_cache_size = *dirent_cache_size;
488
489    Ok(features)
490}
491
492/// Runs all the features that are enabled in `system_task.kernel()`.
493
494pub fn run_container_features(
495    locked: &mut Locked<Unlocked>,
496    system_task: &CurrentTask,
497    features: &Features,
498) -> Result<(), Error> {
499    let kernel = system_task.kernel();
500
501    if features.framebuffer {
502        let framebuffer = Framebuffer::device_init(
503            locked,
504            system_task,
505            features.aspect_ratio,
506            features.enable_visual_debugging,
507        )
508        .context("initializing framebuffer")?;
509
510        let (touch_source_client, touch_source_server) = fidl::endpoints::create_endpoints();
511        let (mouse_source_client, mouse_source_server) = fidl::endpoints::create_endpoints();
512        let view_bound_protocols = fuicomposition::ViewBoundProtocols {
513            touch_source: Some(touch_source_server),
514            mouse_source: Some(mouse_source_server),
515            ..Default::default()
516        };
517        let view_identity = fuiviews::ViewIdentityOnCreation::from(
518            fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair"),
519        );
520        let view_ref = fuchsia_scenic::duplicate_view_ref(&view_identity.view_ref)
521            .expect("Failed to dup view ref.");
522        let keyboard =
523            fuchsia_component::client::connect_to_protocol_sync::<fuiinput::KeyboardMarker>()
524                .expect("Failed to connect to keyboard");
525        let registry_proxy = fuchsia_component::client::connect_to_protocol_sync::<
526            fuipolicy::DeviceListenerRegistryMarker,
527        >()
528        .expect("Failed to connect to device listener registry");
529
530        // These need to be set before `Framebuffer::start_server` is called.
531        // `Framebuffer::start_server` is only called when the `framebuffer` component feature is
532        // enabled. The container is the runner for said components, and `run_container_features`
533        // is performed before the Container is fully initialized. Therefore, it's safe to set
534        // these values at this point.
535        //
536        // In the future, we would like to avoid initializing a framebuffer unconditionally on the
537        // Kernel, at which point this logic will need to change.
538        *framebuffer.view_identity.lock() = Some(view_identity);
539        *framebuffer.view_bound_protocols.lock() = Some(view_bound_protocols);
540
541        let framebuffer_info = framebuffer.info.read();
542
543        let display_width = framebuffer_info.xres as i32;
544        let display_height = framebuffer_info.yres as i32;
545
546        let touch_device =
547            InputDevice::new_touch(display_width, display_height, &kernel.inspect_node);
548        let keyboard_device = InputDevice::new_keyboard(&kernel.inspect_node);
549        let mouse_device = InputDevice::new_mouse(&kernel.inspect_node);
550
551        touch_device.clone().register(
552            locked,
553            &kernel.kthreads.system_task(),
554            DEFAULT_TOUCH_DEVICE_ID,
555        )?;
556        keyboard_device.clone().register(
557            locked,
558            &kernel.kthreads.system_task(),
559            DEFAULT_KEYBOARD_DEVICE_ID,
560        )?;
561        mouse_device.clone().register(
562            locked,
563            &kernel.kthreads.system_task(),
564            DEFAULT_MOUSE_DEVICE_ID,
565        )?;
566
567        let (input_events_relay, input_events_relay_handle) = new_input_relay();
568        input_events_relay.start_relays(
569            &kernel,
570            EventProxyMode::WakeContainer,
571            touch_source_client,
572            keyboard,
573            mouse_source_client,
574            view_ref,
575            registry_proxy,
576            touch_device.open_files.clone(),
577            keyboard_device.open_files.clone(),
578            mouse_device.open_files.clone(),
579            Some(touch_device.inspect_status),
580            Some(keyboard_device.inspect_status),
581            Some(mouse_device.inspect_status),
582        );
583
584        register_uinput_device(locked, &kernel.kthreads.system_task(), input_events_relay_handle)?;
585
586        // Channel we use to inform the relay of changes to `touch_standby`
587        let (touch_standby_sender, touch_standby_receiver) = channel::<bool>();
588        let touch_policy_device = TouchPowerPolicyDevice::new(touch_standby_sender);
589        touch_policy_device.clone().register(locked, &kernel.kthreads.system_task());
590        touch_policy_device.start_relay(&kernel, touch_standby_receiver);
591
592        framebuffer.start_server(kernel, None);
593    }
594    if features.gralloc {
595        // The virtgralloc0 device allows vulkan_selector to indicate to gralloc
596        // whether swiftshader or magma will be used. This is separate from the
597        // magma feature because the policy choice whether to use magma or
598        // swiftshader is in vulkan_selector, and it can potentially choose
599        // switfshader for testing purposes even when magma0 is present. Also,
600        // it's nice to indicate swiftshader the same way regardless of whether
601        // the magma feature is enabled or disabled. If a call to gralloc AIDL
602        // IAllocator allocate2 occurs with this feature disabled, the call will
603        // fail.
604        gralloc_device_init(locked, system_task);
605    }
606    if features.kgsl {
607        kgsl_device_init(locked, system_task);
608    }
609    if let Some(supported_vendors) = &features.magma_supported_vendors {
610        magma_device_init(locked, system_task, supported_vendors.clone());
611    }
612    if features.gfxstream {
613        gpu_device_init(locked, system_task);
614    }
615    if let Some(socket_path) = features.perfetto.clone() {
616        start_perfetto_consumer_thread(kernel, socket_path)
617            .context("Failed to start perfetto consumer thread")?;
618    }
619    if features.ashmem {
620        ashmem_device_init(locked, system_task);
621    }
622    if features.boot_notifier {
623        booted_device_init(locked, system_task, features.boot_notifier_cpu_boost);
624    }
625    if features.data_collection_consent_sync {
626        consent_sync_init(locked, system_task);
627    }
628    if features.network_manager {
629        if let Err(e) = nmfs_init(system_task) {
630            log_error!("Network manager initialization failed: ({e:?})");
631        }
632    }
633    if features.nanohub {
634        nanohub_device_init(locked, system_task);
635    }
636    if features.thermal {
637        thermal_device_init(locked, kernel)?;
638    }
639    if let Some(devices) = &features.cooling {
640        cooling_device_init(locked, kernel, devices.clone())?;
641    }
642    if features.hvdcp_opti {
643        hvdcp_opti_init(locked, system_task)?;
644    }
645    if features.fastrpc {
646        fastrpc_device_init(locked, system_task);
647    }
648    if features.wakeup_test {
649        register_wakeup_test_device(locked, system_task)?;
650    }
651    if features.mmcblk_stub {
652        let _device = add_mmc_block_device(locked, system_task)
653            .context("Failed to add stub mmcblk0 device")?;
654    }
655    Ok(())
656}
657
658/// Runs features requested by individual components inside the container.
659pub fn run_component_features(
660    kernel: &Kernel,
661    entries: &Vec<String>,
662    mut incoming_dir: Option<fidl_fuchsia_io::DirectoryProxy>,
663) -> Result<(), Errno> {
664    for entry in entries {
665        match entry.as_str() {
666            "framebuffer" => {
667                Framebuffer::get(kernel)?.start_server(kernel, incoming_dir.take());
668            }
669            feature => {
670                return error!(ENOSYS, format!("Unsupported feature: {}", feature));
671            }
672        }
673    }
674    Ok(())
675}