Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ffdc620 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "libprefetch: Start prefetch service based on build" into main

parents e3db2085 ef3a2c05
Loading
Loading
Loading
Loading
+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
@@ -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
+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(())
}
+4 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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(())
}
+37 −0
Original line number Diff line number Diff line
@@ -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 {
@@ -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.
+16 −22
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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> {
@@ -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();
@@ -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