• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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