• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! UProbestats executable.
2 use anyhow::{anyhow, bail, ensure, Result};
3 use binder::ProcessState;
4 use log::{debug, error, LevelFilter};
5 use rustutils::system_properties;
6 use std::process::exit;
7 use std::{
8     thread,
9     time::{Duration, Instant},
10 };
11 use uprobestats_bpf::bpf_perf_event_open;
12 use uprobestats_rs::{config_resolver, guardrail};
13 
14 mod bpf_map;
15 
main()16 fn main() {
17     logger::init(
18         logger::Config::default()
19             .with_tag_on_device("uprobestats")
20             .with_max_level(if is_user_build() { LevelFilter::Info } else { LevelFilter::Trace }),
21     );
22 
23     if let Err(e) = main_impl() {
24         error!("{}", e);
25         exit(1);
26     };
27 }
28 
main_impl() -> Result<()>29 fn main_impl() -> Result<()> {
30     debug!("started");
31 
32     ensure!(is_uprobestats_enabled(), "Uprobestats disabled by flag");
33 
34     let config = config_resolver::read_config("/data/misc/uprobestats-configs/config")?;
35     ensure!(
36         guardrail::is_allowed(&config, is_user_build(), true)?,
37         "uprobestats probing config disallowed on this device"
38     );
39     let task = config_resolver::resolve_single_task(config)?;
40 
41     ProcessState::start_thread_pool();
42 
43     let probes = config_resolver::resolve_probes(&task.task)?;
44     for probe in probes {
45         bpf_perf_event_open(
46             probe.filename.clone(),
47             probe.offset,
48             task.pid,
49             probe.bpf_program_path.clone(),
50         )?;
51         debug!(
52             "attached bpf {} to {} at {}",
53             probe.bpf_program_path, &probe.filename, &probe.offset
54         );
55     }
56 
57     let duration_seconds: u64 = task.duration_seconds.try_into()?;
58     let now = Instant::now();
59     let duration = Duration::from_secs(duration_seconds);
60 
61     let results = task.bpf_map_paths.into_iter().map(|map_path| {
62         debug!("Spawning thread for map_path: {}", map_path);
63         match thread::spawn({
64             let task_proto = task.task.clone();
65             move || bpf_map::poll_and_loop(&map_path, now, duration, task_proto)
66         })
67         .join()
68         {
69             Ok(result) => result.map_err(|e| anyhow!("Thread error: {}", e)),
70             Err(panic) => bail!("Thread panic: {:?}", panic),
71         }
72     });
73 
74     let errors: Vec<_> = results
75         .filter_map(|r| match r {
76             Ok(()) => None,
77             Err(e) => Some(e),
78         })
79         .collect();
80 
81     if !errors.is_empty() {
82         let msg = errors.into_iter().map(|e| e.to_string()).collect::<Vec<String>>().join(",");
83         let msg = format!("At least one thread returned error: {}", msg);
84         bail!("{}", msg);
85     }
86 
87     debug!("done");
88 
89     Ok(())
90 }
91 
is_user_build() -> bool92 fn is_user_build() -> bool {
93     if let Ok(Some(val)) = system_properties::read("ro.build.type") {
94         return val == "user";
95     }
96     true
97 }
98 
is_uprobestats_enabled() -> bool99 fn is_uprobestats_enabled() -> bool {
100     uprobestats_mainline_flags_rust::enable_uprobestats()
101 }
102