File Index
Files and directories
Sign in
FILE

freeze.rs

File preview with syntax highlighting.

linux-6.19.14/drivers/android/binder/freeze.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3// Copyright (C) 2025 Google LLC.
  4
  5use kernel::{
  6    alloc::AllocError,
  7    list::ListArc,
  8    prelude::*,
  9    rbtree::{self, RBTreeNodeReservation},
 10    seq_file::SeqFile,
 11    seq_print,
 12    sync::{Arc, UniqueArc},
 13    uaccess::UserSliceReader,
 14};
 15
 16use crate::{
 17    defs::*, node::Node, process::Process, thread::Thread, BinderReturnWriter, DArc, DLArc,
 18    DTRWrap, DeliverToRead,
 19};
 20
 21#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
 22pub(crate) struct FreezeCookie(u64);
 23
 24/// Represents a listener for changes to the frozen state of a process.
 25pub(crate) struct FreezeListener {
 26    /// The node we are listening for.
 27    pub(crate) node: DArc<Node>,
 28    /// The cookie of this freeze listener.
 29    cookie: FreezeCookie,
 30    /// What value of `is_frozen` did we most recently tell userspace about?
 31    last_is_frozen: Option<bool>,
 32    /// We sent a `BR_FROZEN_BINDER` and we are waiting for `BC_FREEZE_NOTIFICATION_DONE` before
 33    /// sending any other commands.
 34    is_pending: bool,
 35    /// Userspace sent `BC_CLEAR_FREEZE_NOTIFICATION` and we need to reply with
 36    /// `BR_CLEAR_FREEZE_NOTIFICATION_DONE` as soon as possible. If `is_pending` is set, then we
 37    /// must wait for it to be unset before we can reply.
 38    is_clearing: bool,
 39    /// Number of cleared duplicates that can't be deleted until userspace sends
 40    /// `BC_FREEZE_NOTIFICATION_DONE`.
 41    num_pending_duplicates: u64,
 42    /// Number of cleared duplicates that can be deleted.
 43    num_cleared_duplicates: u64,
 44}
 45
 46impl FreezeListener {
 47    /// Is it okay to create a new listener with the same cookie as this one for the provided node?
 48    ///
 49    /// Under some scenarios, userspace may delete a freeze listener and immediately recreate it
 50    /// with the same cookie. This results in duplicate listeners. To avoid issues with ambiguity,
 51    /// we allow this only if the new listener is for the same node, and we also require that the
 52    /// old listener has already been cleared.
 53    fn allow_duplicate(&self, node: &DArc<Node>) -> bool {
 54        Arc::ptr_eq(&self.node, node) && self.is_clearing
 55    }
 56}
 57
 58type UninitFM = UniqueArc<core::mem::MaybeUninit<DTRWrap<FreezeMessage>>>;
 59
 60/// Represents a notification that the freeze state has changed.
 61pub(crate) struct FreezeMessage {
 62    cookie: FreezeCookie,
 63}
 64
 65kernel::list::impl_list_arc_safe! {
 66    impl ListArcSafe<0> for FreezeMessage {
 67        untracked;
 68    }
 69}
 70
 71impl FreezeMessage {
 72    fn new(flags: kernel::alloc::Flags) -> Result<UninitFM, AllocError> {
 73        UniqueArc::new_uninit(flags)
 74    }
 75
 76    fn init(ua: UninitFM, cookie: FreezeCookie) -> DLArc<FreezeMessage> {
 77        match ua.pin_init_with(DTRWrap::new(FreezeMessage { cookie })) {
 78            Ok(msg) => ListArc::from(msg),
 79            Err(err) => match err {},
 80        }
 81    }
 82}
 83
 84impl DeliverToRead for FreezeMessage {
 85    fn do_work(
 86        self: DArc<Self>,
 87        thread: &Thread,
 88        writer: &mut BinderReturnWriter<'_>,
 89    ) -> Result<bool> {
 90        let _removed_listener;
 91        let mut node_refs = thread.process.node_refs.lock();
 92        let Some(mut freeze_entry) = node_refs.freeze_listeners.find_mut(&self.cookie) else {
 93            return Ok(true);
 94        };
 95        let freeze = freeze_entry.get_mut();
 96
 97        if freeze.num_cleared_duplicates > 0 {
 98            freeze.num_cleared_duplicates -= 1;
 99            drop(node_refs);
100            writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?;
101            writer.write_payload(&self.cookie.0)?;
102            return Ok(true);
103        }
104
105        if freeze.is_pending {
106            return Ok(true);
107        }
108        if freeze.is_clearing {
109            kernel::warn_on!(freeze.num_cleared_duplicates != 0);
110            if freeze.num_pending_duplicates > 0 {
111                // The primary freeze listener was deleted, so convert a pending duplicate back
112                // into the primary one.
113                freeze.num_pending_duplicates -= 1;
114                freeze.is_pending = true;
115                freeze.is_clearing = true;
116            } else {
117                _removed_listener = freeze_entry.remove_node();
118            }
119            drop(node_refs);
120            writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?;
121            writer.write_payload(&self.cookie.0)?;
122            Ok(true)
123        } else {
124            let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
125            if freeze.last_is_frozen == Some(is_frozen) {
126                return Ok(true);
127            }
128
129            let mut state_info = BinderFrozenStateInfo::default();
130            state_info.is_frozen = is_frozen as u32;
131            state_info.cookie = freeze.cookie.0;
132            freeze.is_pending = true;
133            freeze.last_is_frozen = Some(is_frozen);
134            drop(node_refs);
135
136            writer.write_code(BR_FROZEN_BINDER)?;
137            writer.write_payload(&state_info)?;
138            // BR_FROZEN_BINDER notifications can cause transactions
139            Ok(false)
140        }
141    }
142
143    fn cancel(self: DArc<Self>) {}
144
145    fn should_sync_wakeup(&self) -> bool {
146        false
147    }
148
149    #[inline(never)]
150    fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
151        seq_print!(m, "{}has frozen binder\n", prefix);
152        Ok(())
153    }
154}
155
156impl FreezeListener {
157    pub(crate) fn on_process_exit(&self, proc: &Arc<Process>) {
158        if !self.is_clearing {
159            self.node.remove_freeze_listener(proc);
160        }
161    }
162}
163
164impl Process {
165    pub(crate) fn request_freeze_notif(
166        self: &Arc<Self>,
167        reader: &mut UserSliceReader,
168    ) -> Result<()> {
169        let hc = reader.read::<BinderHandleCookie>()?;
170        let handle = hc.handle;
171        let cookie = FreezeCookie(hc.cookie);
172
173        let msg = FreezeMessage::new(GFP_KERNEL)?;
174        let alloc = RBTreeNodeReservation::new(GFP_KERNEL)?;
175
176        let mut node_refs_guard = self.node_refs.lock();
177        let node_refs = &mut *node_refs_guard;
178        let Some(info) = node_refs.by_handle.get_mut(&handle) else {
179            pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION invalid ref {}\n", handle);
180            return Err(EINVAL);
181        };
182        if info.freeze().is_some() {
183            pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION already set\n");
184            return Err(EINVAL);
185        }
186        let node_ref = info.node_ref();
187        let freeze_entry = node_refs.freeze_listeners.entry(cookie);
188
189        if let rbtree::Entry::Occupied(ref dupe) = freeze_entry {
190            if !dupe.get().allow_duplicate(&node_ref.node) {
191                pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION duplicate cookie\n");
192                return Err(EINVAL);
193            }
194        }
195
196        // All failure paths must come before this call, and all modifications must come after this
197        // call.
198        node_ref.node.add_freeze_listener(self, GFP_KERNEL)?;
199
200        match freeze_entry {
201            rbtree::Entry::Vacant(entry) => {
202                entry.insert(
203                    FreezeListener {
204                        cookie,
205                        node: node_ref.node.clone(),
206                        last_is_frozen: None,
207                        is_pending: false,
208                        is_clearing: false,
209                        num_pending_duplicates: 0,
210                        num_cleared_duplicates: 0,
211                    },
212                    alloc,
213                );
214            }
215            rbtree::Entry::Occupied(mut dupe) => {
216                let dupe = dupe.get_mut();
217                if dupe.is_pending {
218                    dupe.num_pending_duplicates += 1;
219                } else {
220                    dupe.num_cleared_duplicates += 1;
221                }
222                dupe.last_is_frozen = None;
223                dupe.is_pending = false;
224                dupe.is_clearing = false;
225            }
226        }
227
228        *info.freeze() = Some(cookie);
229        let msg = FreezeMessage::init(msg, cookie);
230        drop(node_refs_guard);
231        let _ = self.push_work(msg);
232        Ok(())
233    }
234
235    pub(crate) fn freeze_notif_done(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> {
236        let cookie = FreezeCookie(reader.read()?);
237        let alloc = FreezeMessage::new(GFP_KERNEL)?;
238        let mut node_refs_guard = self.node_refs.lock();
239        let node_refs = &mut *node_refs_guard;
240        let Some(freeze) = node_refs.freeze_listeners.get_mut(&cookie) else {
241            pr_warn!("BC_FREEZE_NOTIFICATION_DONE {:016x} not found\n", cookie.0);
242            return Err(EINVAL);
243        };
244        let mut clear_msg = None;
245        if freeze.num_pending_duplicates > 0 {
246            clear_msg = Some(FreezeMessage::init(alloc, cookie));
247            freeze.num_pending_duplicates -= 1;
248            freeze.num_cleared_duplicates += 1;
249        } else {
250            if !freeze.is_pending {
251                pr_warn!(
252                    "BC_FREEZE_NOTIFICATION_DONE {:016x} not pending\n",
253                    cookie.0
254                );
255                return Err(EINVAL);
256            }
257            let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
258            if freeze.is_clearing || freeze.last_is_frozen != Some(is_frozen) {
259                // Immediately send another FreezeMessage.
260                clear_msg = Some(FreezeMessage::init(alloc, cookie));
261            }
262            freeze.is_pending = false;
263        }
264        drop(node_refs_guard);
265        if let Some(clear_msg) = clear_msg {
266            let _ = self.push_work(clear_msg);
267        }
268        Ok(())
269    }
270
271    pub(crate) fn clear_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> {
272        let hc = reader.read::<BinderHandleCookie>()?;
273        let handle = hc.handle;
274        let cookie = FreezeCookie(hc.cookie);
275
276        let alloc = FreezeMessage::new(GFP_KERNEL)?;
277        let mut node_refs_guard = self.node_refs.lock();
278        let node_refs = &mut *node_refs_guard;
279        let Some(info) = node_refs.by_handle.get_mut(&handle) else {
280            pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION invalid ref {}\n", handle);
281            return Err(EINVAL);
282        };
283        let Some(info_cookie) = info.freeze() else {
284            pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION freeze notification not active\n");
285            return Err(EINVAL);
286        };
287        if *info_cookie != cookie {
288            pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION freeze notification cookie mismatch\n");
289            return Err(EINVAL);
290        }
291        let Some(listener) = node_refs.freeze_listeners.get_mut(&cookie) else {
292            pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION invalid cookie {}\n", handle);
293            return Err(EINVAL);
294        };
295        listener.is_clearing = true;
296        listener.node.remove_freeze_listener(self);
297        *info.freeze() = None;
298        let mut msg = None;
299        if !listener.is_pending {
300            msg = Some(FreezeMessage::init(alloc, cookie));
301        }
302        drop(node_refs_guard);
303
304        if let Some(msg) = msg {
305            let _ = self.push_work(msg);
306        }
307        Ok(())
308    }
309
310    fn get_freeze_cookie(&self, node: &DArc<Node>) -> Option<FreezeCookie> {
311        let node_refs = &mut *self.node_refs.lock();
312        let handle = node_refs.by_node.get(&node.global_id())?;
313        let node_ref = node_refs.by_handle.get_mut(handle)?;
314        *node_ref.freeze()
315    }
316
317    /// Creates a vector of every freeze listener on this process.
318    ///
319    /// Returns pairs of the remote process listening for notifications and the local node it is
320    /// listening on.
321    #[expect(clippy::type_complexity)]
322    fn find_freeze_recipients(&self) -> Result<KVVec<(DArc<Node>, Arc<Process>)>, AllocError> {
323        // Defined before `inner` to drop after releasing spinlock if `push_within_capacity` fails.
324        let mut node_proc_pair;
325
326        // We pre-allocate space for up to 8 recipients before we take the spinlock. However, if
327        // the allocation fails, use a vector with a capacity of zero instead of failing. After
328        // all, there might not be any freeze listeners, in which case this operation could still
329        // succeed.
330        let mut recipients =
331            KVVec::with_capacity(8, GFP_KERNEL).unwrap_or_else(|_err| KVVec::new());
332
333        let mut inner = self.lock_with_nodes();
334        let mut curr = inner.nodes.cursor_front_mut();
335        while let Some(cursor) = curr {
336            let (key, node) = cursor.current();
337            let key = *key;
338            let list = node.freeze_list(&inner.inner);
339            let len = list.len();
340
341            if recipients.spare_capacity_mut().len() < len {
342                drop(inner);
343                recipients.reserve(len, GFP_KERNEL)?;
344                inner = self.lock_with_nodes();
345                // Find the node we were looking at and try again. If the set of nodes was changed,
346                // then just proceed to the next node. This is ok because we don't guarantee the
347                // inclusion of nodes that are added or removed in parallel with this operation.
348                curr = inner.nodes.cursor_lower_bound_mut(&key);
349                continue;
350            }
351
352            for proc in list {
353                node_proc_pair = (node.clone(), proc.clone());
354                recipients
355                    .push_within_capacity(node_proc_pair)
356                    .map_err(|_| {
357                        pr_err!(
358                            "push_within_capacity failed even though we checked the capacity\n"
359                        );
360                        AllocError
361                    })?;
362            }
363
364            curr = cursor.move_next();
365        }
366        Ok(recipients)
367    }
368
369    /// Prepare allocations for sending freeze messages.
370    pub(crate) fn prepare_freeze_messages(&self) -> Result<FreezeMessages, AllocError> {
371        let recipients = self.find_freeze_recipients()?;
372        let mut batch = KVVec::with_capacity(recipients.len(), GFP_KERNEL)?;
373        for (node, proc) in recipients {
374            let Some(cookie) = proc.get_freeze_cookie(&node) else {
375                // If the freeze listener was removed in the meantime, just discard the
376                // notification.
377                continue;
378            };
379            let msg_alloc = FreezeMessage::new(GFP_KERNEL)?;
380            let msg = FreezeMessage::init(msg_alloc, cookie);
381            batch.push((proc, msg), GFP_KERNEL)?;
382        }
383
384        Ok(FreezeMessages { batch })
385    }
386}
387
388pub(crate) struct FreezeMessages {
389    batch: KVVec<(Arc<Process>, DLArc<FreezeMessage>)>,
390}
391
392impl FreezeMessages {
393    pub(crate) fn send_messages(self) {
394        for (proc, msg) in self.batch {
395            let _ = proc.push_work(msg);
396        }
397    }
398}
~/ Read-only file preview.