You've already forked ZygiskNext
mirror of
https://github.com/Dr-TSNG/ZygiskNext.git
synced 2025-08-27 23:46:34 +00:00
Get rid of binder-rs & Refine watchdog
This commit is contained in:
@@ -9,6 +9,13 @@ fi
|
||||
|
||||
cd "$MODDIR"
|
||||
|
||||
# temporary fix AVD 11 magisk
|
||||
if [ -f /dev/zygisk_service ];then
|
||||
log -p i -t "zygisk-sh" "service called twice";
|
||||
exit;
|
||||
fi
|
||||
touch /dev/zygisk_service
|
||||
|
||||
if [ "$(which magisk)" ]; then
|
||||
for file in ../*; do
|
||||
if [ -d "$file" ] && [ -d "$file/zygisk" ] && ! [ -f "$file/disable" ]; then
|
||||
|
||||
@@ -23,7 +23,6 @@ proc-maps = "0.3"
|
||||
rustix = { version = "0.38", features = [ "fs", "process", "mount", "net", "thread"] }
|
||||
tokio = { version = "1.28", features = ["full"] }
|
||||
|
||||
binder = { git = "https://github.com/Kernel-SU/binder_rs", rev = "c9f2b62d6a744fd2264056c638c1b061a6a2932d" }
|
||||
fuser = { git = "https://github.com/Dr-TSNG/fuser", default-features = false }
|
||||
ptrace-do = { git = "https://github.com/5ec1cff/ptrace-do" }
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ pub const STATUS_ROOT_IMPL_TOO_OLD: &str = "❌ Root implementation version too
|
||||
pub const STATUS_ROOT_IMPL_ABNORMAL: &str = "❌ Abnormal root implementation version";
|
||||
pub const STATUS_ROOT_IMPL_MULTIPLE: &str = "❌ Multiple root implementations installed";
|
||||
|
||||
pub const MAX_RESTART_COUNT: i32 = 5;
|
||||
pub const ZYGOTE_SERVICE_PROP: &str = "init.svc.zygote";
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum DaemonSocketAction {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
use std::ffi::{c_char, c_void, CStr, CString};
|
||||
use std::os::fd::AsFd;
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::process::Command;
|
||||
@@ -96,6 +96,28 @@ pub fn set_property(name: &str, value: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wait_property(name: &str, serial: u32) -> Result<u32> {
|
||||
let name = CString::new(name)?;
|
||||
let info = unsafe {
|
||||
__system_property_find(name.as_ptr())
|
||||
};
|
||||
let mut serial = serial;
|
||||
unsafe {
|
||||
__system_property_wait(info, serial, &mut serial, std::ptr::null());
|
||||
}
|
||||
Ok(serial)
|
||||
}
|
||||
|
||||
pub fn get_property_serial(name: &str) -> Result<u32> {
|
||||
let name = CString::new(name)?;
|
||||
let info = unsafe {
|
||||
__system_property_find(name.as_ptr())
|
||||
};
|
||||
Ok(unsafe {
|
||||
__system_property_serial(info)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn switch_mount_namespace(pid: i32) -> Result<()> {
|
||||
let cwd = std::env::current_dir()?;
|
||||
let mnt = fs::File::open(format!("/proc/{}/ns/mnt", pid))?;
|
||||
@@ -177,4 +199,7 @@ extern "C" {
|
||||
fn __android_log_print(prio: i32, tag: *const c_char, fmt: *const c_char, ...) -> i32;
|
||||
fn __system_property_get(name: *const c_char, value: *mut c_char) -> u32;
|
||||
fn __system_property_set(name: *const c_char, value: *const c_char) -> u32;
|
||||
fn __system_property_find(name: *const c_char) -> *const c_void;
|
||||
fn __system_property_wait(info: *const c_void, old_serial: u32, new_serial: *mut u32, timeout: *const libc::timespec) -> bool;
|
||||
fn __system_property_serial(info: *const c_void) -> u32;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
use crate::{constants, root_impl, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use std::fs;
|
||||
use std::future::Future;
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
use binder::IBinder;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::StreamExt;
|
||||
use futures::{FutureExt, join, pin_mut};
|
||||
use futures::future::{Fuse, FusedFuture};
|
||||
use log::{debug, error, info};
|
||||
use rustix::mount::mount_bind;
|
||||
use rustix::process::{getgid, getuid, kill_process, Pid, Signal};
|
||||
use rustix::process::{getgid, getuid};
|
||||
use tokio::process::{Child, Command};
|
||||
use crate::utils::LateInit;
|
||||
use tokio::{select, task};
|
||||
use tokio::time::Instant;
|
||||
use crate::utils::{get_property, get_property_serial, LateInit, wait_property};
|
||||
|
||||
static PROP_SECTIONS: LateInit<[String; 2]> = LateInit::new();
|
||||
|
||||
@@ -108,62 +107,111 @@ fn check_and_set_hint() -> Result<bool> {
|
||||
}
|
||||
|
||||
async fn spawn_daemon() -> Result<()> {
|
||||
let mut lives = 5;
|
||||
let mut lives = constants::MAX_RESTART_COUNT;
|
||||
let mut last_restart_time = Instant::now();
|
||||
let (sender, mut receiver) = tokio::sync::mpsc::channel(1);
|
||||
task::spawn_blocking(move || {
|
||||
let mut serial = 0u32;
|
||||
let mut last_state = "running".to_string();
|
||||
info!("zygote property monitor started");
|
||||
loop {
|
||||
let old_serial = serial;
|
||||
serial = wait_property(constants::ZYGOTE_SERVICE_PROP, serial).expect("failed to wait on property");
|
||||
let new_state = get_property(constants::ZYGOTE_SERVICE_PROP).expect("failed to get property");
|
||||
if last_state == "running" && new_state != "running" {
|
||||
info!("new zygote state: {} serial {} -> {}", new_state, old_serial, serial);
|
||||
sender.blocking_send(old_serial).expect("failed to notify");
|
||||
}
|
||||
last_state = new_state
|
||||
}
|
||||
});
|
||||
let mut restart_serial = 0u32;
|
||||
loop {
|
||||
let mut futures = FuturesUnordered::<Pin<Box<dyn Future<Output=Result<()>>>>>::new();
|
||||
let mut child_ids = vec![];
|
||||
let daemon32 = Command::new(constants::PATH_CP_BIN32).arg("daemon").spawn();
|
||||
let daemon64 = Command::new(constants::PATH_CP_BIN64).arg("daemon").spawn();
|
||||
async fn spawn_daemon(mut daemon: Child) -> Result<()> {
|
||||
let result = daemon.wait().await?;
|
||||
log::error!("Daemon process {} died: {}", daemon.id().unwrap(), result);
|
||||
Ok(())
|
||||
}
|
||||
if let Ok(it) = daemon32 {
|
||||
child_ids.push(it.id().unwrap());
|
||||
futures.push(Box::pin(spawn_daemon(it)));
|
||||
}
|
||||
if let Ok(it) = daemon64 {
|
||||
child_ids.push(it.id().unwrap());
|
||||
futures.push(Box::pin(spawn_daemon(it)));
|
||||
}
|
||||
|
||||
async fn binder_listener() -> Result<()> {
|
||||
let mut binder = loop {
|
||||
match binder::get_service("activity") {
|
||||
Some(binder) => break binder,
|
||||
None => {
|
||||
log::trace!("System server not ready, wait for 1s...");
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
info!("System server ready");
|
||||
|
||||
loop {
|
||||
if binder.ping_binder().is_err() { break; }
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
async fn spawn_daemon(mut daemon: Child, mut killer: tokio::sync::watch::Receiver<()>) {
|
||||
let id = daemon.id().unwrap();
|
||||
select! {
|
||||
result = daemon.wait() => {
|
||||
log::error!("Daemon process {} died: {}", id, result
|
||||
.expect("failed to get daemon process exit reason")
|
||||
);
|
||||
},
|
||||
_ = killer.changed() => {
|
||||
log::warn!("Kill daemon process {}", id);
|
||||
daemon.kill().await.expect("failed to kill");
|
||||
}
|
||||
}
|
||||
bail!("System server died");
|
||||
}
|
||||
futures.push(Box::pin(binder_listener()));
|
||||
let (tx, rx) = tokio::sync::watch::channel(());
|
||||
let wait32 = match daemon32 {
|
||||
Ok(child) => {
|
||||
spawn_daemon(child, rx.clone()).fuse()
|
||||
}
|
||||
Err(..) => {
|
||||
Fuse::terminated()
|
||||
}
|
||||
};
|
||||
let wait64 = match daemon64 {
|
||||
Ok(child) => {
|
||||
spawn_daemon(child, rx.clone()).fuse()
|
||||
}
|
||||
Err(..) => {
|
||||
Fuse::terminated()
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = futures.next().await.unwrap() {
|
||||
error!("{}", e);
|
||||
pin_mut!(wait32, wait64);
|
||||
|
||||
let mut restart_zygote = true;
|
||||
|
||||
select! {
|
||||
_ = &mut wait32 => {},
|
||||
_ = &mut wait64 => {},
|
||||
_ = async {
|
||||
// we expect a serial different from last restart
|
||||
loop {
|
||||
if restart_serial != receiver.recv().await.expect("no serial received") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} => {
|
||||
restart_zygote = false;
|
||||
}
|
||||
}
|
||||
|
||||
for child in child_ids {
|
||||
debug!("Killing child process {}", child);
|
||||
let _ = kill_process(Pid::from_raw(child as i32).unwrap(), Signal::Kill);
|
||||
// kill all remain daemons
|
||||
tx.send(())?;
|
||||
|
||||
// wait for all daemons
|
||||
loop {
|
||||
futures::select! {
|
||||
_ = wait32 => {},
|
||||
_ = wait64 => {},
|
||||
complete => { break; }
|
||||
}
|
||||
}
|
||||
|
||||
lives -= 1;
|
||||
let current = Instant::now();
|
||||
if current - last_restart_time >= Duration::new(30, 0) {
|
||||
lives = constants::MAX_RESTART_COUNT;
|
||||
log::warn!("reset live count to {}", lives);
|
||||
} else {
|
||||
lives -= 1;
|
||||
log::warn!("remain live count {}", lives);
|
||||
}
|
||||
if lives == 0 {
|
||||
bail!("Too many crashes, abort");
|
||||
}
|
||||
last_restart_time = current;
|
||||
|
||||
error!("Restarting zygote...");
|
||||
utils::set_property(constants::PROP_CTL_RESTART, "zygote")?;
|
||||
error!("Daemons are going to restart ...");
|
||||
|
||||
if restart_zygote {
|
||||
error!("Restarting zygote...");
|
||||
restart_serial = get_property_serial(constants::ZYGOTE_SERVICE_PROP)?;
|
||||
debug!("serial before restart {}", restart_serial);
|
||||
utils::set_property(constants::PROP_CTL_RESTART, "zygote")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user