Loading init/libprefetch/prefetch/prefetch.rc +16 −0 Original line number Diff line number Diff line on init && property:ro.prefetch_boot.enabled=true start prefetch service prefetch /system/bin/prefetch start class main user root group root system disabled oneshot on property:ro.prefetch_boot.record=true start prefetch_record service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boot.duration_s:-0} class main user root Loading @@ -5,6 +18,9 @@ service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boo disabled oneshot on property:ro.prefetch_boot.replay=true start prefetch_replay service prefetch_replay /system/bin/prefetch replay --io-depth ${ro.prefetch_boot.io_depth:-2} --max-fds ${ro.prefetch_boot.max_fds:-128} class main user root Loading init/libprefetch/prefetch/src/arch/android.rs 0 → 100644 +118 −0 Original line number Diff line number Diff line use crate::Error; use crate::RecordArgs; use crate::StartArgs; use log::info; use log::warn; use std::fs::File; use std::fs::OpenOptions; use std::io::Write; use std::time::Duration; use rustutils::system_properties::error::PropertyWatcherError; use rustutils::system_properties::PropertyWatcher; const PREFETCH_RECORD_PROPERTY: &str = "ro.prefetch_boot.record"; const PREFETCH_REPLAY_PROPERTY: &str = "ro.prefetch_boot.replay"; const PREFETCH_RECORD_PROPERTY_STOP: &str = "ro.prefetch_boot.record_stop"; fn wait_for_property_true( property_name: &str, timeout: Option<Duration>, ) -> Result<(), PropertyWatcherError> { let mut prop = PropertyWatcher::new(property_name)?; prop.wait_for_value("1", timeout)?; Ok(()) } /// Wait for record to stop pub fn wait_for_record_stop() { wait_for_property_true(PREFETCH_RECORD_PROPERTY_STOP, None).unwrap_or_else(|e| { warn!("failed to wait for {} with error: {}", PREFETCH_RECORD_PROPERTY_STOP, e) }); } fn start_prefetch_service(property_name: &str) -> Result<(), Error> { match rustutils::system_properties::write(property_name, "true") { Ok(_) => {} Err(_) => { return Err(Error::Custom { error: "Failed to start prefetch service".to_string() }); } } Ok(()) } /// Start prefetch service /// /// 1: Check the presence of the file 'prefetch_ready'. If it doesn't /// exist then the device is booting for the first time after wipe. /// Thus, we would just create the file and exit as we do not want /// to initiate the record after data wipe primiarly because boot /// after data wipe is long and the I/O pattern during first boot may not actually match /// with subsequent boot. /// /// 2: If the file 'prefetch_ready' is present: /// /// a: Compare the build-finger-print of the device with the one record format /// is associated with by reading the file 'build_finger_print'. If they match, /// start the prefetch_replay. /// /// b: If they don't match, then the device was updated through OTA. Hence, start /// a fresh record and delete the build-finger-print file. This should also cover /// the case of device rollback. /// /// c: If the build-finger-print file doesn't exist, then just restart the record /// from scratch. pub fn start_prefetch(args: &StartArgs) -> Result<(), Error> { if !args.path.exists() { match File::create(args.path.clone()) { Ok(_) => {} Err(_) => { return Err(Error::Custom { error: "File Creation failed".to_string() }); } } return Ok(()); } if args.build_fingerprint_path.exists() { let device_build_fingerprint = rustutils::system_properties::read("ro.build.fingerprint") .map_err(|e| Error::Custom { error: format!("Failed to read ro.build.fingerprint: {}", e), })?; let pack_build_fingerprint = std::fs::read_to_string(&args.build_fingerprint_path)?; if pack_build_fingerprint.trim() == device_build_fingerprint.as_deref().unwrap_or_default() { info!("Start replay"); start_prefetch_service(PREFETCH_REPLAY_PROPERTY)?; } else { info!("Start record"); std::fs::remove_file(&args.build_fingerprint_path)?; start_prefetch_service(PREFETCH_RECORD_PROPERTY)?; } } else { info!("Start record"); start_prefetch_service(PREFETCH_RECORD_PROPERTY)?; } Ok(()) } /// Write build finger print to associate prefetch pack file pub fn write_build_fingerprint(args: &RecordArgs) -> Result<(), Error> { let mut build_fingerprint_file = OpenOptions::new() .write(true) .create(true) .truncate(true) .open(&args.build_fingerprint_path) .map_err(|source| Error::Create { source, path: args.build_fingerprint_path.to_str().unwrap().to_owned(), })?; let device_build_fingerprint = rustutils::system_properties::read("ro.build.fingerprint").unwrap_or_default(); let device_build_fingerprint = device_build_fingerprint.unwrap_or_default(); build_fingerprint_file.write_all(device_build_fingerprint.as_bytes())?; build_fingerprint_file.sync_all()?; Ok(()) } init/libprefetch/prefetch/src/args.rs +4 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ use std::process::exit; pub use args_internal::OutputFormat; pub use args_internal::ReplayArgs; #[cfg(target_os = "android")] pub use args_internal::StartArgs; pub use args_internal::TracerType; pub use args_internal::{DumpArgs, MainArgs, RecordArgs, SubCommands}; use serde::Deserialize; Loading Loading @@ -66,6 +68,8 @@ fn verify_and_fix(args: &mut MainArgs) -> Result<(), Error> { SubCommands::Dump(arg) => { ensure_path_exists(&arg.path)?; } #[cfg(target_os = "android")] SubCommands::Start(_arg) => return Ok(()), } Ok(()) } Loading init/libprefetch/prefetch/src/args/args_argh.rs +37 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,38 @@ pub enum SubCommands { Replay(ReplayArgs), /// Dump prefetch data in human readable format Dump(DumpArgs), /// Start prefetch service if possible /// If the pack file is present, then prefetch replay is started /// If the pack file is absent or if the build fingerprint /// of the current pack file is different, then prefetch record is started. #[cfg(target_os = "android")] Start(StartArgs), } #[cfg(target_os = "android")] fn default_ready_path() -> PathBuf { PathBuf::from("/metadata/prefetch/prefetch_ready") } #[cfg(target_os = "android")] fn default_build_finger_print_path() -> PathBuf { PathBuf::from("/metadata/prefetch/build_finger_print") } #[cfg(target_os = "android")] #[derive(Eq, PartialEq, Debug, Default, FromArgs)] /// Start prefetch service based on if pack file is present. #[argh(subcommand, name = "start")] pub struct StartArgs { /// file path to check if prefetch_ready is present. /// /// A new file is created at the given path if it's not present. #[argh(option, default = "default_ready_path()")] pub path: PathBuf, /// file path where build fingerprint is stored #[argh(option, default = "default_build_finger_print_path()")] pub build_fingerprint_path: PathBuf, } impl Default for SubCommands { Loading Loading @@ -110,6 +142,11 @@ pub struct RecordArgs { from_str_fn(parse_tracing_instance) )] pub tracing_instance: Option<String>, #[cfg(target_os = "android")] /// store build_finger_print to tie the pack format #[argh(option, default = "default_build_finger_print_path()")] pub build_fingerprint_path: PathBuf, } /// Type of tracing subsystem to use. Loading init/libprefetch/prefetch/src/lib.rs +16 −22 Original line number Diff line number Diff line Loading @@ -20,6 +20,10 @@ mod error; mod format; mod replay; mod tracer; #[cfg(target_os = "android")] mod arch { pub mod android; } use std::fs::File; use std::fs::OpenOptions; Loading @@ -38,6 +42,8 @@ use log::LevelFilter; pub use args::args_from_env; use args::OutputFormat; pub use args::ReplayArgs; #[cfg(target_os = "android")] pub use args::StartArgs; pub use args::{DumpArgs, MainArgs, RecordArgs, SubCommands}; pub use error::Error; pub use format::FileId; Loading @@ -45,29 +51,11 @@ pub use format::InodeInfo; pub use format::Record; pub use format::RecordsFile; use log::info; #[cfg(target_os = "android")] use log::warn; pub use replay::Replay; pub use tracer::nanoseconds_since_boot; #[cfg(target_os = "android")] use rustutils::system_properties; #[cfg(target_os = "android")] use rustutils::system_properties::error::PropertyWatcherError; #[cfg(target_os = "android")] use rustutils::system_properties::PropertyWatcher; #[cfg(target_os = "android")] fn wait_for_property_true(property_name: &str) -> Result<(), PropertyWatcherError> { let mut prop = PropertyWatcher::new(property_name)?; loop { prop.wait(None)?; if system_properties::read_bool(property_name, false)? { break; } } Ok(()) } pub use arch::android::*; /// Records prefetch data for the given configuration pub fn record(args: &RecordArgs) -> Result<(), Error> { Loading @@ -85,11 +73,10 @@ pub fn record(args: &RecordArgs) -> Result<(), Error> { thread::sleep(duration); } else { #[cfg(target_os = "android")] wait_for_property_true("sys.boot_completed").unwrap_or_else(|e| { warn!("failed to wait for sys.boot_completed with error: {}", e) }); wait_for_record_stop(); } info!("Prefetch record exiting"); // We want to unwrap here on failure to send this signal. Otherwise // tracer will continue generating huge records data. exit_tx.send(()).unwrap(); Loading @@ -107,9 +94,16 @@ pub fn record(args: &RecordArgs) -> Result<(), Error> { std::fs::set_permissions(&args.path, std::fs::Permissions::from_mode(0o644)) .map_err(|source| Error::Create { source, path: args.path.to_str().unwrap().to_owned() })?; // Write the record file out_file .write_all(&rf.add_checksum_and_serialize()?) .map_err(|source| Error::Write { path: args.path.to_str().unwrap().to_owned(), source })?; out_file.sync_all()?; // Write build-finger-print file #[cfg(target_os = "android")] write_build_fingerprint(args)?; Ok(()) } Loading Loading
init/libprefetch/prefetch/prefetch.rc +16 −0 Original line number Diff line number Diff line on init && property:ro.prefetch_boot.enabled=true start prefetch service prefetch /system/bin/prefetch start class main user root group root system disabled oneshot on property:ro.prefetch_boot.record=true start prefetch_record service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boot.duration_s:-0} class main user root Loading @@ -5,6 +18,9 @@ service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boo disabled oneshot on property:ro.prefetch_boot.replay=true start prefetch_replay service prefetch_replay /system/bin/prefetch replay --io-depth ${ro.prefetch_boot.io_depth:-2} --max-fds ${ro.prefetch_boot.max_fds:-128} class main user root Loading
init/libprefetch/prefetch/src/arch/android.rs 0 → 100644 +118 −0 Original line number Diff line number Diff line use crate::Error; use crate::RecordArgs; use crate::StartArgs; use log::info; use log::warn; use std::fs::File; use std::fs::OpenOptions; use std::io::Write; use std::time::Duration; use rustutils::system_properties::error::PropertyWatcherError; use rustutils::system_properties::PropertyWatcher; const PREFETCH_RECORD_PROPERTY: &str = "ro.prefetch_boot.record"; const PREFETCH_REPLAY_PROPERTY: &str = "ro.prefetch_boot.replay"; const PREFETCH_RECORD_PROPERTY_STOP: &str = "ro.prefetch_boot.record_stop"; fn wait_for_property_true( property_name: &str, timeout: Option<Duration>, ) -> Result<(), PropertyWatcherError> { let mut prop = PropertyWatcher::new(property_name)?; prop.wait_for_value("1", timeout)?; Ok(()) } /// Wait for record to stop pub fn wait_for_record_stop() { wait_for_property_true(PREFETCH_RECORD_PROPERTY_STOP, None).unwrap_or_else(|e| { warn!("failed to wait for {} with error: {}", PREFETCH_RECORD_PROPERTY_STOP, e) }); } fn start_prefetch_service(property_name: &str) -> Result<(), Error> { match rustutils::system_properties::write(property_name, "true") { Ok(_) => {} Err(_) => { return Err(Error::Custom { error: "Failed to start prefetch service".to_string() }); } } Ok(()) } /// Start prefetch service /// /// 1: Check the presence of the file 'prefetch_ready'. If it doesn't /// exist then the device is booting for the first time after wipe. /// Thus, we would just create the file and exit as we do not want /// to initiate the record after data wipe primiarly because boot /// after data wipe is long and the I/O pattern during first boot may not actually match /// with subsequent boot. /// /// 2: If the file 'prefetch_ready' is present: /// /// a: Compare the build-finger-print of the device with the one record format /// is associated with by reading the file 'build_finger_print'. If they match, /// start the prefetch_replay. /// /// b: If they don't match, then the device was updated through OTA. Hence, start /// a fresh record and delete the build-finger-print file. This should also cover /// the case of device rollback. /// /// c: If the build-finger-print file doesn't exist, then just restart the record /// from scratch. pub fn start_prefetch(args: &StartArgs) -> Result<(), Error> { if !args.path.exists() { match File::create(args.path.clone()) { Ok(_) => {} Err(_) => { return Err(Error::Custom { error: "File Creation failed".to_string() }); } } return Ok(()); } if args.build_fingerprint_path.exists() { let device_build_fingerprint = rustutils::system_properties::read("ro.build.fingerprint") .map_err(|e| Error::Custom { error: format!("Failed to read ro.build.fingerprint: {}", e), })?; let pack_build_fingerprint = std::fs::read_to_string(&args.build_fingerprint_path)?; if pack_build_fingerprint.trim() == device_build_fingerprint.as_deref().unwrap_or_default() { info!("Start replay"); start_prefetch_service(PREFETCH_REPLAY_PROPERTY)?; } else { info!("Start record"); std::fs::remove_file(&args.build_fingerprint_path)?; start_prefetch_service(PREFETCH_RECORD_PROPERTY)?; } } else { info!("Start record"); start_prefetch_service(PREFETCH_RECORD_PROPERTY)?; } Ok(()) } /// Write build finger print to associate prefetch pack file pub fn write_build_fingerprint(args: &RecordArgs) -> Result<(), Error> { let mut build_fingerprint_file = OpenOptions::new() .write(true) .create(true) .truncate(true) .open(&args.build_fingerprint_path) .map_err(|source| Error::Create { source, path: args.build_fingerprint_path.to_str().unwrap().to_owned(), })?; let device_build_fingerprint = rustutils::system_properties::read("ro.build.fingerprint").unwrap_or_default(); let device_build_fingerprint = device_build_fingerprint.unwrap_or_default(); build_fingerprint_file.write_all(device_build_fingerprint.as_bytes())?; build_fingerprint_file.sync_all()?; Ok(()) }
init/libprefetch/prefetch/src/args.rs +4 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ use std::process::exit; pub use args_internal::OutputFormat; pub use args_internal::ReplayArgs; #[cfg(target_os = "android")] pub use args_internal::StartArgs; pub use args_internal::TracerType; pub use args_internal::{DumpArgs, MainArgs, RecordArgs, SubCommands}; use serde::Deserialize; Loading Loading @@ -66,6 +68,8 @@ fn verify_and_fix(args: &mut MainArgs) -> Result<(), Error> { SubCommands::Dump(arg) => { ensure_path_exists(&arg.path)?; } #[cfg(target_os = "android")] SubCommands::Start(_arg) => return Ok(()), } Ok(()) } Loading
init/libprefetch/prefetch/src/args/args_argh.rs +37 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,38 @@ pub enum SubCommands { Replay(ReplayArgs), /// Dump prefetch data in human readable format Dump(DumpArgs), /// Start prefetch service if possible /// If the pack file is present, then prefetch replay is started /// If the pack file is absent or if the build fingerprint /// of the current pack file is different, then prefetch record is started. #[cfg(target_os = "android")] Start(StartArgs), } #[cfg(target_os = "android")] fn default_ready_path() -> PathBuf { PathBuf::from("/metadata/prefetch/prefetch_ready") } #[cfg(target_os = "android")] fn default_build_finger_print_path() -> PathBuf { PathBuf::from("/metadata/prefetch/build_finger_print") } #[cfg(target_os = "android")] #[derive(Eq, PartialEq, Debug, Default, FromArgs)] /// Start prefetch service based on if pack file is present. #[argh(subcommand, name = "start")] pub struct StartArgs { /// file path to check if prefetch_ready is present. /// /// A new file is created at the given path if it's not present. #[argh(option, default = "default_ready_path()")] pub path: PathBuf, /// file path where build fingerprint is stored #[argh(option, default = "default_build_finger_print_path()")] pub build_fingerprint_path: PathBuf, } impl Default for SubCommands { Loading Loading @@ -110,6 +142,11 @@ pub struct RecordArgs { from_str_fn(parse_tracing_instance) )] pub tracing_instance: Option<String>, #[cfg(target_os = "android")] /// store build_finger_print to tie the pack format #[argh(option, default = "default_build_finger_print_path()")] pub build_fingerprint_path: PathBuf, } /// Type of tracing subsystem to use. Loading
init/libprefetch/prefetch/src/lib.rs +16 −22 Original line number Diff line number Diff line Loading @@ -20,6 +20,10 @@ mod error; mod format; mod replay; mod tracer; #[cfg(target_os = "android")] mod arch { pub mod android; } use std::fs::File; use std::fs::OpenOptions; Loading @@ -38,6 +42,8 @@ use log::LevelFilter; pub use args::args_from_env; use args::OutputFormat; pub use args::ReplayArgs; #[cfg(target_os = "android")] pub use args::StartArgs; pub use args::{DumpArgs, MainArgs, RecordArgs, SubCommands}; pub use error::Error; pub use format::FileId; Loading @@ -45,29 +51,11 @@ pub use format::InodeInfo; pub use format::Record; pub use format::RecordsFile; use log::info; #[cfg(target_os = "android")] use log::warn; pub use replay::Replay; pub use tracer::nanoseconds_since_boot; #[cfg(target_os = "android")] use rustutils::system_properties; #[cfg(target_os = "android")] use rustutils::system_properties::error::PropertyWatcherError; #[cfg(target_os = "android")] use rustutils::system_properties::PropertyWatcher; #[cfg(target_os = "android")] fn wait_for_property_true(property_name: &str) -> Result<(), PropertyWatcherError> { let mut prop = PropertyWatcher::new(property_name)?; loop { prop.wait(None)?; if system_properties::read_bool(property_name, false)? { break; } } Ok(()) } pub use arch::android::*; /// Records prefetch data for the given configuration pub fn record(args: &RecordArgs) -> Result<(), Error> { Loading @@ -85,11 +73,10 @@ pub fn record(args: &RecordArgs) -> Result<(), Error> { thread::sleep(duration); } else { #[cfg(target_os = "android")] wait_for_property_true("sys.boot_completed").unwrap_or_else(|e| { warn!("failed to wait for sys.boot_completed with error: {}", e) }); wait_for_record_stop(); } info!("Prefetch record exiting"); // We want to unwrap here on failure to send this signal. Otherwise // tracer will continue generating huge records data. exit_tx.send(()).unwrap(); Loading @@ -107,9 +94,16 @@ pub fn record(args: &RecordArgs) -> Result<(), Error> { std::fs::set_permissions(&args.path, std::fs::Permissions::from_mode(0o644)) .map_err(|source| Error::Create { source, path: args.path.to_str().unwrap().to_owned() })?; // Write the record file out_file .write_all(&rf.add_checksum_and_serialize()?) .map_err(|source| Error::Write { path: args.path.to_str().unwrap().to_owned(), source })?; out_file.sync_all()?; // Write build-finger-print file #[cfg(target_os = "android")] write_build_fingerprint(args)?; Ok(()) } Loading