xref: /aosp_15_r20/system/extras/profcollectd/libprofcollectd/service.rs (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker //
2*288bf522SAndroid Build Coastguard Worker // Copyright (C) 2021 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker //
4*288bf522SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker //
8*288bf522SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker //
10*288bf522SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker // limitations under the License.
15*288bf522SAndroid Build Coastguard Worker //
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker //! ProfCollect Binder service implementation.
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker use anyhow::{anyhow, Context, Error, Result};
20*288bf522SAndroid Build Coastguard Worker use binder::Result as BinderResult;
21*288bf522SAndroid Build Coastguard Worker use binder::{SpIBinder, Status};
22*288bf522SAndroid Build Coastguard Worker use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::IProfCollectd;
23*288bf522SAndroid Build Coastguard Worker use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProviderStatusCallback::IProviderStatusCallback;
24*288bf522SAndroid Build Coastguard Worker use std::ffi::CString;
25*288bf522SAndroid Build Coastguard Worker use std::fs::{read_dir, read_to_string, remove_file, write};
26*288bf522SAndroid Build Coastguard Worker use std::str::FromStr;
27*288bf522SAndroid Build Coastguard Worker use std::sync::{Mutex, MutexGuard};
28*288bf522SAndroid Build Coastguard Worker use std::time::Duration;
29*288bf522SAndroid Build Coastguard Worker 
30*288bf522SAndroid Build Coastguard Worker use crate::config::{
31*288bf522SAndroid Build Coastguard Worker     clear_data, Config, CONFIG_FILE, PROFILE_OUTPUT_DIR, REPORT_OUTPUT_DIR, REPORT_RETENTION_SECS,
32*288bf522SAndroid Build Coastguard Worker };
33*288bf522SAndroid Build Coastguard Worker use crate::report::{get_report_ts, pack_report};
34*288bf522SAndroid Build Coastguard Worker use crate::scheduler::Scheduler;
35*288bf522SAndroid Build Coastguard Worker 
err_to_binder_status(msg: Error) -> Status36*288bf522SAndroid Build Coastguard Worker pub fn err_to_binder_status(msg: Error) -> Status {
37*288bf522SAndroid Build Coastguard Worker     let msg = format!("{:#?}", msg);
38*288bf522SAndroid Build Coastguard Worker     let msg = CString::new(msg).expect("Failed to convert to CString");
39*288bf522SAndroid Build Coastguard Worker     Status::new_service_specific_error(1, Some(&msg))
40*288bf522SAndroid Build Coastguard Worker }
41*288bf522SAndroid Build Coastguard Worker 
42*288bf522SAndroid Build Coastguard Worker pub struct ProfcollectdBinderService {
43*288bf522SAndroid Build Coastguard Worker     lock: Mutex<Lock>,
44*288bf522SAndroid Build Coastguard Worker }
45*288bf522SAndroid Build Coastguard Worker 
46*288bf522SAndroid Build Coastguard Worker struct Lock {
47*288bf522SAndroid Build Coastguard Worker     config: Config,
48*288bf522SAndroid Build Coastguard Worker     scheduler: Scheduler,
49*288bf522SAndroid Build Coastguard Worker }
50*288bf522SAndroid Build Coastguard Worker 
51*288bf522SAndroid Build Coastguard Worker impl binder::Interface for ProfcollectdBinderService {}
52*288bf522SAndroid Build Coastguard Worker 
53*288bf522SAndroid Build Coastguard Worker impl IProfCollectd for ProfcollectdBinderService {
schedule(&self) -> BinderResult<()>54*288bf522SAndroid Build Coastguard Worker     fn schedule(&self) -> BinderResult<()> {
55*288bf522SAndroid Build Coastguard Worker         let lock = &mut *self.lock();
56*288bf522SAndroid Build Coastguard Worker         lock.scheduler
57*288bf522SAndroid Build Coastguard Worker             .schedule_periodic(&lock.config)
58*288bf522SAndroid Build Coastguard Worker             .context("Failed to schedule collection.")
59*288bf522SAndroid Build Coastguard Worker             .map_err(err_to_binder_status)
60*288bf522SAndroid Build Coastguard Worker     }
terminate(&self) -> BinderResult<()>61*288bf522SAndroid Build Coastguard Worker     fn terminate(&self) -> BinderResult<()> {
62*288bf522SAndroid Build Coastguard Worker         self.lock()
63*288bf522SAndroid Build Coastguard Worker             .scheduler
64*288bf522SAndroid Build Coastguard Worker             .terminate_periodic()
65*288bf522SAndroid Build Coastguard Worker             .context("Failed to terminate collection.")
66*288bf522SAndroid Build Coastguard Worker             .map_err(err_to_binder_status)
67*288bf522SAndroid Build Coastguard Worker     }
trace_system(&self, tag: &str) -> BinderResult<()>68*288bf522SAndroid Build Coastguard Worker     fn trace_system(&self, tag: &str) -> BinderResult<()> {
69*288bf522SAndroid Build Coastguard Worker         let lock = &mut *self.lock();
70*288bf522SAndroid Build Coastguard Worker         lock.scheduler
71*288bf522SAndroid Build Coastguard Worker             .trace_system(&lock.config, tag)
72*288bf522SAndroid Build Coastguard Worker             .context("Failed to perform system-wide trace.")
73*288bf522SAndroid Build Coastguard Worker             .map_err(err_to_binder_status)
74*288bf522SAndroid Build Coastguard Worker     }
trace_process(&self, tag: &str, process: &str, duration: f32) -> BinderResult<()>75*288bf522SAndroid Build Coastguard Worker     fn trace_process(&self, tag: &str, process: &str, duration: f32) -> BinderResult<()> {
76*288bf522SAndroid Build Coastguard Worker         let lock = &mut *self.lock();
77*288bf522SAndroid Build Coastguard Worker         lock.scheduler
78*288bf522SAndroid Build Coastguard Worker             .trace_process(&lock.config, tag, process, duration)
79*288bf522SAndroid Build Coastguard Worker             .context("Failed to perform process trace.")
80*288bf522SAndroid Build Coastguard Worker             .map_err(err_to_binder_status)
81*288bf522SAndroid Build Coastguard Worker     }
process(&self) -> BinderResult<()>82*288bf522SAndroid Build Coastguard Worker     fn process(&self) -> BinderResult<()> {
83*288bf522SAndroid Build Coastguard Worker         let lock = &mut *self.lock();
84*288bf522SAndroid Build Coastguard Worker         lock.scheduler
85*288bf522SAndroid Build Coastguard Worker             .process(&lock.config)
86*288bf522SAndroid Build Coastguard Worker             .context("Failed to process profiles.")
87*288bf522SAndroid Build Coastguard Worker             .map_err(err_to_binder_status)
88*288bf522SAndroid Build Coastguard Worker     }
report(&self, usage_setting: i32) -> BinderResult<String>89*288bf522SAndroid Build Coastguard Worker     fn report(&self, usage_setting: i32) -> BinderResult<String> {
90*288bf522SAndroid Build Coastguard Worker         self.process()?;
91*288bf522SAndroid Build Coastguard Worker 
92*288bf522SAndroid Build Coastguard Worker         let lock = &mut *self.lock();
93*288bf522SAndroid Build Coastguard Worker         pack_report(&PROFILE_OUTPUT_DIR, &REPORT_OUTPUT_DIR, &lock.config, usage_setting)
94*288bf522SAndroid Build Coastguard Worker             .context("Failed to create profile report.")
95*288bf522SAndroid Build Coastguard Worker             .map_err(err_to_binder_status)
96*288bf522SAndroid Build Coastguard Worker     }
get_supported_provider(&self) -> BinderResult<String>97*288bf522SAndroid Build Coastguard Worker     fn get_supported_provider(&self) -> BinderResult<String> {
98*288bf522SAndroid Build Coastguard Worker         Ok(self.lock().scheduler.get_trace_provider_name().to_string())
99*288bf522SAndroid Build Coastguard Worker     }
100*288bf522SAndroid Build Coastguard Worker 
registerProviderStatusCallback( &self, cb: &binder::Strong<(dyn IProviderStatusCallback)>, ) -> BinderResult<()>101*288bf522SAndroid Build Coastguard Worker     fn registerProviderStatusCallback(
102*288bf522SAndroid Build Coastguard Worker         &self,
103*288bf522SAndroid Build Coastguard Worker         cb: &binder::Strong<(dyn IProviderStatusCallback)>,
104*288bf522SAndroid Build Coastguard Worker     ) -> BinderResult<()> {
105*288bf522SAndroid Build Coastguard Worker         if self.lock().scheduler.is_provider_ready() {
106*288bf522SAndroid Build Coastguard Worker             if let Err(e) = cb.onProviderReady() {
107*288bf522SAndroid Build Coastguard Worker                 log::error!("Failed to call ProviderStatusCallback {:?}", e);
108*288bf522SAndroid Build Coastguard Worker             }
109*288bf522SAndroid Build Coastguard Worker             return Ok(());
110*288bf522SAndroid Build Coastguard Worker         }
111*288bf522SAndroid Build Coastguard Worker 
112*288bf522SAndroid Build Coastguard Worker         let cb_binder: SpIBinder = cb.as_binder();
113*288bf522SAndroid Build Coastguard Worker         self.lock().scheduler.register_provider_ready_callback(Box::new(move || {
114*288bf522SAndroid Build Coastguard Worker             if let Ok(cb) = cb_binder.into_interface::<dyn IProviderStatusCallback>() {
115*288bf522SAndroid Build Coastguard Worker                 if let Err(e) = cb.onProviderReady() {
116*288bf522SAndroid Build Coastguard Worker                     log::error!("Failed to call ProviderStatusCallback {:?}", e)
117*288bf522SAndroid Build Coastguard Worker                 }
118*288bf522SAndroid Build Coastguard Worker             } else {
119*288bf522SAndroid Build Coastguard Worker                 log::error!("SpIBinder is not a IProviderStatusCallback.");
120*288bf522SAndroid Build Coastguard Worker             }
121*288bf522SAndroid Build Coastguard Worker         }));
122*288bf522SAndroid Build Coastguard Worker         Ok(())
123*288bf522SAndroid Build Coastguard Worker     }
124*288bf522SAndroid Build Coastguard Worker }
125*288bf522SAndroid Build Coastguard Worker 
126*288bf522SAndroid Build Coastguard Worker impl ProfcollectdBinderService {
new() -> Result<Self>127*288bf522SAndroid Build Coastguard Worker     pub fn new() -> Result<Self> {
128*288bf522SAndroid Build Coastguard Worker         let new_scheduler = Scheduler::new()?;
129*288bf522SAndroid Build Coastguard Worker         let new_config = Config::from_env()?;
130*288bf522SAndroid Build Coastguard Worker 
131*288bf522SAndroid Build Coastguard Worker         let config_changed = read_to_string(*CONFIG_FILE)
132*288bf522SAndroid Build Coastguard Worker             .ok()
133*288bf522SAndroid Build Coastguard Worker             .and_then(|s| Config::from_str(&s).ok())
134*288bf522SAndroid Build Coastguard Worker             .filter(|c| new_config == *c)
135*288bf522SAndroid Build Coastguard Worker             .is_none();
136*288bf522SAndroid Build Coastguard Worker 
137*288bf522SAndroid Build Coastguard Worker         if config_changed {
138*288bf522SAndroid Build Coastguard Worker             log::info!("Config change detected, resetting profcollect.");
139*288bf522SAndroid Build Coastguard Worker             clear_data()?;
140*288bf522SAndroid Build Coastguard Worker 
141*288bf522SAndroid Build Coastguard Worker             write(*CONFIG_FILE, new_config.to_string())?;
142*288bf522SAndroid Build Coastguard Worker             new_scheduler.clear_trace_log()?;
143*288bf522SAndroid Build Coastguard Worker         }
144*288bf522SAndroid Build Coastguard Worker 
145*288bf522SAndroid Build Coastguard Worker         // Clear profile reports out of rentention period.
146*288bf522SAndroid Build Coastguard Worker         for report in read_dir(*REPORT_OUTPUT_DIR)? {
147*288bf522SAndroid Build Coastguard Worker             let report = report?.path();
148*288bf522SAndroid Build Coastguard Worker             let report_name = report
149*288bf522SAndroid Build Coastguard Worker                 .file_stem()
150*288bf522SAndroid Build Coastguard Worker                 .and_then(|f| f.to_str())
151*288bf522SAndroid Build Coastguard Worker                 .ok_or_else(|| anyhow!("Malformed path {}", report.display()))?;
152*288bf522SAndroid Build Coastguard Worker             let report_ts = get_report_ts(report_name);
153*288bf522SAndroid Build Coastguard Worker             if let Err(e) = report_ts {
154*288bf522SAndroid Build Coastguard Worker                 log::error!(
155*288bf522SAndroid Build Coastguard Worker                     "Cannot decode creation timestamp for report {}, caused by {}, deleting",
156*288bf522SAndroid Build Coastguard Worker                     report_name,
157*288bf522SAndroid Build Coastguard Worker                     e
158*288bf522SAndroid Build Coastguard Worker                 );
159*288bf522SAndroid Build Coastguard Worker                 remove_file(report)?;
160*288bf522SAndroid Build Coastguard Worker                 continue;
161*288bf522SAndroid Build Coastguard Worker             }
162*288bf522SAndroid Build Coastguard Worker             let report_age = report_ts.unwrap().elapsed()?;
163*288bf522SAndroid Build Coastguard Worker             if report_age > Duration::from_secs(REPORT_RETENTION_SECS) {
164*288bf522SAndroid Build Coastguard Worker                 log::info!("Report {} past rentention period, deleting", report_name);
165*288bf522SAndroid Build Coastguard Worker                 remove_file(report)?;
166*288bf522SAndroid Build Coastguard Worker             }
167*288bf522SAndroid Build Coastguard Worker         }
168*288bf522SAndroid Build Coastguard Worker 
169*288bf522SAndroid Build Coastguard Worker         Ok(ProfcollectdBinderService {
170*288bf522SAndroid Build Coastguard Worker             lock: Mutex::new(Lock { scheduler: new_scheduler, config: new_config }),
171*288bf522SAndroid Build Coastguard Worker         })
172*288bf522SAndroid Build Coastguard Worker     }
173*288bf522SAndroid Build Coastguard Worker 
lock(&self) -> MutexGuard<Lock>174*288bf522SAndroid Build Coastguard Worker     fn lock(&self) -> MutexGuard<Lock> {
175*288bf522SAndroid Build Coastguard Worker         self.lock.lock().unwrap()
176*288bf522SAndroid Build Coastguard Worker     }
177*288bf522SAndroid Build Coastguard Worker }
178