diff options
author | Yabin Cui <yabinc@google.com> | 2022-02-09 18:09:59 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-02-09 18:09:59 +0000 |
commit | d9d70c8fb612d61f990f6ae5be2b2f29e07bcc71 (patch) | |
tree | a8d5e6a1d53af37eaf5f3b8c49a21a7de1daab72 /profcollectd | |
parent | e3f9772919c1c6407f25300f17d0cf088a9201cc (diff) | |
parent | f158a752cf96f9d710314731c6cdc407230a80f6 (diff) | |
download | extras-d9d70c8fb612d61f990f6ae5be2b2f29e07bcc71.tar.gz |
Merge "profcollectd: add interface to wait for ETM after boot."android-t-preview-2android-t-preview-1android-t-beta-3android-s-v2-beta-3android-s-qpr3-beta-1android-t-preview-1android-s-v2-beta-3android-s-qpr3-beta-1
Diffstat (limited to 'profcollectd')
9 files changed, 145 insertions, 7 deletions
diff --git a/profcollectd/Android.bp b/profcollectd/Android.bp index f1723006..122e4f61 100644 --- a/profcollectd/Android.bp +++ b/profcollectd/Android.bp @@ -59,6 +59,7 @@ filegroup { name: "profcollectd_aidl", srcs: [ "binder/com/android/server/profcollect/IProfCollectd.aidl", + "binder/com/android/server/profcollect/IProviderStatusCallback.aidl", ], path: "binder", } diff --git a/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl b/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl index c8f33a1e..bfc24446 100644 --- a/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl +++ b/profcollectd/binder/com/android/server/profcollect/IProfCollectd.aidl @@ -16,6 +16,8 @@ package com.android.server.profcollect; +import com.android.server.profcollect.IProviderStatusCallback; + /** {@hide} */ interface IProfCollectd { void schedule(); @@ -24,4 +26,5 @@ interface IProfCollectd { void process(); @utf8InCpp String report(); @utf8InCpp String get_supported_provider(); + void registerProviderStatusCallback(IProviderStatusCallback cb); } diff --git a/profcollectd/binder/com/android/server/profcollect/IProviderStatusCallback.aidl b/profcollectd/binder/com/android/server/profcollect/IProviderStatusCallback.aidl new file mode 100644 index 00000000..b311cf91 --- /dev/null +++ b/profcollectd/binder/com/android/server/profcollect/IProviderStatusCallback.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.profcollect; + +/** {@hide} */ +oneway interface IProviderStatusCallback { + void onProviderReady(); +} diff --git a/profcollectd/libprofcollectd/lib.rs b/profcollectd/libprofcollectd/lib.rs index abc11272..f95132f4 100644 --- a/profcollectd/libprofcollectd/lib.rs +++ b/profcollectd/libprofcollectd/lib.rs @@ -30,11 +30,34 @@ use anyhow::{Context, Result}; use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::{ self, BnProfCollectd, }; +use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProviderStatusCallback::{IProviderStatusCallback, BnProviderStatusCallback}; use profcollectd_aidl_interface::binder::{self, BinderFeatures}; -use service::ProfcollectdBinderService; +use service::{err_to_binder_status, ProfcollectdBinderService}; +use std::time::{Duration, Instant}; const PROFCOLLECTD_SERVICE_NAME: &str = "profcollectd"; +struct ProviderStatusCallback { + service_start_time: Instant, +} + +impl binder::Interface for ProviderStatusCallback {} + +impl IProviderStatusCallback for ProviderStatusCallback { + fn onProviderReady(&self) -> binder::Result<()> { + // If we have waited too long for the provider to be ready, then we have passed + // boot phase, and no need to collect boot profile. + // TODO: should we check boottime instead? + const TIMEOUT_TO_COLLECT_BOOT_PROFILE: Duration = Duration::from_secs(3); + let elapsed = Instant::now().duration_since(self.service_start_time); + if elapsed < TIMEOUT_TO_COLLECT_BOOT_PROFILE { + trace_once("boot").map_err(err_to_binder_status)?; + } + schedule().map_err(err_to_binder_status)?; + Ok(()) + } +} + /// Initialise profcollectd service. /// * `schedule_now` - Immediately schedule collection after service is initialised. pub fn init_service(schedule_now: bool) -> Result<()> { @@ -49,8 +72,11 @@ pub fn init_service(schedule_now: bool) -> Result<()> { .context("Failed to register service.")?; if schedule_now { - trace_once("boot")?; - schedule()?; + let cb = BnProviderStatusCallback::new_binder( + ProviderStatusCallback { service_start_time: Instant::now() }, + BinderFeatures::default(), + ); + get_profcollectd_service()?.registerProviderStatusCallback(&cb)?; } binder::ProcessState::join_thread_pool(); diff --git a/profcollectd/libprofcollectd/logging_trace_provider.rs b/profcollectd/libprofcollectd/logging_trace_provider.rs index 1325855d..fda4c66a 100644 --- a/profcollectd/libprofcollectd/logging_trace_provider.rs +++ b/profcollectd/libprofcollectd/logging_trace_provider.rs @@ -32,6 +32,10 @@ impl TraceProvider for LoggingTraceProvider { "logging" } + fn is_ready(&self) -> bool { + true + } + fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration) { let trace_file = trace_provider::get_path(trace_dir, tag, LOGGING_TRACEFILE_EXTENSION); diff --git a/profcollectd/libprofcollectd/scheduler.rs b/profcollectd/libprofcollectd/scheduler.rs index 31a495a5..f58c4995 100644 --- a/profcollectd/libprofcollectd/scheduler.rs +++ b/profcollectd/libprofcollectd/scheduler.rs @@ -17,11 +17,13 @@ //! ProfCollect tracing scheduler. use std::fs; +use std::mem; use std::path::Path; use std::sync::mpsc::{sync_channel, SyncSender}; use std::sync::Arc; use std::sync::Mutex; use std::thread; +use std::time::{Duration, Instant}; use crate::config::{Config, PROFILE_OUTPUT_DIR, TRACE_OUTPUT_DIR}; use crate::trace_provider::{self, TraceProvider}; @@ -33,12 +35,17 @@ pub struct Scheduler { termination_ch: Option<SyncSender<()>>, /// The preferred trace provider for the system. trace_provider: Arc<Mutex<dyn TraceProvider + Send>>, + provider_ready_callbacks: Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>>, } impl Scheduler { pub fn new() -> Result<Self> { let p = trace_provider::get_trace_provider()?; - Ok(Scheduler { termination_ch: None, trace_provider: p }) + Ok(Scheduler { + termination_ch: None, + trace_provider: p, + provider_ready_callbacks: Arc::new(Mutex::new(Vec::new())), + }) } fn is_scheduled(&self) -> bool { @@ -106,6 +113,51 @@ impl Scheduler { pub fn get_trace_provider_name(&self) -> &'static str { self.trace_provider.lock().unwrap().get_name() } + + pub fn is_provider_ready(&self) -> bool { + self.trace_provider.lock().unwrap().is_ready() + } + + pub fn register_provider_ready_callback(&self, cb: Box<dyn FnOnce() + Send>) { + let mut locked_callbacks = self.provider_ready_callbacks.lock().unwrap(); + locked_callbacks.push(cb); + if locked_callbacks.len() == 1 { + self.start_thread_waiting_for_provider_ready(); + } + } + + fn start_thread_waiting_for_provider_ready(&self) { + let provider = self.trace_provider.clone(); + let callbacks = self.provider_ready_callbacks.clone(); + + thread::spawn(move || { + let start_time = Instant::now(); + loop { + let elapsed = Instant::now().duration_since(start_time); + if provider.lock().unwrap().is_ready() { + break; + } + // Decide check period based on how long we have waited: + // For the first 10s waiting, check every 100ms (likely to work on EVT devices). + // For the first 10m waiting, check every 10s (likely to work on DVT devices). + // For others, check every 10m. + let sleep_duration = if elapsed < Duration::from_secs(10) { + Duration::from_millis(100) + } else if elapsed < Duration::from_secs(60 * 10) { + Duration::from_secs(10) + } else { + Duration::from_secs(60 * 10) + }; + thread::sleep(sleep_duration); + } + + let mut locked_callbacks = callbacks.lock().unwrap(); + let v = mem::take(&mut *locked_callbacks); + for cb in v { + cb(); + } + }); + } } /// Run if space usage is under limit. diff --git a/profcollectd/libprofcollectd/service.rs b/profcollectd/libprofcollectd/service.rs index 0199c105..3f338024 100644 --- a/profcollectd/libprofcollectd/service.rs +++ b/profcollectd/libprofcollectd/service.rs @@ -18,8 +18,9 @@ use anyhow::{anyhow, Context, Error, Result}; use binder::Result as BinderResult; -use binder::Status; +use binder::{SpIBinder, Status}; use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProfCollectd::IProfCollectd; +use profcollectd_aidl_interface::aidl::com::android::server::profcollect::IProviderStatusCallback::IProviderStatusCallback; use std::ffi::CString; use std::fs::{read_dir, read_to_string, remove_file, write}; use std::str::FromStr; @@ -32,7 +33,7 @@ use crate::config::{ use crate::report::{get_report_ts, pack_report}; use crate::scheduler::Scheduler; -fn err_to_binder_status(msg: Error) -> Status { +pub fn err_to_binder_status(msg: Error) -> Status { let msg = format!("{:#?}", msg); let msg = CString::new(msg).expect("Failed to convert to CString"); Status::new_service_specific_error(1, Some(&msg)) @@ -89,6 +90,30 @@ impl IProfCollectd for ProfcollectdBinderService { fn get_supported_provider(&self) -> BinderResult<String> { Ok(self.lock().scheduler.get_trace_provider_name().to_string()) } + + fn registerProviderStatusCallback( + &self, + cb: &binder::Strong<(dyn IProviderStatusCallback)>, + ) -> BinderResult<()> { + if self.lock().scheduler.is_provider_ready() { + if let Err(e) = cb.onProviderReady() { + log::error!("Failed to call ProviderStatusCallback {:?}", e); + } + return Ok(()); + } + + let cb_binder: SpIBinder = cb.as_binder(); + self.lock().scheduler.register_provider_ready_callback(Box::new(move || { + if let Ok(cb) = cb_binder.into_interface::<dyn IProviderStatusCallback>() { + if let Err(e) = cb.onProviderReady() { + log::error!("Failed to call ProviderStatusCallback {:?}", e) + } + } else { + log::error!("SpIBinder is not a IProviderStatusCallback."); + } + })); + Ok(()) + } } impl ProfcollectdBinderService { diff --git a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs index 14fb7509..f25f5ffc 100644 --- a/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs +++ b/profcollectd/libprofcollectd/simpleperf_etm_trace_provider.rs @@ -34,6 +34,10 @@ impl TraceProvider for SimpleperfEtmTraceProvider { "simpleperf_etm" } + fn is_ready(&self) -> bool { + simpleperf_profcollect::has_device_support() + } + fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration) { let trace_file = trace_provider::get_path(trace_dir, tag, ETM_TRACEFILE_EXTENSION); @@ -76,6 +80,6 @@ impl TraceProvider for SimpleperfEtmTraceProvider { impl SimpleperfEtmTraceProvider { pub fn supported() -> bool { - simpleperf_profcollect::has_support() + simpleperf_profcollect::has_driver_support() } } diff --git a/profcollectd/libprofcollectd/trace_provider.rs b/profcollectd/libprofcollectd/trace_provider.rs index 98cd5ec4..13059199 100644 --- a/profcollectd/libprofcollectd/trace_provider.rs +++ b/profcollectd/libprofcollectd/trace_provider.rs @@ -29,6 +29,7 @@ use crate::logging_trace_provider::LoggingTraceProvider; pub trait TraceProvider { fn get_name(&self) -> &'static str; + fn is_ready(&self) -> bool; fn trace(&self, trace_dir: &Path, tag: &str, sampling_period: &Duration); fn process(&self, trace_dir: &Path, profile_dir: &Path, binary_filter: &str) -> Result<()>; } |