blob: 5e3097af98426e74b3ffb6e006f207671f1ea8be [file] [log] [blame]
Yi Konge3aab142021-03-02 13:58:25 +08001//
2// Copyright (C) 2021 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17//! ProfCollect Binder service implementation.
18
Yi Kong6e3fe962021-11-30 14:24:10 +080019use anyhow::{anyhow, Context, Error, Result};
Stephen Crane23e8e532022-01-19 17:49:46 +000020use binder::Result as BinderResult;
Yabin Cuif158a752022-01-10 15:35:59 -080021use binder::{SpIBinder, Status};
Yi Konge3aab142021-03-02 13:58:25 +080022use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::IProfCollectd;
Yabin Cuif158a752022-01-10 15:35:59 -080023use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProviderStatusCallback::IProviderStatusCallback;
Yi Konge3aab142021-03-02 13:58:25 +080024use std::ffi::CString;
Yi Kong6e3fe962021-11-30 14:24:10 +080025use std::fs::{read_dir, read_to_string, remove_file, write};
Yi Konge30762a2021-03-24 02:41:49 +080026use std::str::FromStr;
27use std::sync::{Mutex, MutexGuard};
Yi Kong8dffc122021-07-20 16:55:39 +080028use std::time::Duration;
Yi Konge3aab142021-03-02 13:58:25 +080029
Yi Kong4e33c572021-03-04 14:47:48 +080030use crate::config::{
Yi Kong6e3fe962021-11-30 14:24:10 +080031 clear_data, Config, CONFIG_FILE, PROFILE_OUTPUT_DIR, REPORT_OUTPUT_DIR, REPORT_RETENTION_SECS,
Yi Kong4e33c572021-03-04 14:47:48 +080032};
Yi Kong8dffc122021-07-20 16:55:39 +080033use crate::report::{get_report_ts, pack_report};
Yi Konge3aab142021-03-02 13:58:25 +080034use crate::scheduler::Scheduler;
35
Yabin Cuif158a752022-01-10 15:35:59 -080036pub fn err_to_binder_status(msg: Error) -> Status {
Yi Kongbbc9b4e2021-03-29 16:53:03 +080037 let msg = format!("{:#?}", msg);
38 let msg = CString::new(msg).expect("Failed to convert to CString");
Yi Konge3aab142021-03-02 13:58:25 +080039 Status::new_service_specific_error(1, Some(&msg))
40}
41
42pub struct ProfcollectdBinderService {
43 lock: Mutex<Lock>,
44}
45
46struct Lock {
47 config: Config,
48 scheduler: Scheduler,
49}
50
51impl binder::Interface for ProfcollectdBinderService {}
52
53impl IProfCollectd for ProfcollectdBinderService {
54 fn schedule(&self) -> BinderResult<()> {
55 let lock = &mut *self.lock();
56 lock.scheduler
57 .schedule_periodic(&lock.config)
58 .context("Failed to schedule collection.")
59 .map_err(err_to_binder_status)
60 }
61 fn terminate(&self) -> BinderResult<()> {
62 self.lock()
63 .scheduler
64 .terminate_periodic()
65 .context("Failed to terminate collection.")
66 .map_err(err_to_binder_status)
67 }
Yi Kongc26c15b2024-07-06 17:20:44 +090068 fn trace_system(&self, tag: &str) -> BinderResult<()> {
Yi Konge3aab142021-03-02 13:58:25 +080069 let lock = &mut *self.lock();
70 lock.scheduler
Yi Kongbae27482024-07-09 02:41:54 +090071 .trace_system(&lock.config, tag)
72 .context("Failed to perform system-wide trace.")
73 .map_err(err_to_binder_status)
74 }
Yi Kong90fc4c92024-07-22 14:30:54 +090075 fn trace_process(&self, tag: &str, process: &str, duration: f32) -> BinderResult<()> {
Yi Kongbae27482024-07-09 02:41:54 +090076 let lock = &mut *self.lock();
77 lock.scheduler
Yi Kong90fc4c92024-07-22 14:30:54 +090078 .trace_process(&lock.config, tag, process, duration)
Yi Kongbae27482024-07-09 02:41:54 +090079 .context("Failed to perform process trace.")
Yi Konge3aab142021-03-02 13:58:25 +080080 .map_err(err_to_binder_status)
81 }
Yi Konge7627422021-11-15 16:20:02 +080082 fn process(&self) -> BinderResult<()> {
Yi Konge3aab142021-03-02 13:58:25 +080083 let lock = &mut *self.lock();
84 lock.scheduler
Yi Kong87d0a172021-12-09 01:37:57 +080085 .process(&lock.config)
Yi Konge3aab142021-03-02 13:58:25 +080086 .context("Failed to process profiles.")
87 .map_err(err_to_binder_status)
88 }
Yabin Cui1c3d80e2023-05-12 20:47:27 +000089 fn report(&self, usage_setting: i32) -> BinderResult<String> {
Yi Konge7627422021-11-15 16:20:02 +080090 self.process()?;
Yi Kong037bde82021-03-23 14:25:38 +080091
92 let lock = &mut *self.lock();
Yabin Cui1c3d80e2023-05-12 20:47:27 +000093 pack_report(&PROFILE_OUTPUT_DIR, &REPORT_OUTPUT_DIR, &lock.config, usage_setting)
Yi Konge3aab142021-03-02 13:58:25 +080094 .context("Failed to create profile report.")
95 .map_err(err_to_binder_status)
96 }
97 fn get_supported_provider(&self) -> BinderResult<String> {
98 Ok(self.lock().scheduler.get_trace_provider_name().to_string())
99 }
Yabin Cuif158a752022-01-10 15:35:59 -0800100
101 fn registerProviderStatusCallback(
102 &self,
103 cb: &binder::Strong<(dyn IProviderStatusCallback)>,
104 ) -> BinderResult<()> {
105 if self.lock().scheduler.is_provider_ready() {
106 if let Err(e) = cb.onProviderReady() {
107 log::error!("Failed to call ProviderStatusCallback {:?}", e);
108 }
109 return Ok(());
110 }
111
112 let cb_binder: SpIBinder = cb.as_binder();
113 self.lock().scheduler.register_provider_ready_callback(Box::new(move || {
114 if let Ok(cb) = cb_binder.into_interface::<dyn IProviderStatusCallback>() {
115 if let Err(e) = cb.onProviderReady() {
116 log::error!("Failed to call ProviderStatusCallback {:?}", e)
117 }
118 } else {
119 log::error!("SpIBinder is not a IProviderStatusCallback.");
120 }
121 }));
122 Ok(())
123 }
Yi Konge3aab142021-03-02 13:58:25 +0800124}
125
126impl ProfcollectdBinderService {
127 pub fn new() -> Result<Self> {
128 let new_scheduler = Scheduler::new()?;
129 let new_config = Config::from_env()?;
130
131 let config_changed = read_to_string(*CONFIG_FILE)
132 .ok()
133 .and_then(|s| Config::from_str(&s).ok())
134 .filter(|c| new_config == *c)
135 .is_none();
136
137 if config_changed {
Yi Kong34ebf872021-11-29 19:57:55 +0800138 log::info!("Config change detected, resetting profcollect.");
139 clear_data()?;
Yi Kong4e33c572021-03-04 14:47:48 +0800140
Chris Wailesc270ca52023-01-19 16:35:09 -0800141 write(*CONFIG_FILE, new_config.to_string())?;
Yabin Cuif1d91d22023-04-27 12:50:59 -0700142 new_scheduler.clear_trace_log()?;
Yi Konge3aab142021-03-02 13:58:25 +0800143 }
144
Yi Kong8dffc122021-07-20 16:55:39 +0800145 // Clear profile reports out of rentention period.
146 for report in read_dir(*REPORT_OUTPUT_DIR)? {
147 let report = report?.path();
148 let report_name = report
149 .file_stem()
150 .and_then(|f| f.to_str())
151 .ok_or_else(|| anyhow!("Malformed path {}", report.display()))?;
152 let report_ts = get_report_ts(report_name);
153 if let Err(e) = report_ts {
154 log::error!(
155 "Cannot decode creation timestamp for report {}, caused by {}, deleting",
156 report_name,
157 e
158 );
159 remove_file(report)?;
160 continue;
161 }
162 let report_age = report_ts.unwrap().elapsed()?;
163 if report_age > Duration::from_secs(REPORT_RETENTION_SECS) {
164 log::info!("Report {} past rentention period, deleting", report_name);
165 remove_file(report)?;
166 }
167 }
168
Yi Konge3aab142021-03-02 13:58:25 +0800169 Ok(ProfcollectdBinderService {
170 lock: Mutex::new(Lock { scheduler: new_scheduler, config: new_config }),
171 })
172 }
173
174 fn lock(&self) -> MutexGuard<Lock> {
175 self.lock.lock().unwrap()
176 }
177}