initialize, try dev on linux
This commit is contained in:
commit
59b801dfe3
10 changed files with 841 additions and 0 deletions
32
src/adb.rs
Normal file
32
src/adb.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use bytes::{Buf, BytesMut};
|
||||
|
||||
// little endian "OPEN"
|
||||
pub const CMD_OPEN: u32 = u32::from_le_bytes(*b"NEPO");
|
||||
|
||||
pub struct AdbFrame {
|
||||
pub cmd: u32,
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn try_parse(buf: &mut BytesMut) -> Option<AdbFrame> {
|
||||
loop {
|
||||
if buf.len() < 24 {
|
||||
return None;
|
||||
}
|
||||
// header
|
||||
let hdr = &buf[..24];
|
||||
let cmd = u32::from_le_bytes(hdr[0..4].try_into().unwrap());
|
||||
let data_len = u32::from_le_bytes(hdr[12..16].try_into().unwrap()) as usize;
|
||||
let magic = u32::from_le_bytes(hdr[20..24].try_into().unwrap());
|
||||
if (cmd ^ 0xFFFF_FFFF) != magic {
|
||||
buf.advance(1);
|
||||
continue;
|
||||
}
|
||||
if buf.len() < 24 + data_len {
|
||||
return None;
|
||||
}
|
||||
let payload = buf[24..24 + data_len].to_vec();
|
||||
buf.advance(24 + data_len);
|
||||
return Some(AdbFrame { cmd, payload });
|
||||
}
|
||||
}
|
||||
2
src/backend/mod.rs
Normal file
2
src/backend/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#[cfg(all(feature = "ptrace", target_arch = "aarch64"))]
|
||||
pub mod ptrace;
|
||||
29
src/backend/ptrace.rs
Normal file
29
src/backend/ptrace.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use crate::{adb, broadcaster, rule::RuleSet};
|
||||
use anyhow::Result;
|
||||
use bytes::BytesMut;
|
||||
use nix::{
|
||||
libc,
|
||||
sys::{
|
||||
ptrace,
|
||||
signal::Signal,
|
||||
wait::{WaitPidFlag, WaitStatus, waitpid},
|
||||
},
|
||||
unistd::Pid,
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
const PTRACE_GETREGSET_FALLBACK: i32 = 0x4204;
|
||||
const NT_PRSTATUS_FALLBACK: i32 = 1;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct UserAtRegs {
|
||||
regs: [u64; 31],
|
||||
sp: u64,
|
||||
pc: u64,
|
||||
pstate: u64,
|
||||
}
|
||||
17
src/broadcaster.rs
Normal file
17
src/broadcaster.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
use std::process::Command;
|
||||
|
||||
pub fn broadcast(action: &str, service: &str, rule: &str) {
|
||||
let _ = Command::new("am")
|
||||
.args([
|
||||
"broadcast",
|
||||
"-a",
|
||||
action,
|
||||
"--es",
|
||||
"service",
|
||||
service,
|
||||
"--es",
|
||||
"rule",
|
||||
rule,
|
||||
])
|
||||
.status();
|
||||
}
|
||||
43
src/config.rs
Normal file
43
src/config.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use anyhow::Ok;
|
||||
use serde::Deserialize;
|
||||
use std::{fs, time::Duration};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Rule {
|
||||
pub name: String,
|
||||
pub when: String,
|
||||
#[serde(default)]
|
||||
pub contains: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub pattern: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Config {
|
||||
#[serde(default = "default_debounce")]
|
||||
pub debounce_ms: u64,
|
||||
#[serde(default = "default_peek")]
|
||||
pub max_payload_peek: usize,
|
||||
pub broadcast_action: String,
|
||||
#[serde(default)]
|
||||
pub rules: Vec<Rule>,
|
||||
}
|
||||
|
||||
fn default_debounce() -> u64 {
|
||||
3000
|
||||
}
|
||||
|
||||
fn default_peek() -> usize {
|
||||
256
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load(path: &str) -> anyhow::Result<Self> {
|
||||
let s = fs::read_to_string(path)?;
|
||||
Ok(serde_json::from_str(&s)?)
|
||||
}
|
||||
|
||||
pub fn debounce(&self) -> Duration {
|
||||
Duration::from_millis(self.debounce_ms)
|
||||
}
|
||||
}
|
||||
9
src/main.rs
Normal file
9
src/main.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
mod adb;
|
||||
mod backend;
|
||||
mod broadcaster;
|
||||
mod config;
|
||||
mod rule;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
49
src/rule.rs
Normal file
49
src/rule.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use crate::config::{Config, Rule};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
pub struct CompiledRule {
|
||||
pub name: String,
|
||||
pub contains: Vec<String>,
|
||||
pub pattern: Option<Regex>,
|
||||
}
|
||||
|
||||
pub struct RuleSet {
|
||||
rules: Vec<CompiledRule>,
|
||||
}
|
||||
|
||||
impl RuleSet {
|
||||
pub fn from_cfg(cfg: &Config) -> Self {
|
||||
let mut v = Vec::new();
|
||||
for r in &cfg.rules {
|
||||
let re = match &r.pattern {
|
||||
Some(p) => Some(Regex::new(p).unwrap()),
|
||||
None => None,
|
||||
};
|
||||
v.push(CompiledRule {
|
||||
name: r.name.clone(),
|
||||
contains: r.contains.clone(),
|
||||
pattern: re,
|
||||
});
|
||||
}
|
||||
|
||||
Self { rules: v }
|
||||
}
|
||||
|
||||
pub fn match_service<'a>(&'a self, service: &str) -> Option<&'a str> {
|
||||
'outer: for r in &self.rules {
|
||||
for c in &r.contains {
|
||||
if !service.contains(c) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
if let Some(re) = &r.pattern {
|
||||
if !re.is_match(service) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return Some(&r.name);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue