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