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

Commit ab808938 authored by Soichiro Fujii's avatar Soichiro Fujii Committed by Automerger Merge Worker
Browse files

Merge changes Idb791187,Iad926450 into main am: dcf5858c

parents b9578b5c dcf5858c
Loading
Loading
Loading
Loading
+25 −17
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:prefetch_boot.record=true
    start prefetch_record
# Reads data from disk in advance and populates page cache
# to speed up subsequent disk access.
#
# Record:
#   start by `start prefetch_record` at appropriate timing.
#   stop by setting `prefetch_boot.record_stop` to 1.
#   set --duration to only capture for a certain duration instead.
#
# Replay:
#   start by `start prefetch_replay` at appropriate timing.
#   it will depend on several files generated from record.
#
#   replay is I/O intensive. make sure you pick appropriate
#   timing to run each, so that you can maximize the page cache
#   hit for subsequent disk access.
#
# Example:
#   on early-init && property:ro.prefetch_boot.enabled=true
#     start prefetch_replay
#
#   on init && property:ro.prefetch_boot.enabled=true
#     start prefetch_record
#
#   on property:sys.boot_completed=1 && property:ro.prefetch_boot.enabled=true
#     setprop prefetch_boot.record_stop 1

service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boot.duration_s:-0}
    class main
    user root
    group root system
    disabled
    oneshot

on property: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
    group root system
    disabled
+30 −60
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::path::Path;
use std::time::Duration;

use rustutils::system_properties::error::PropertyWatcherError;
use rustutils::system_properties::PropertyWatcher;

const PREFETCH_RECORD_PROPERTY: &str = "prefetch_boot.record";
const PREFETCH_REPLAY_PROPERTY: &str = "prefetch_boot.replay";
const PREFETCH_RECORD_PROPERTY_STOP: &str = "prefetch_boot.record_stop";

fn wait_for_property_true(
@@ -31,68 +28,41 @@ pub fn wait_for_record_stop() {
    });
}

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(())
/// Checks if we can perform replay phase.
/// Ensure that the pack file exists and is up-to-date, returns false otherwise.
pub fn can_perform_replay(pack_path: &Path, fingerprint_path: &Path) -> Result<bool, Error> {
    if !pack_path.exists() || !fingerprint_path.exists() {
        return Ok(false);
    }

/// 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(());
    }
    let saved_fingerprint = std::fs::read_to_string(fingerprint_path)?;

    if args.build_fingerprint_path.exists() {
        let device_build_fingerprint = rustutils::system_properties::read("ro.build.fingerprint")
    let current_device_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)?;

    Ok(current_device_fingerprint.is_some_and(|fp| fp == saved_fingerprint.trim()))
}
    } else {
        info!("Start record");
        start_prefetch_service(PREFETCH_RECORD_PROPERTY)?;

/// Checks if we can perform record phase.
/// Ensure that following conditions hold:
///   - File specified in ready_path exists. otherwise, create a new file and return false.
///   - can_perform_replay is false.
pub fn ensure_record_is_ready(
    ready_path: &Path,
    pack_path: &Path,
    fingerprint_path: &Path,
) -> Result<bool, Error> {
    if !ready_path.exists() {
        File::create(ready_path)
            .map_err(|_| Error::Custom { error: "File Creation failed".to_string() })?;

        return Ok(false);
    }
    Ok(())

    let can_replay = can_perform_replay(pack_path, fingerprint_path)?;
    Ok(!can_replay)
}

/// Write build finger print to associate prefetch pack file
+0 −4
Original line number Diff line number Diff line
@@ -25,8 +25,6 @@ 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;
@@ -68,8 +66,6 @@ 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(())
}
+12 −22
Original line number Diff line number Diff line
@@ -40,12 +40,6 @@ 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")]
@@ -58,22 +52,6 @@ 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 {
    fn default() -> Self {
        Self::Dump(DumpArgs::default())
@@ -147,6 +125,13 @@ pub struct RecordArgs {
    /// store build_finger_print to tie the pack format
    #[argh(option, default = "default_build_finger_print_path()")]
    pub build_fingerprint_path: PathBuf,

    #[cfg(target_os = "android")]
    /// 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 ready_path: PathBuf,
}

/// Type of tracing subsystem to use.
@@ -204,6 +189,11 @@ pub struct ReplayArgs {
    /// file path from where the prefetch config file will be read
    #[argh(option, default = "PathBuf::new()")]
    pub config_path: PathBuf,

    #[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,
}

/// dump records file in given format
+14 −2
Original line number Diff line number Diff line
@@ -42,8 +42,6 @@ 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;
@@ -59,6 +57,13 @@ pub use arch::android::*;

/// Records prefetch data for the given configuration
pub fn record(args: &RecordArgs) -> Result<(), Error> {
    #[cfg(target_os = "android")]
    if !ensure_record_is_ready(&args.ready_path, &args.path, &args.build_fingerprint_path)? {
        info!("Cannot perform record -- skipping");
        return Ok(());
    }

    info!("Starting record.");
    let (mut tracer, exit_tx) = tracer::Tracer::create(
        args.trace_buffer_size_kib,
        args.tracing_subsystem.clone(),
@@ -109,6 +114,13 @@ pub fn record(args: &RecordArgs) -> Result<(), Error> {

/// Replays prefetch data for the given configuration
pub fn replay(args: &ReplayArgs) -> Result<(), Error> {
    #[cfg(target_os = "android")]
    if !can_perform_replay(&args.path, &args.build_fingerprint_path)? {
        info!("Cannot perform replay -- exiting.");
        return Ok(());
    }

    info!("Starting replay.");
    let replay = Replay::new(args)?;
    replay.replay()
}
Loading