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_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/// A collection of parsed features, and their arguments.
46#[derive(Default, Debug)]
47pub struct Features {
48    /// Features that must be available to the kernel after initialization.
49    pub kernel: KernelFeatures,
50
51    /// SELinux configuration.
52    pub selinux: SELinuxFeature,
53
54    /// Limits value passed to the kernel during the initialization.
55    pub system_limits: SystemLimits,
56
57    /// Whether to enable ashmem.
58    pub ashmem: bool,
59
60    /// Whether to enable a boot notifier device.
61    pub boot_notifier: bool,
62
63    /// Whether to enable consent sync.
64    pub data_collection_consent_sync: bool,
65
66    /// Whether to boost CPU for a fixed duration.
67    pub boot_notifier_cpu_boost: Option<zx::MonotonicDuration>,
68
69    /// Whether to enable a framebuffer device.
70    pub framebuffer: bool,
71
72    /// Display aspect ratio.
73    pub aspect_ratio: Option<AspectRatio>,
74
75    /// This controls whether or not the default framebuffer background is black or colorful, to
76    /// aid debugging.
77    pub enable_visual_debugging: bool,
78
79    /// Whether to enable gralloc.
80    pub gralloc: bool,
81
82    /// Whether to enable the Kernel Graphics Support Layer (kgsl) device used by Adreno GPUs.
83    pub kgsl: bool,
84
85    /// Supported magma vendor IDs.
86    pub magma_supported_vendors: Option<Vec<u16>>,
87
88    /// Whether to enable gfxstream.
89    pub gfxstream: bool,
90
91    /// Include the /container directory in the root file system.
92    pub container: bool,
93
94    /// Include the /test_data directory in the root file system.
95    pub test_data: bool,
96
97    /// Include the /custom_artifacts directory in the root file system.
98    pub custom_artifacts: bool,
99
100    /// Whether to provide android with a serial number.
101    pub android_serialno: bool,
102
103    /// Optional perfetto configuration.
104    pub perfetto: Option<FsString>,
105
106    /// Whether to allow the root filesystem to be read/write.
107    pub rootfs_rw: bool,
108
109    /// Whether to enable network manager and its filesystem.
110    pub network_manager: bool,
111
112    /// Whether to enable the nanohub module.
113    pub nanohub: bool,
114
115    /// Whether to enable the fastrpc module.
116    pub fastrpc: bool,
117
118    pub enable_utc_time_adjustment: bool,
119
120    pub thermal: bool,
121
122    /// Optional cooling features to enable. See [`cooling_device_init`] for a list of possible
123    /// values and their parameters.
124    pub cooling: Option<Vec<String>>,
125
126    /// Whether to add android bootreason to kernel cmdline.
127    pub android_bootreason: bool,
128
129    pub hvdcp_opti: bool,
130
131    pub additional_mounts: Option<Vec<String>>,
132
133    /// Support kernel level suspend/resume tests.
134    pub wakeup_test: bool,
135
136    /// Add a stub block device entry for mmcblk0. This is required for certain containers that
137    /// query certain functionality based on block device naming.
138    pub mmcblk_stub: bool,
139
140    /// Whether to initialize Android-compatible USB monitoring sysfs logic.
141    pub android_usb: bool,
142}
143
144#[derive(Default, Debug, PartialEq)]
145pub struct SELinuxFeature {
146    /// True if SELinux should be enabled in the container.
147    pub enabled: bool,
148
149    /// Optional set of options to pass to the SELinux module.
150    pub options: String,
151
152    /// Optional set of access-check exceptions to pass to the SELinux module.
153    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
310/// Parses all the featurse in `entries`.
311///
312/// Returns an error if parsing fails, or if an unsupported feature is present in `features`.
313pub 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
499/// Runs all the features that are enabled in `system_task.kernel()`.
500
501pub 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        // These need to be set before `Framebuffer::start_server` is called.
538        // `Framebuffer::start_server` is only called when the `framebuffer` component feature is
539        // enabled. The container is the runner for said components, and `run_container_features`
540        // is performed before the Container is fully initialized. Therefore, it's safe to set
541        // these values at this point.
542        //
543        // In the future, we would like to avoid initializing a framebuffer unconditionally on the
544        // Kernel, at which point this logic will need to change.
545        *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        // Channel we use to inform the relay of changes to `touch_standby`
594        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        // The virtgralloc0 device allows vulkan_selector to indicate to gralloc
603        // whether swiftshader or magma will be used. This is separate from the
604        // magma feature because the policy choice whether to use magma or
605        // swiftshader is in vulkan_selector, and it can potentially choose
606        // switfshader for testing purposes even when magma0 is present. Also,
607        // it's nice to indicate swiftshader the same way regardless of whether
608        // the magma feature is enabled or disabled. If a call to gralloc AIDL
609        // IAllocator allocate2 occurs with this feature disabled, the call will
610        // fail.
611        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
668/// Runs features requested by individual components inside the container.
669pub 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}