starnix_consent_sync/
lib.rs1use fidl_fuchsia_settings as fsettings;
6use starnix_core::device::DeviceOps;
7use starnix_core::task::CurrentTask;
8use starnix_core::vfs::FileOps;
9use starnix_core::vfs::pseudo::simple_file::{BytesFile, BytesFileOps};
10use starnix_logging::log_error;
11use starnix_sync::{FileOpsCore, Locked};
12use starnix_uapi::device_type::DeviceType;
13use starnix_uapi::error;
14use starnix_uapi::errors::Errno;
15use starnix_uapi::open_flags::OpenFlags;
16use std::borrow::Cow;
17use std::sync::Arc;
18use std::sync::atomic::{AtomicBool, Ordering};
19use zx;
20
21#[derive(Clone)]
22struct ConsentSyncHandle(Arc<ConsentSyncFileBackend>);
23
24impl DeviceOps for ConsentSyncHandle {
25 fn open(
26 &self,
27 _locked: &mut Locked<FileOpsCore>,
28 _current_task: &CurrentTask,
29 _device_type: DeviceType,
30 _node: &starnix_core::vfs::NamespaceNode,
31 _flags: OpenFlags,
32 ) -> Result<Box<dyn FileOps>, Errno> {
33 Ok(Box::new(BytesFile::new(self.clone())))
34 }
35}
36
37struct ConsentSyncFileBackend {
38 consent: AtomicBool,
39 privacy_proxy: fsettings::PrivacySynchronousProxy,
40}
41
42impl BytesFileOps for ConsentSyncHandle {
43 fn write(&self, current_task: &CurrentTask, data: Vec<u8>) -> Result<(), Errno> {
44 self.0.write(current_task, data)
45 }
46
47 fn read(&self, current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
48 self.0.read(current_task)
49 }
50}
51
52impl BytesFileOps for ConsentSyncFileBackend {
53 fn write(&self, _current_task: &CurrentTask, data: Vec<u8>) -> Result<(), Errno> {
54 let content_str = String::from_utf8_lossy(&data);
55 let trimmed_content = content_str.trim();
56
57 let granted = match trimmed_content {
58 "0" => false,
59 "1" => true,
60 _ => {
61 log_error!(
62 "ConsentSync: Invalid value written: {:?}. Must be '0' or '1'.",
63 trimmed_content
64 );
65 return error!(EINVAL);
66 }
67 };
68
69 let settings = fsettings::PrivacySettings {
70 user_data_sharing_consent: Some(granted),
71 ..Default::default()
72 };
73
74 match self.privacy_proxy.set(&settings, zx::MonotonicInstant::INFINITE) {
75 Ok(Ok(())) => {
76 self.consent.store(granted, Ordering::Relaxed);
77 Ok(())
78 }
79 Ok(Err(e)) => {
80 log_error!("ConsentSync: fuchsia.settings.Privacy.Set application error: {:?}", e);
81 error!(EIO)
82 }
83 Err(e) => {
84 log_error!(
85 "ConsentSync: FIDL call to fuchsia.settings.Privacy.Set failed: {:?}",
86 e
87 );
88 error!(EIO)
89 }
90 }
91 }
92
93 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
94 let val = if self.consent.load(Ordering::Relaxed) { "1\n" } else { "0\n" };
95 Ok(val.as_bytes().into())
96 }
97}
98
99pub fn init(locked: &mut Locked<starnix_sync::Unlocked>, system_task: &CurrentTask) {
100 let kernel = system_task.kernel();
101 let registry = &kernel.device_registry;
102
103 let privacy_proxy = fsettings::PrivacySynchronousProxy::new(
104 kernel
105 .connect_to_protocol_at_container_svc::<fsettings::PrivacyMarker>()
106 .expect("Connected to privacy service")
107 .into_channel(),
108 );
109
110 let file_backend =
111 Arc::new(ConsentSyncFileBackend { consent: AtomicBool::new(false), privacy_proxy });
112
113 let device = ConsentSyncHandle(file_backend);
114
115 registry
116 .register_dyn_device(
117 locked,
118 system_task,
119 "consent".into(),
120 registry.objects.starnix_class(),
121 device,
122 )
123 .expect("can register consent device");
124}