use crate::module::{handle_updated_modules, prune_modules}; use crate::{ assets, defs, ksucalls, 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); #[cfg(unix)] let _ = catch_bootlog("logcat", vec!["logcat"]); #[cfg(unix)] let _ = catch_bootlog("dmesg", vec!["dmesg", "-w"]); if utils::has_magisk() { warn!("Magisk detected, skip post-fs-data!"); return Ok(()); } let safe_mode = utils::is_safe_mode(); if 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); } } assets::ensure_binaries(true).with_context(|| "Failed to extract bin assets")?; // tell kernel that we've mount the module, so that it can do some optimization ksucalls::report_module_mounted(); // 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) = prune_modules() { warn!("prune modules failed: {}", e); } if let Err(e) = handle_updated_modules() { warn!("handle updated 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); } // 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); } // mount module systemlessly by magic mount if let Err(e) = mount_modules_systemlessly() { warn!("do systemless mount failed: {}", e); } run_stage("post-mount", true); Ok(()) } #[cfg(target_os = "android")] pub fn mount_modules_systemlessly() -> Result<()> { crate::magic_mount::magic_mount() } #[cfg(not(target_os = "android"))] pub fn mount_modules_systemlessly() -> Result<()> { 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}"); } if let Err(e) = crate::module::exec_stage_script(stage, block) { warn!("Failed to exec {stage} scripts: {e}"); } } pub fn on_services() -> Result<()> { info!("on_services triggered!"); run_stage("service", false); Ok(()) } pub fn on_boot_completed() -> Result<()> { ksucalls::report_boot_complete(); info!("on_boot_completed triggered!"); run_stage("boot-completed", false); Ok(()) } #[cfg(unix)] fn catch_bootlog(logname: &str, command: Vec<&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(()) }