1 // SPDX-License-Identifier: GPL-2.0 2 3 // Copyright (C) 2024 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 { new() -> Self22 pub(crate) const fn new() -> Self { 23 const ZERO: AtomicU32 = AtomicU32::new(0); 24 25 Self { 26 bc: [ZERO; BC_COUNT], 27 br: [ZERO; BR_COUNT], 28 } 29 } 30 inc_bc(&self, bc: u32)31 pub(crate) fn inc_bc(&self, bc: u32) { 32 let idx = _IOC_NR(bc) as usize; 33 if let Some(bc_ref) = self.bc.get(idx) { 34 bc_ref.fetch_add(1, Relaxed); 35 } 36 } 37 inc_br(&self, br: u32)38 pub(crate) fn inc_br(&self, br: u32) { 39 let idx = _IOC_NR(br) as usize; 40 if let Some(br_ref) = self.br.get(idx) { 41 br_ref.fetch_add(1, Relaxed); 42 } 43 } 44 debug_print(&self, prefix: &str, m: &SeqFile)45 pub(crate) fn debug_print(&self, prefix: &str, m: &SeqFile) { 46 for (i, cnt) in self.bc.iter().enumerate() { 47 let cnt = cnt.load(Relaxed); 48 if cnt > 0 { 49 seq_print!(m, "{}{}: {}\n", prefix, command_string(i), cnt); 50 } 51 } 52 for (i, cnt) in self.br.iter().enumerate() { 53 let cnt = cnt.load(Relaxed); 54 if cnt > 0 { 55 seq_print!(m, "{}{}: {}\n", prefix, return_string(i), cnt); 56 } 57 } 58 } 59 } 60 61 mod strings { 62 use core::str::from_utf8_unchecked; 63 use kernel::str::CStr; 64 65 extern "C" { 66 static binder_command_strings: [*const u8; super::BC_COUNT]; 67 static binder_return_strings: [*const u8; super::BR_COUNT]; 68 } 69 command_string(i: usize) -> &'static str70 pub(super) fn command_string(i: usize) -> &'static str { 71 // SAFETY: Accessing `binder_command_strings` is always safe. 72 let c_str_ptr = unsafe { binder_command_strings[i] }; 73 // SAFETY: The `binder_command_strings` array only contains nul-terminated strings. 74 let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.as_bytes(); 75 // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars. 76 unsafe { from_utf8_unchecked(bytes) } 77 } 78 return_string(i: usize) -> &'static str79 pub(super) fn return_string(i: usize) -> &'static str { 80 // SAFETY: Accessing `binder_return_strings` is always safe. 81 let c_str_ptr = unsafe { binder_return_strings[i] }; 82 // SAFETY: The `binder_command_strings` array only contains nul-terminated strings. 83 let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.as_bytes(); 84 // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars. 85 unsafe { from_utf8_unchecked(bytes) } 86 } 87 } 88 use strings::{command_string, return_string}; 89