implement magic mount

This commit is contained in:
5ec1cff
2024-11-21 17:07:13 +08:00
parent 1ef751eb06
commit a5edae9fac
10 changed files with 534 additions and 1044 deletions

View File

@@ -1,100 +1,11 @@
use anyhow::{Context, Result, bail};
use log::{info, warn};
use std::{collections::HashMap, path::Path};
use crate::module::prune_modules;
use crate::module::{handle_updated_modules, prune_modules};
use crate::{
assets, defs, ksucalls, mount, restorecon,
utils::{self, ensure_clean_dir},
assets, defs, ksucalls, restorecon,
utils::self,
};
fn mount_partition(partition_name: &str, lowerdir: &Vec<String>) -> Result<()> {
if lowerdir.is_empty() {
warn!("partition: {partition_name} lowerdir is empty");
return Ok(());
}
let partition = format!("/{partition_name}");
// if /partition is a symlink and linked to /system/partition, then we don't need to overlay it separately
if Path::new(&partition).read_link().is_ok() {
warn!("partition: {partition} is a symlink");
return Ok(());
}
let mut workdir = None;
let mut upperdir = None;
let system_rw_dir = Path::new(defs::SYSTEM_RW_DIR);
if system_rw_dir.exists() {
workdir = Some(system_rw_dir.join(partition_name).join("workdir"));
upperdir = Some(system_rw_dir.join(partition_name).join("upperdir"));
}
mount::mount_overlay(&partition, lowerdir, workdir, upperdir)
}
pub fn mount_modules_systemlessly(module_dir: &str) -> Result<()> {
// construct overlay mount params
let dir = std::fs::read_dir(module_dir);
let Ok(dir) = dir else {
bail!("open {} failed", defs::MODULE_DIR);
};
let mut system_lowerdir: Vec<String> = Vec::new();
let partition = vec!["vendor", "product", "system_ext", "odm", "oem"];
let mut partition_lowerdir: HashMap<String, Vec<String>> = HashMap::new();
for ele in &partition {
partition_lowerdir.insert((*ele).to_string(), Vec::new());
}
for entry in dir.flatten() {
let module = entry.path();
if !module.is_dir() {
continue;
}
let disabled = module.join(defs::DISABLE_FILE_NAME).exists();
if disabled {
info!("module: {} is disabled, ignore!", module.display());
continue;
}
let skip_mount = module.join(defs::SKIP_MOUNT_FILE_NAME).exists();
if skip_mount {
info!("module: {} skip_mount exist, skip!", module.display());
continue;
}
let module_system = Path::new(&module).join("system");
if module_system.is_dir() {
system_lowerdir.push(format!("{}", module_system.display()));
}
for part in &partition {
// if /partition is a mountpoint, we would move it to $MODPATH/$partition when install
// otherwise it must be a symlink and we don't need to overlay!
let part_path = Path::new(&module).join(part);
if part_path.is_dir() {
if let Some(v) = partition_lowerdir.get_mut(*part) {
v.push(format!("{}", part_path.display()));
}
}
}
}
// mount /system first
if let Err(e) = mount_partition("system", &system_lowerdir) {
warn!("mount system failed: {:#}", e);
}
// mount other partitions
for (k, v) in partition_lowerdir {
if let Err(e) = mount_partition(&k, &v) {
warn!("mount {k} failed: {:#}", e);
}
}
Ok(())
}
use anyhow::{Context, Result};
use log::{info, warn};
use std::path::Path;
pub fn on_post_data_fs() -> Result<()> {
ksucalls::report_post_fs_data();
@@ -111,11 +22,9 @@ pub fn on_post_data_fs() -> Result<()> {
return Ok(());
}
let safe_mode = crate::utils::is_safe_mode();
let safe_mode = utils::is_safe_mode();
if safe_mode {
// we should still mount modules.img to `/data/adb/modules` in safe mode
// becuase 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
@@ -124,43 +33,8 @@ pub fn on_post_data_fs() -> Result<()> {
}
}
let module_update_img = defs::MODULE_UPDATE_IMG;
let module_img = defs::MODULE_IMG;
let module_dir = defs::MODULE_DIR;
let module_update_flag = Path::new(defs::WORKING_DIR).join(defs::UPDATE_FILE_NAME);
// modules.img is the default image
let mut target_update_img = &module_img;
// we should clean the module mount point if it exists
ensure_clean_dir(module_dir)?;
assets::ensure_binaries(true).with_context(|| "Failed to extract bin assets")?;
if Path::new(module_update_img).exists() {
if module_update_flag.exists() {
// if modules_update.img exists, and the the flag indicate this is an update
// this make sure that if the update failed, we will fallback to the old image
// if we boot succeed, we will rename the modules_update.img to modules.img #on_boot_complete
target_update_img = &module_update_img;
// And we should delete the flag immediately
std::fs::remove_file(module_update_flag)?;
} else {
// if modules_update.img exists, but the flag not exist, we should delete it
std::fs::remove_file(module_update_img)?;
}
}
if !Path::new(target_update_img).exists() {
return Ok(());
}
// we should always mount the module.img to module dir
// becuase we may need to operate the module dir in safe mode
info!("mount module image: {target_update_img} to {module_dir}");
mount::AutoMountExt4::try_new(target_update_img, module_dir, false)
.with_context(|| "mount module image failed".to_string())?;
// tell kernel that we've mount the module, so that it can do some optimization
ksucalls::report_module_mounted();
@@ -177,6 +51,10 @@ pub fn on_post_data_fs() -> Result<()> {
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);
}
@@ -190,11 +68,6 @@ pub fn on_post_data_fs() -> Result<()> {
warn!("apply root profile sepolicy failed: {}", e);
}
// mount temp dir
if let Err(e) = mount::mount_tmpfs(defs::TEMP_DIR) {
warn!("do temp dir mount failed: {}", e);
}
// exec modules post-fs-data scripts
// TODO: Add timeout
if let Err(e) = crate::module::exec_stage_script("post-fs-data", true) {
@@ -206,15 +79,23 @@ pub fn on_post_data_fs() -> Result<()> {
warn!("load system.prop failed: {}", e);
}
// mount module systemlessly by overlay
if let Err(e) = mount_modules_systemlessly(module_dir) {
// mount module systemlessly by magic mount
if let Err(e) = mount_modules_systemlessly() {
warn!("do systemless mount failed: {}", e);
}
run_stage("post-mount", true);
std::env::set_current_dir("/").with_context(|| "failed to chdir to /")?;
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(())
}
@@ -249,17 +130,6 @@ pub fn on_services() -> Result<()> {
pub fn on_boot_completed() -> Result<()> {
ksucalls::report_boot_complete();
info!("on_boot_completed triggered!");
let module_update_img = Path::new(defs::MODULE_UPDATE_IMG);
let module_img = Path::new(defs::MODULE_IMG);
if module_update_img.exists() {
// this is a update and we successfully booted
if std::fs::rename(module_update_img, module_img).is_err() {
warn!("Failed to rename images, copy it now.",);
utils::copy_sparse_file(module_update_img, module_img, false)
.with_context(|| "Failed to copy images")?;
std::fs::remove_file(module_update_img).with_context(|| "Failed to remove image!")?;
}
}
run_stage("boot-completed", false);