opt: Optimize the kpm && uid_scanner (#549)

* opt: Optimize the structure of kpm.rs

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* opt: Optimize the uid_scanner startup logic in userspace && code style

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* opt: rename kpm's ioctl

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* opt: rename ksucalls::KsuKpmCmd's arg2..arg5

using
```rust
pub struct KsuKpmCmd {
    pub control_code: u64,
    pub arg1: u64,
    pub arg2: u64,
    pub result_code: u64,
}
```
This makes it easier to distinguish parameters.

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

---------

Signed-off-by: Tools-app <localhost.hutao@gmail.com>
This commit is contained in:
生于生时 亡于亡刻
2025-11-08 16:13:32 +08:00
committed by GitHub
parent 704f7cba32
commit ed6b2e0a8e
5 changed files with 98 additions and 75 deletions

View File

@@ -1,6 +1,3 @@
use crate::ksucalls;
use anyhow::{Result, anyhow, bail};
use notify::{RecursiveMode, Watcher};
use std::{ use std::{
ffi::{CStr, CString, OsStr}, ffi::{CStr, CString, OsStr},
fs, fs,
@@ -8,19 +5,24 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use anyhow::{Result, anyhow, bail};
use notify::{RecursiveMode, Watcher};
use crate::ksucalls;
pub const KPM_DIR: &str = "/data/adb/kpm"; pub const KPM_DIR: &str = "/data/adb/kpm";
const SUKISU_KPM_LOAD: u64 = 1; const KPM_LOAD: u64 = 1;
const SUKISU_KPM_UNLOAD: u64 = 2; const KPM_UNLOAD: u64 = 2;
const SUKISU_KPM_NUM: u64 = 3; const KPM_NUM: u64 = 3;
const SUKISU_KPM_LIST: u64 = 4; const KPM_LIST: u64 = 4;
const SUKISU_KPM_INFO: u64 = 5; const KPM_INFO: u64 = 5;
const SUKISU_KPM_CONTROL: u64 = 6; const KPM_CONTROL: u64 = 6;
const SUKISU_KPM_VERSION: u64 = 7; const KPM_VERSION: u64 = 7;
/// Convert raw kernel return code to `Result`. /// Convert raw kernel return code to `Result`.
#[inline(always)] #[inline(always)]
fn check_out(rc: i32) -> Result<i32> { fn check_ret(rc: i32) -> Result<i32> {
if rc < 0 { if rc < 0 {
bail!("KPM error: {}", std::io::Error::from_raw_os_error(-rc)); bail!("KPM error: {}", std::io::Error::from_raw_os_error(-rc));
} }
@@ -34,14 +36,14 @@ pub fn kpm_load(path: &str, args: Option<&str>) -> Result<()> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_LOAD, control_code: KPM_LOAD,
arg3: path_c.as_ptr() as u64, arg1: path_c.as_ptr() as u64,
arg4: args_c.as_ref().map_or(0, |s| s.as_ptr() as u64), arg2: args_c.as_ref().map_or(0, |s| s.as_ptr() as u64),
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
check_out(result)?; check_ret(result)?;
println!("Success"); println!("Success");
Ok(()) Ok(())
} }
@@ -52,14 +54,14 @@ pub fn kpm_unload(name: &str) -> Result<()> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_UNLOAD, control_code: KPM_UNLOAD,
arg3: name_c.as_ptr() as u64, arg1: name_c.as_ptr() as u64,
arg4: 0, arg2: 0,
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
check_out(result)?; check_ret(result)?;
Ok(()) Ok(())
} }
@@ -67,14 +69,14 @@ pub fn kpm_unload(name: &str) -> Result<()> {
pub fn kpm_num() -> Result<i32> { pub fn kpm_num() -> Result<i32> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_NUM, control_code: KPM_NUM,
arg3: 0, arg1: 0,
arg4: 0, arg2: 0,
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
let n = check_out(result)?; let n = check_ret(result)?;
println!("{n}"); println!("{n}");
Ok(n) Ok(n)
} }
@@ -85,14 +87,14 @@ pub fn kpm_list() -> Result<()> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_LIST, control_code: KPM_LIST,
arg3: buf.as_mut_ptr() as u64, arg1: buf.as_mut_ptr() as u64,
arg4: buf.len() as u64, arg2: buf.len() as u64,
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
check_out(result)?; check_ret(result)?;
print!("{}", buf2str(&buf)); print!("{}", buf2str(&buf));
Ok(()) Ok(())
} }
@@ -104,14 +106,14 @@ pub fn kpm_info(name: &str) -> Result<()> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_INFO, control_code: KPM_INFO,
arg3: name_c.as_ptr() as u64, arg1: name_c.as_ptr() as u64,
arg4: buf.as_mut_ptr() as u64, arg2: buf.as_mut_ptr() as u64,
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
check_out(result)?; check_ret(result)?;
println!("{}", buf2str(&buf)); println!("{}", buf2str(&buf));
Ok(()) Ok(())
} }
@@ -123,14 +125,14 @@ pub fn kpm_control(name: &str, args: &str) -> Result<i32> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_CONTROL, control_code: KPM_CONTROL,
arg3: name_c.as_ptr() as u64, arg1: name_c.as_ptr() as u64,
arg4: args_c.as_ptr() as u64, arg2: args_c.as_ptr() as u64,
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
check_out(result) check_ret(result)
} }
/// Print loader version string. /// Print loader version string.
@@ -139,14 +141,14 @@ pub fn kpm_version_loader() -> Result<()> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_VERSION, control_code: KPM_VERSION,
arg3: buf.as_mut_ptr() as u64, arg1: buf.as_mut_ptr() as u64,
arg4: buf.len() as u64, arg2: buf.len() as u64,
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
check_out(result)?; check_ret(result)?;
print!("{}", buf2str(&buf)); print!("{}", buf2str(&buf));
Ok(()) Ok(())
} }
@@ -157,14 +159,14 @@ pub fn check_kpm_version() -> Result<String> {
let mut result: i32 = -1; let mut result: i32 = -1;
let mut cmd = ksucalls::KsuKpmCmd { let mut cmd = ksucalls::KsuKpmCmd {
arg2: SUKISU_KPM_VERSION, control_code: KPM_VERSION,
arg3: buf.as_mut_ptr() as u64, arg1: buf.as_mut_ptr() as u64,
arg4: buf.len() as u64, arg2: buf.len() as u64,
arg5: &mut result as *mut i32 as u64, result_code: &mut result as *mut i32 as u64,
}; };
ksucalls::kpm_ioctl(&mut cmd)?; ksucalls::kpm_ioctl(&mut cmd)?;
check_out(result)?; check_ret(result)?;
let ver = buf2str(&buf); let ver = buf2str(&buf);
if ver.is_empty() { if ver.is_empty() {
bail!("KPM: invalid version response: {ver}"); bail!("KPM: invalid version response: {ver}");
@@ -177,6 +179,7 @@ pub fn check_kpm_version() -> Result<String> {
pub fn ensure_kpm_dir() -> Result<()> { pub fn ensure_kpm_dir() -> Result<()> {
fs::create_dir_all(KPM_DIR)?; fs::create_dir_all(KPM_DIR)?;
let meta = fs::metadata(KPM_DIR)?; let meta = fs::metadata(KPM_DIR)?;
if meta.permissions().mode() & 0o777 != 0o777 { if meta.permissions().mode() & 0o777 != 0o777 {
fs::set_permissions(KPM_DIR, fs::Permissions::from_mode(0o777))?; fs::set_permissions(KPM_DIR, fs::Permissions::from_mode(0o777))?;
} }
@@ -187,6 +190,7 @@ pub fn ensure_kpm_dir() -> Result<()> {
pub fn start_kpm_watcher() -> Result<()> { pub fn start_kpm_watcher() -> Result<()> {
check_kpm_version()?; // bails if loader too old check_kpm_version()?; // bails if loader too old
ensure_kpm_dir()?; ensure_kpm_dir()?;
if crate::utils::is_safe_mode() { if crate::utils::is_safe_mode() {
log::warn!("KPM: safe-mode removing all modules"); log::warn!("KPM: safe-mode removing all modules");
remove_all_kpms()?; remove_all_kpms()?;
@@ -205,7 +209,10 @@ pub fn start_kpm_watcher() -> Result<()> {
fn handle_kpm_event(evt: notify::Event) { fn handle_kpm_event(evt: notify::Event) {
if let notify::EventKind::Create(_) = evt.kind { if let notify::EventKind::Create(_) = evt.kind {
for p in evt.paths { for p in evt.paths {
if p.extension() == Some(OsStr::new("kpm")) && load_kpm(&p).is_err() { if let Some(ex) = p.extension()
&& ex == OsStr::new("kpm")
&& load_kpm(&p).is_err()
{
log::warn!("KPM: failed to load {}", p.display()); log::warn!("KPM: failed to load {}", p.display());
} }
} }
@@ -221,22 +228,30 @@ pub fn load_kpm(path: &Path) -> Result<()> {
/// Unload module and delete file. /// Unload module and delete file.
pub fn unload_kpm(name: &str) -> Result<()> { pub fn unload_kpm(name: &str) -> Result<()> {
kpm_unload(name)?; kpm_unload(name)?;
if let Some(p) = find_kpm_file(name)? { if let Some(p) = find_kpm_file(name)? {
let _ = fs::remove_file(&p); let _ = fs::remove_file(&p);
log::info!("KPM: deleted {}", p.display()); log::info!("KPM: deleted {}", p.display());
} }
Ok(()) Ok(())
} }
/// Locate `/data/adb/kpm/<name>.kpm`. /// Locate `/data/adb/kpm/<name>.kpm`.
fn find_kpm_file(name: &str) -> Result<Option<PathBuf>> { fn find_kpm_file(name: &str) -> Result<Option<PathBuf>> {
let dir = Path::new(KPM_DIR); let dir = Path::new(KPM_DIR);
if !dir.is_dir() { if !dir.is_dir() {
return Ok(None); return Ok(None);
} }
for entry in fs::read_dir(dir)? { for entry in fs::read_dir(dir)? {
let p = entry?.path(); let p = entry?.path();
if p.extension() == Some(OsStr::new("kpm")) && p.file_stem() == Some(OsStr::new(name)) { if let Some(ex) = p.extension()
&& ex == OsStr::new("kpm")
&& let Some(fs) = p.file_stem()
&& fs == OsStr::new(name)
{
return Ok(Some(p)); return Ok(Some(p));
} }
} }
@@ -251,7 +266,8 @@ pub fn remove_all_kpms() -> Result<()> {
} }
for entry in fs::read_dir(dir)? { for entry in fs::read_dir(dir)? {
let p = entry?.path(); let p = entry?.path();
if p.extension() == Some(OsStr::new("kpm")) if let Some(ex) = p.extension()
&& ex == OsStr::new("kpm")
&& let Some(name) = p.file_stem().and_then(|s| s.to_str()) && let Some(name) = p.file_stem().and_then(|s| s.to_str())
&& let Err(e) = unload_kpm(name) && let Err(e) = unload_kpm(name)
{ {
@@ -265,14 +281,19 @@ pub fn remove_all_kpms() -> Result<()> {
pub fn load_kpm_modules() -> Result<()> { pub fn load_kpm_modules() -> Result<()> {
check_kpm_version()?; check_kpm_version()?;
ensure_kpm_dir()?; ensure_kpm_dir()?;
let dir = Path::new(KPM_DIR); let dir = Path::new(KPM_DIR);
if !dir.is_dir() { if !dir.is_dir() {
return Ok(()); return Ok(());
} }
let (mut ok, mut ng) = (0, 0); let (mut ok, mut ng) = (0, 0);
for entry in fs::read_dir(dir)? { for entry in fs::read_dir(dir)? {
let p = entry?.path(); let p = entry?.path();
if p.extension() == Some(OsStr::new("kpm")) { if let Some(ex) = p.extension()
&& ex == OsStr::new("kpm")
{
match load_kpm(&p) { match load_kpm(&p) {
Ok(_) => ok += 1, Ok(_) => ok += 1,
Err(e) => { Err(e) => {

View File

@@ -243,10 +243,10 @@ pub fn proxy_file(fd: RawFd) -> std::io::Result<RawFd> {
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
#[allow(dead_code)] #[allow(dead_code)]
pub struct KsuKpmCmd { pub struct KsuKpmCmd {
pub control_code: u64,
pub arg1: u64,
pub arg2: u64, pub arg2: u64,
pub arg3: u64, pub result_code: u64,
pub arg4: u64,
pub arg5: u64,
} }
#[allow(dead_code)] #[allow(dead_code)]

View File

@@ -1,7 +1,7 @@
use crate::{ use crate::{
defs,
ksucalls::proxy_file, ksucalls::proxy_file,
utils::{self, umask}, utils::{self, umask},
defs,
}; };
use anyhow::{Context, Ok, Result, bail}; use anyhow::{Context, Ok, Result, bail};
use getopts::Options; use getopts::Options;

View File

@@ -5,21 +5,20 @@ use std::{
fs::{PermissionsExt, symlink}, fs::{PermissionsExt, symlink},
process::CommandExt, process::CommandExt,
}, },
path::Path,
process::{Command, Stdio}, process::{Command, Stdio},
}; };
use anyhow::Result; use anyhow::Result;
use log::{info, warn}; use log::{info, warn};
pub fn start_uid_scanner_daemon() -> Result<()> { const SCANNER_PATH: &str = "/data/adb/uid_scanner";
const SCANNER_PATH: &str = "/data/adb/uid_scanner"; const LINK_DIR: &str = "/data/adb/ksu/bin";
const LINK_DIR: &str = "/data/adb/ksu/bin"; const LINK_PATH: &str = "/data/adb/ksu/bin/uid_scanner";
const LINK_PATH: &str = "/data/adb/ksu/bin/uid_scanner"; const SERVICE_DIR: &str = "/data/adb/service.d";
const SERVICE_DIR: &str = "/data/adb/service.d"; const SERVICE_PATH: &str = "/data/adb/service.d/uid_scanner.sh";
const SERVICE_PATH: &str = "/data/adb/service.d/uid_scanner.sh";
if !Path::new(SCANNER_PATH).exists() { pub fn start_uid_scanner_daemon() -> Result<()> {
if !fs::exists(SCANNER_PATH)? {
warn!("uid scanner binary not found at {}", SCANNER_PATH); warn!("uid scanner binary not found at {}", SCANNER_PATH);
return Ok(()); return Ok(());
} }
@@ -32,7 +31,7 @@ pub fn start_uid_scanner_daemon() -> Result<()> {
{ {
if let Err(e) = fs::create_dir_all(LINK_DIR) { if let Err(e) = fs::create_dir_all(LINK_DIR) {
warn!("failed to create {}: {}", LINK_DIR, e); warn!("failed to create {}: {}", LINK_DIR, e);
} else if !Path::new(LINK_PATH).exists() { } else if !fs::exists(LINK_PATH)? {
match symlink(SCANNER_PATH, LINK_PATH) { match symlink(SCANNER_PATH, LINK_PATH) {
Ok(_) => info!("created symlink {} -> {}", SCANNER_PATH, LINK_PATH), Ok(_) => info!("created symlink {} -> {}", SCANNER_PATH, LINK_PATH),
Err(e) => warn!("failed to create symlink: {}", e), Err(e) => warn!("failed to create symlink: {}", e),
@@ -42,13 +41,11 @@ pub fn start_uid_scanner_daemon() -> Result<()> {
if let Err(e) = fs::create_dir_all(SERVICE_DIR) { if let Err(e) = fs::create_dir_all(SERVICE_DIR) {
warn!("failed to create {}: {}", SERVICE_DIR, e); warn!("failed to create {}: {}", SERVICE_DIR, e);
} else if !Path::new(SERVICE_PATH).exists() { }
let content = r#"#!/system/bin/sh
# KSU uid_scanner auto-restart script if !fs::exists(SERVICE_PATH)? {
until [ -d "/sdcard/Android" ]; do sleep 1; done let content = include_str!("uid_scanner.sh");
sleep 10
/data/adb/uid_scanner restart
"#;
match fs::OpenOptions::new() match fs::OpenOptions::new()
.write(true) .write(true)
.create_new(true) .create_new(true)

View File

@@ -0,0 +1,5 @@
#!/system/bin/sh
# KSU uid_scanner auto-restart script
until [ -d "/sdcard/Android" ]; do sleep 1; done
sleep 10
/data/adb/uid_scanner restart