#[cfg(target_arch = "aarch64")] use crate::kpm; use crate::module::{handle_updated_modules, prune_modules}; use crate::utils::is_safe_mode; use crate::{ assets, defs, ksucalls, metamodule, restorecon, utils::{self}, }; use anyhow::{Context, Result}; use log::{info, warn}; use std::path::Path; pub fn on_post_data_fs() -> Result<()> { ksucalls::report_post_fs_data(); utils::umask(0); // Clear all temporary module configs early if let Err(e) = crate::module_config::clear_all_temp_configs() { warn!("clear temp configs failed: {e}"); } #[cfg(unix)] let _ = catch_bootlog("logcat", &["logcat"]); #[cfg(unix)] let _ = catch_bootlog("dmesg", &["dmesg", "-w"]); if utils::has_magisk() { warn!("Magisk detected, skip post-fs-data!"); return Ok(()); } let safe_mode = crate::utils::is_safe_mode(); if safe_mode { // we should still ensure module directory exists in safe mode // because we may need to operate the module dir in safe mode warn!("safe mode, skip common post-fs-data.d scripts"); } else { // Then exec common post-fs-data scripts if let Err(e) = crate::module::exec_common_scripts("post-fs-data.d", true) { warn!("exec common post-fs-data scripts failed: {e}"); } } let module_dir = defs::MODULE_DIR; assets::ensure_binaries(true).with_context(|| "Failed to extract bin assets")?; // Start UID scanner daemon with highest priority crate::uid_scanner::start_uid_scanner_daemon()?; if is_safe_mode() { warn!("safe mode, skip load feature config"); } else if let Err(e) = crate::umount_manager::load_and_apply_config() { warn!("Failed to load umount config: {e}"); } // if we are in safe mode, we should disable all modules if safe_mode { warn!("safe mode, skip post-fs-data scripts and disable all modules!"); if let Err(e) = crate::module::disable_all_modules() { warn!("disable all modules failed: {e}"); } return Ok(()); } if let Err(e) = handle_updated_modules() { warn!("handle updated modules failed: {e}"); } if let Err(e) = prune_modules() { warn!("prune modules failed: {e}"); } if let Err(e) = restorecon::restorecon() { warn!("restorecon failed: {e}"); } // load sepolicy.rule if crate::module::load_sepolicy_rule().is_err() { warn!("load sepolicy.rule failed"); } if let Err(e) = crate::profile::apply_sepolies() { warn!("apply root profile sepolicy failed: {e}"); } // load feature config if is_safe_mode() { warn!("safe mode, skip load feature config"); } else if let Err(e) = crate::feature::init_features() { warn!("init features failed: {e}"); } #[cfg(target_arch = "aarch64")] if let Err(e) = kpm::start_kpm_watcher() { warn!("KPM: Failed to start KPM watcher: {e}"); } #[cfg(target_arch = "aarch64")] if let Err(e) = kpm::load_kpm_modules() { warn!("KPM: Failed to load KPM modules: {e}"); } // execute metamodule post-fs-data script first (priority) if let Err(e) = metamodule::exec_stage_script("post-fs-data", true) { warn!("exec metamodule post-fs-data script failed: {e}"); } // exec modules post-fs-data scripts // TODO: Add timeout if let Err(e) = crate::module::exec_stage_script("post-fs-data", true) { warn!("exec post-fs-data scripts failed: {e}"); } // load system.prop if let Err(e) = crate::module::load_system_prop() { warn!("load system.prop failed: {e}"); } // execute metamodule mount script if let Err(e) = metamodule::exec_mount_script(module_dir) { warn!("execute metamodule mount failed: {e}"); } run_stage("post-mount", true); std::env::set_current_dir("/").with_context(|| "failed to chdir to /")?; Ok(()) } fn run_stage(stage: &str, block: bool) { utils::umask(0); if utils::has_magisk() { warn!("Magisk detected, skip {stage}"); return; } if crate::utils::is_safe_mode() { warn!("safe mode, skip {stage} scripts"); return; } if let Err(e) = crate::module::exec_common_scripts(&format!("{stage}.d"), block) { warn!("Failed to exec common {stage} scripts: {e}"); } // execute metamodule stage script first (priority) if let Err(e) = metamodule::exec_stage_script(stage, block) { warn!("Failed to exec metamodule {stage} script: {e}"); } // execute regular modules stage scripts if let Err(e) = crate::module::exec_stage_script(stage, block) { warn!("Failed to exec {stage} scripts: {e}"); } } pub fn on_services() { info!("on_services triggered!"); run_stage("service", false); } pub fn on_boot_completed() { ksucalls::report_boot_complete(); info!("on_boot_completed triggered!"); run_stage("boot-completed", false); } #[cfg(unix)] fn catch_bootlog(logname: &str, command: &[&str]) -> Result<()> { use std::os::unix::process::CommandExt; use std::process::Stdio; let logdir = Path::new(defs::LOG_DIR); utils::ensure_dir_exists(logdir)?; let bootlog = logdir.join(format!("{logname}.log")); let oldbootlog = logdir.join(format!("{logname}.old.log")); if bootlog.exists() { std::fs::rename(&bootlog, oldbootlog)?; } let bootlog = std::fs::File::create(bootlog)?; let mut args = vec!["-s", "9", "30s"]; args.extend_from_slice(command); // timeout -s 9 30s logcat > boot.log let result = unsafe { std::process::Command::new("timeout") .process_group(0) .pre_exec(|| { utils::switch_cgroups(); Ok(()) }) .args(args) .stdout(Stdio::from(bootlog)) .spawn() }; if let Err(e) = result { warn!("Failed to start logcat: {e:#}"); } Ok(()) }