Merge "libprefetch: Start prefetch service based on build" into main am: 3ffdc6206a am: 36252ab703
Original change: https://android-review.googlesource.com/c/platform/system/core/+/3368783
Change-Id: I91d8cfc9ee0a073d547e2faeedd1b835d320abf7
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/init/libprefetch/prefetch/prefetch.rc b/init/libprefetch/prefetch/prefetch.rc
index 9f2cb7f..fb3fb3b 100644
--- a/init/libprefetch/prefetch/prefetch.rc
+++ b/init/libprefetch/prefetch/prefetch.rc
@@ -1,3 +1,16 @@
+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
@@ -5,6 +18,9 @@
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
diff --git a/init/libprefetch/prefetch/src/arch/android.rs b/init/libprefetch/prefetch/src/arch/android.rs
new file mode 100644
index 0000000..c765e38
--- /dev/null
+++ b/init/libprefetch/prefetch/src/arch/android.rs
@@ -0,0 +1,118 @@
+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(())
+}
diff --git a/init/libprefetch/prefetch/src/args.rs b/init/libprefetch/prefetch/src/args.rs
index 4c1e689..e534210 100644
--- a/init/libprefetch/prefetch/src/args.rs
+++ b/init/libprefetch/prefetch/src/args.rs
@@ -25,6 +25,8 @@
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;
@@ -66,6 +68,8 @@
SubCommands::Dump(arg) => {
ensure_path_exists(&arg.path)?;
}
+ #[cfg(target_os = "android")]
+ SubCommands::Start(_arg) => return Ok(()),
}
Ok(())
}
diff --git a/init/libprefetch/prefetch/src/args/args_argh.rs b/init/libprefetch/prefetch/src/args/args_argh.rs
index 8ac95fc..65084ee 100644
--- a/init/libprefetch/prefetch/src/args/args_argh.rs
+++ b/init/libprefetch/prefetch/src/args/args_argh.rs
@@ -40,6 +40,38 @@
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 {
@@ -110,6 +142,11 @@
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.
diff --git a/init/libprefetch/prefetch/src/lib.rs b/init/libprefetch/prefetch/src/lib.rs
index 4b56b13..6564c4b 100644
--- a/init/libprefetch/prefetch/src/lib.rs
+++ b/init/libprefetch/prefetch/src/lib.rs
@@ -20,6 +20,10 @@
mod format;
mod replay;
mod tracer;
+#[cfg(target_os = "android")]
+mod arch {
+ pub mod android;
+}
use std::fs::File;
use std::fs::OpenOptions;
@@ -38,6 +42,8 @@
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;
@@ -45,29 +51,11 @@
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> {
@@ -85,11 +73,10 @@
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();
@@ -107,9 +94,16 @@
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(())
}
diff --git a/init/libprefetch/prefetch/src/main.rs b/init/libprefetch/prefetch/src/main.rs
index 046e07e..eab826f 100644
--- a/init/libprefetch/prefetch/src/main.rs
+++ b/init/libprefetch/prefetch/src/main.rs
@@ -22,6 +22,8 @@
use prefetch_rs::init_logging;
use prefetch_rs::record;
use prefetch_rs::replay;
+#[cfg(target_os = "android")]
+use prefetch_rs::start_prefetch;
use prefetch_rs::LogLevel;
use prefetch_rs::MainArgs;
use prefetch_rs::SubCommands;
@@ -33,6 +35,8 @@
SubCommands::Record(args) => record(args),
SubCommands::Replay(args) => replay(args),
SubCommands::Dump(args) => dump(args),
+ #[cfg(target_os = "android")]
+ SubCommands::Start(args) => start_prefetch(args),
};
if let Err(err) = ret {