xref: /linux/drivers/android/binder/stats.rs (revision eafedbc7c050c44744fbdf80bdf3315e860b7513)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2025 Google LLC.
4 
5 //! Keep track of statistics for binder_logs.
6 
7 use crate::defs::*;
8 use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
9 use kernel::{ioctl::_IOC_NR, seq_file::SeqFile, seq_print};
10 
11 const BC_COUNT: usize = _IOC_NR(BC_REPLY_SG) as usize + 1;
12 const BR_COUNT: usize = _IOC_NR(BR_TRANSACTION_PENDING_FROZEN) as usize + 1;
13 
14 pub(crate) static GLOBAL_STATS: BinderStats = BinderStats::new();
15 
16 pub(crate) struct BinderStats {
17     bc: [AtomicU32; BC_COUNT],
18     br: [AtomicU32; BR_COUNT],
19 }
20 
21 impl BinderStats {
22     pub(crate) const fn new() -> Self {
23         #[expect(clippy::declare_interior_mutable_const)]
24         const ZERO: AtomicU32 = AtomicU32::new(0);
25 
26         Self {
27             bc: [ZERO; BC_COUNT],
28             br: [ZERO; BR_COUNT],
29         }
30     }
31 
32     pub(crate) fn inc_bc(&self, bc: u32) {
33         let idx = _IOC_NR(bc) as usize;
34         if let Some(bc_ref) = self.bc.get(idx) {
35             bc_ref.fetch_add(1, Relaxed);
36         }
37     }
38 
39     pub(crate) fn inc_br(&self, br: u32) {
40         let idx = _IOC_NR(br) as usize;
41         if let Some(br_ref) = self.br.get(idx) {
42             br_ref.fetch_add(1, Relaxed);
43         }
44     }
45 
46     pub(crate) fn debug_print(&self, prefix: &str, m: &SeqFile) {
47         for (i, cnt) in self.bc.iter().enumerate() {
48             let cnt = cnt.load(Relaxed);
49             if cnt > 0 {
50                 seq_print!(m, "{}{}: {}\n", prefix, command_string(i), cnt);
51             }
52         }
53         for (i, cnt) in self.br.iter().enumerate() {
54             let cnt = cnt.load(Relaxed);
55             if cnt > 0 {
56                 seq_print!(m, "{}{}: {}\n", prefix, return_string(i), cnt);
57             }
58         }
59     }
60 }
61 
62 mod strings {
63     use core::str::from_utf8_unchecked;
64     use kernel::str::CStr;
65 
66     extern "C" {
67         static binder_command_strings: [*const u8; super::BC_COUNT];
68         static binder_return_strings: [*const u8; super::BR_COUNT];
69     }
70 
71     pub(super) fn command_string(i: usize) -> &'static str {
72         // SAFETY: Accessing `binder_command_strings` is always safe.
73         let c_str_ptr = unsafe { binder_command_strings[i] };
74         // SAFETY: The `binder_command_strings` array only contains nul-terminated strings.
75         let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.as_bytes();
76         // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars.
77         unsafe { from_utf8_unchecked(bytes) }
78     }
79 
80     pub(super) fn return_string(i: usize) -> &'static str {
81         // SAFETY: Accessing `binder_return_strings` is always safe.
82         let c_str_ptr = unsafe { binder_return_strings[i] };
83         // SAFETY: The `binder_command_strings` array only contains nul-terminated strings.
84         let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.as_bytes();
85         // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars.
86         unsafe { from_utf8_unchecked(bytes) }
87     }
88 }
89 use strings::{command_string, return_string};
90