Handle zygote death

This commit is contained in:
Nullptr
2023-02-15 13:15:35 +08:00
parent 5c00071fed
commit baf444228d
9 changed files with 89 additions and 61 deletions

View File

@@ -10,6 +10,7 @@ android_logger = "0.12.0"
anyhow = { version = "1.0.68", features = ["backtrace"] }
clap = { version = "4.1.4", features = ["derive"] }
const_format = "0.2.5"
lazy_static = "1.4.0"
log = "0.4.17"
memfd = "0.6.2"
nix = "0.26.2"
@@ -17,6 +18,8 @@ num_enum = "0.5.9"
passfd = "0.1.5"
rand = "0.8.5"
binder = { path = "src/external/binder_rs/binder" }
[profile.release]
strip = true
opt-level = "z"

View File

@@ -20,6 +20,7 @@ cargo {
val isDebug = gradle.startParameter.taskNames.any { it.toLowerCase().contains("debug") }
profile = if (isDebug) "debug" else "release"
exec = { spec, _ ->
spec.environment("ANDROID_NDK_HOME", android.ndkDirectory.path)
spec.environment("VERSION_CODE", verCode)
spec.environment("VERSION_NAME", verName)
}

View File

@@ -23,6 +23,8 @@ macro_rules! lp_select {
}
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
pub const PROP_SVC_ZYGOTE: &str = "init.svc.zygote";
pub const ZYGISK_LOADER: &str = "libzygiskloader.so";
pub const SOCKET_PLACEHOLDER: &str = "socket_placeholder";

View File

@@ -1,4 +1,3 @@
use crate::constants;
use anyhow::Result;
use nix::unistd::gettid;
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream, process::Command};
@@ -27,10 +26,10 @@ pub fn get_native_bridge() -> String {
std::env::var("NATIVE_BRIDGE").unwrap_or_default()
}
pub fn restore_native_bridge() -> Result<()> {
pub fn set_property(name: &str, value: &str) -> Result<()> {
Command::new("resetprop")
.arg(constants::PROP_NATIVE_BRIDGE)
.arg(get_native_bridge())
.arg(name)
.arg(value)
.spawn()?.wait()?;
Ok(())
}

View File

@@ -1,12 +1,13 @@
use crate::{constants, utils};
use anyhow::{bail, Result};
use nix::unistd::{getgid, getuid};
use nix::unistd::{getgid, getuid, Pid};
use std::process::{Child, Command};
use std::sync::mpsc;
use std::{fs, thread};
use std::os::unix::net::UnixListener;
use std::path::Path;
use std::time::Duration;
use binder::IBinder;
use nix::sys::signal::{kill, Signal};
static mut LOCK: Option<UnixListener> = None;
@@ -49,36 +50,56 @@ fn ensure_single_instance() -> Result<()> {
}
fn spawn_daemon() -> Result<()> {
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
let (sender, receiver) = mpsc::channel();
let mut waiting = vec![];
let mut spawn = |mut daemon: Child, socket: &'static str| {
waiting.push(socket);
let sender = sender.clone();
thread::spawn(move || {
let result = daemon.wait().unwrap();
log::error!("Daemon process {} died: {}", daemon.id(), result);
drop(daemon);
sender.send(()).unwrap();
});
};
if let Ok(it) = daemon32 { spawn(it, "/dev/socket/zygote_secondary") }
if let Ok(it) = daemon64 { spawn(it, "/dev/socket/zygote") }
waiting.into_iter().for_each(|socket| wait_zygote(socket));
log::info!("Zygote ready, restore native bridge");
utils::restore_native_bridge()?;
let _ = receiver.recv();
bail!("Daemon process died");
}
fn wait_zygote(socket: &str) -> () {
let path = Path::new(socket);
let mut lives = 5;
loop {
if path.exists() { return; }
log::debug!("{socket} not exists, wait for 1s...");
thread::sleep(Duration::from_secs(1));
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
let mut child_ids = vec![];
let (sender, receiver) = mpsc::channel();
let mut spawn = |mut daemon: Child| {
child_ids.push(daemon.id());
let sender = sender.clone();
thread::spawn(move || {
let result = daemon.wait().unwrap();
log::error!("Daemon process {} died: {}", daemon.id(), result);
drop(daemon);
let _ = sender.send(());
});
};
if let Ok(it) = daemon32 { spawn(it) }
if let Ok(it) = daemon64 { spawn(it) }
let mut binder = loop {
if receiver.try_recv().is_ok() {
bail!("Daemon died before system server ready");
}
match binder::get_service("activity") {
Some(binder) => break binder,
None => {
log::trace!("System server not ready, wait for 1s...");
thread::sleep(Duration::from_secs(1));
}
};
};
log::info!("System server ready, restore native bridge");
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
loop {
if receiver.try_recv().is_ok() || binder.ping_binder().is_err() { break; }
thread::sleep(Duration::from_secs(1))
}
for child in child_ids {
let _ = kill(Pid::from_raw(child as i32), Signal::SIGKILL);
}
lives -= 1;
if lives == 0 {
bail!("Too many crashes, abort");
}
log::error!("Restarting zygote...");
utils::set_property(constants::PROP_NATIVE_BRIDGE, constants::ZYGISK_LOADER)?;
utils::set_property(constants::PROP_SVC_ZYGOTE, "restart")?;
thread::sleep(Duration::from_secs(2));
}
}