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