Skip to content

Instantly share code, notes, and snippets.

@anonymousik
Created February 25, 2026 06:02
Show Gist options
  • Select an option

  • Save anonymousik/20d96b80b3487d36084a02ded508aabe to your computer and use it in GitHub Desktop.

Select an option

Save anonymousik/20d96b80b3487d36084a02ded508aabe to your computer and use it in GitHub Desktop.
fix(v13): hardware-grounded from live getprop — 12 targeted fixes, PSI-LMK, A15-idiv, V3D-fence, MMA, TCP-FO v3 — Hardware-Targeted Edition
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
╔══════════════════════════════════════════════════════════════════════════════╗
║ PLAYBOX TITANIUM v13.0 PRECISION — Hardware-Targeted Edition ║
║ Target : Sagemcom DCTIW362P | Android TV 9 API 28 | PTT1.190826.001 ║
║ Kernel : 4.9.190-1-6pre armv7l ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ REAL HARDWARE (verified from live getprop dump): ║
║ CPU : ARMv7 Cortex-A15 dual-core @ ~1.0 GHz ║
║ dalvik.vm.isa.arm.variant = cortex-a15 ║
║ dalvik.vm.isa.arm.features = default ← A15 idiv NOT enabled ║
║ GPU : Broadcom VideoCore | ro.gfx.driver.0 = gfxdriver-bcmstb ║
║ ro.opengles.version = 196609 (GLES 3.1) ║
║ ro.v3d.fence.expose = true | ro.v3d.disable_buffer_age = true ║
║ ro.sf.disable_triple_buffer = 0 (triple buffer ON) ║
║ ro.nx.hwc2.tweak.fbcomp = 1 (HWC2 FB compositor tweak ON) ║
║ BCM Nexus Heaps (kernel-reserved, CANNOT be overridden): ║
║ main=96m | gfx=64m | video_secure=80m | grow/shrink=2m ║
║ TOTAL Nexus: 240MB | Userspace budget: ~1045MB ║
║ VDec : ro.nx.media.vdec_outportbuf=32 (port buffers) ║
║ ro.nx.media.vdec.fsm1080p=1 (FSM path active) ║
║ ro.nx.media.vdec.progoverride=2 (progressive decode override) ║
║ ro.nx.mma=1 (Memory Manager Arena enabled) ║
║ Display: dyn.nx.display-size=1920x1080 (currently 1080p) ║
║ DRM : PlayReady 2.5 | Widevine | ClearKey (all HALs running) ║
║ LMK : ro.lmk.use_minfree_levels=false → PSI-ONLY, minfree /sys IGNORED ║
║ DEX : dex2oat-Xmx=512m | appimageformat=lz4 | usejitprofiles=true ║
║ Net : Kernel 4.9.190 | TCP Fast Open v3 | BBR absent (not compiled in) ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ PRECISION FIXES vs v12: ║
║ [FIX-1] Dalvik heap: NEVER shrink heapsize/growthlimit — OEM 512m/192m OK ║
║ heapminfree: 512k → 2m (too small → excessive GC pressure) ║
║ heapmaxfree: 8m → 16m (allow more free to reduce GC frequency) ║
║ [FIX-2] LMK: use_minfree_levels=false → /sys minfree writes SKIPPED ║
║ Use PSI-based thresholds + upgrade_pressure: 100 → 50 ║
║ extra_free_kbytes tuning (zone watermark adjust) ║
║ [FIX-3] A15 IDIV: dalvik.vm.isa.arm.features = default,idiv ║
║ Hardware integer divide on A15 — reduces codec selection overhead ║
║ [FIX-4] BCM MMA: media.brcm.mma.enable=1 (confirmed ro.nx.mma=1) ║
║ [FIX-5] VDec buffers: media.brcm.vpu.buffers=32 (from vdec_outportbuf=32) ║
║ [FIX-6] persist.sys.ui.hw: false → true (GPU force rendering) ║
║ [FIX-7] persist.sys.hdmi.keep_awake: false → true ║
║ [FIX-8] media.stagefright.cache-params: 32768/65536/25 → 65536/131072/30 ║
║ [FIX-9] net.tcp.default_init_rwnd: 60 → 120 ║
║ [FIX-10] WebView vmsize: 100MB → 50MB (TV STB, no browser use) ║
║ [FIX-11] dex2oat budget: use confirmed -Xmx 512m for AOT speed-profile ║
║ [FIX-12] BBR: removed (not in kernel 4.9.190-1-6pre config) → cubic/htcp ║
║ [NEW] debug.hwui.layer_cache_size: 16384 → 32768 (V3D with explicit fence)║
║ [NEW] HWC2 fbcomp-aware layer budget tuning ║
║ [NEW] Stagefright: vdec.progoverride=2 path tuning ║
║ [NEW] DRM: PlayReady 2.5 + Widevine specific hints ║
║ [NEW] 50Hz/PAL mode: persist.nx.vidout.50hz check for pl-PL locale ║
╚══════════════════════════════════════════════════════════════════════════════╝
"""
from __future__ import annotations
import os, sys, subprocess, time, json, argparse, shutil
from pathlib import Path
from typing import Optional, List, Dict, Tuple, Callable, Any
from dataclasses import dataclass
from enum import Enum, auto
# ─────────────────────────────────────────────────────────────────────────────
VERSION = "13.0-PRECISION"
DEFAULT_DEVICE = "192.168.1.3:5555"
CACHE_DIR = Path.home() / ".playbox_cache"
BACKUP_DIR = CACHE_DIR / "backups_v13"
LOG_FILE = CACHE_DIR / "autopilot_v13.log"
for d in (CACHE_DIR, BACKUP_DIR):
d.mkdir(parents=True, exist_ok=True)
# ─────────────────────────────────────────────────────────────────────────────
# VERIFIED HARDWARE CONSTANTS (from live getprop 192.168.1.3:5555)
# ─────────────────────────────────────────────────────────────────────────────
class HW:
"""
All values verified from real getprop dump.
MUST NOT be changed without new getprop evidence.
"""
# CPU
ISA_VARIANT = "cortex-a15"
# A15 supports hardware integer divide (IDIV) — not in OEM 'default' features
ISA_FEATURES_OEM = "default"
ISA_FEATURES_OPT = "default,idiv" # enables HW idiv in JIT/AOT codegen
# BCM Nexus Kernel Heaps (FIXED — kernel-reserved, cannot change from userspace)
NX_HEAP_MAIN = 96 # MB — Nexus core heap (media pipeline)
NX_HEAP_GFX = 64 # MB — VideoCore graphics heap
NX_HEAP_VIDEO_SECURE = 80 # MB — DRM/secure video decode
NX_HEAP_TOTAL = 240 # MB — NX_HEAP_MAIN+GFX+VIDEO_SECURE
# Userspace memory budget: 1459 - 240 (nexus) - 24 (watermark) - 150 (OS)
RAM_TOTAL_MB = 1459
EXTRA_FREE_KB = 24300 # sys.sysctl.extra_free_kbytes (zone watermark)
USERSPACE_BUDGET_MB = RAM_TOTAL_MB - NX_HEAP_TOTAL - (EXTRA_FREE_KB//1024) - 150
# VDec (BCM Nexus media decoder)
VDEC_OUTPORT_BUFFERS = 32 # ro.nx.media.vdec_outportbuf — CONFIRMED
VDEC_FSM_1080P = 1 # ro.nx.media.vdec.fsm1080p — FSM path active
VDEC_PROG_OVERRIDE = 2 # ro.nx.media.vdec.progoverride
# Display (current state from dyn.nx.display-size)
DISPLAY_WIDTH = 1920
DISPLAY_HEIGHT = 1080
LCD_DENSITY = 320 # ro.nx.sf.lcd_density / ro.sf.lcd_density
# GPU / HWC
GLES_VERSION = "196609" # 3.1 (0x30001)
V3D_FENCE_EXPOSE = True # explicit sync fences active
V3D_BUFFER_AGE_OFF = True # vendor already disabled — DO NOT re-enable
HWC2_FBCOMP_TWEAK = 1 # ro.nx.hwc2.tweak.fbcomp
TRIPLE_BUFFER = True # ro.sf.disable_triple_buffer=0
# Dalvik OEM defaults (DO NOT shrink below these)
DALVIK_HEAPSIZE = "512m" # OEM default — sufficient for SmartTube
DALVIK_GROWTHLIMIT = "192m" # OEM default — keep
DALVIK_STARTSIZE = "16m"
DALVIK_HEAPMINFREE = "2m" # FIX: was 512k — causes GC pressure
DALVIK_HEAPMAXFREE = "16m" # FIX: was 8m — increase to reduce GC
DALVIK_TARGET_UTIL = "0.75"
DEX2OAT_XMX = "512m" # confirmed budget for AOT
# LMK: PSI-only (use_minfree_levels=false → /sys minfree IGNORED)
LMK_MINFREE_USABLE = False # confirmed: /sys writes do nothing
LMK_UPGRADE_PRESSURE = 50 # fix: was 100
# Network / Kernel 4.9.190-1-6pre
KERNEL_VER = "4.9.190"
TCP_BBR_AVAILABLE = False # not in this kernel config
TCP_FAST_OPEN = True # supported in 4.9+
# DRM
PLAYREADY_VERSION = "2.5"
WIDEVINE_RUNNING = True
# Locale / Region
LOCALE = "pl-PL"
TIMEZONE = "Europe/Amsterdam"
# Package names (verified from real ps output)
PKG_SMARTTUBE_STABLE = "org.smarttube.stable"
PKG_SMARTTUBE_BETA = "org.smarttube.beta"
PKG_SMARTTUBE_LEGACY = "com.liskovsoft.smarttubetv"
PKG_PROJECTIVY = "com.spocky.projengmenu" # from ps: u0_a88
PKG_SHIZUKU = "moe.shizuku.privileged.api"
PKG_MEDIASHELL = "com.google.android.apps.mediashell"
# APK URLs
URL_SMARTTUBE_STABLE = "https://github.com/yuliskov/SmartTube/releases/download/latest/smarttube_stable.apk"
URL_SMARTTUBE_BETA = "https://github.com/yuliskov/SmartTube/releases/download/latest/smarttube_beta.apk"
URL_PROJECTIVY = "https://github.com/spocky/projectivy-launcher/releases/latest/download/Projectivy_Launcher.apk"
URL_SHIZUKU = "https://github.com/RikkaApps/Shizuku/releases/download/v13.5.4/shizuku-v13.5.4-release.apk"
# DNS providers (correct DoT hostnames — verified RFC + Android 9 tested)
DNS: Dict[str, Tuple[str,str,str]] = {
"cloudflare": ("one.one.one.one", "1.1.1.1", "1.0.0.1"),
"google": ("dns.google", "8.8.8.8", "8.8.4.4"),
"quad9": ("dns.quad9.net", "9.9.9.9", "149.112.112.112"),
"adguard": ("dns.adguard.com", "94.140.14.14", "94.140.15.15"),
"nextdns": ("dns.nextdns.io", "45.90.28.0", "45.90.30.0"),
}
class Status(Enum):
OK=auto(); WARN=auto(); BROKEN=auto(); MISSING=auto(); UNKNOWN=auto()
# ─────────────────────────────────────────────────────────────────────────────
# CHROMECAST PROTECTION
# ─────────────────────────────────────────────────────────────────────────────
class Cast:
"""
PROTECTED packages — verified against device init.svc.* and real ps output.
Note: debloat.sh on device lists apps.mediashell and gms.cast.receiver
as "safe" — THIS IS WRONG. Both are core Cast services. Protected here.
"""
PROTECTED: Dict[str,str] = {
HW.PKG_MEDIASHELL:
"Cast Built-in daemon. mdnsd (running) + mediashell = full Cast stack.",
"com.google.android.gms":
"GMS — Cast SDK v3+, SessionManager, OAuth. DO NOT disable.",
"com.google.android.gsf":
"Google Services Framework — GMS auth dependency.",
"com.google.android.nearby":
"Nearby — mDNS responder. mdnsd (init.svc running) bridges here.",
"com.google.android.gms.cast.receiver":
"Cast Receiver Framework — confirmed in debloat.sh kill-list (WRONG).",
"com.google.android.tv.remote.service":
"TV Remote — Cast session UI. PID active: u0_a1 3569.",
"com.google.android.tvlauncher":
"TV Launcher — Cast ambient mode surface.",
"com.google.android.configupdater":
"Config Updater — TLS cert pins, Cast endpoint config.",
"com.google.android.wifidisplay":
"WiFi Display — Miracast/Cast transport fallback.",
"com.android.networkstack":
"Network Stack — IGMP multicast for mDNS (mdnsd confirmed running).",
"com.android.networkstack.tethering":
"Tethering — multicast routing shared with networkstack.",
}
@classmethod
def is_protected(cls, p: str) -> bool: return p in cls.PROTECTED
@classmethod
def reason(cls, p: str) -> str: return cls.PROTECTED.get(p,"")
# ─────────────────────────────────────────────────────────────────────────────
# LOGGER
# ─────────────────────────────────────────────────────────────────────────────
class L:
C = {"i":"\033[94m","s":"\033[92m","w":"\033[93m","e":"\033[91m",
"h":"\033[95m","c":"\033[96m","b":"\033[1m","r":"\033[0m","d":"\033[2m"}
_buf: List[str] = []
@classmethod
def _out(cls,msg:str,lvl:str)->None:
ts=time.strftime("%H:%M:%S"); c=cls.C.get(lvl,cls.C["i"])
print(f"{c}[{ts}] {msg}{cls.C['r']}")
cls._buf.append(f"[{ts}][{lvl}] {msg}")
@classmethod
def ok(cls,m:str)->None: cls._out(f"✓ {m}","s")
@classmethod
def info(cls,m:str)->None: cls._out(m,"i")
@classmethod
def warn(cls,m:str)->None: cls._out(f"⚠ {m}","w")
@classmethod
def err(cls,m:str)->None: cls._out(f"✗ {m}","e")
@classmethod
def fix(cls,m:str)->None: cls._out(f"🔧 {m}","w")
@classmethod
def cast(cls,m:str)->None: cls._out(f"🛡 {m}","s")
@classmethod
def dim(cls,m:str)->None: cls._out(f" └─ {m}","d")
@classmethod
def hdr(cls,m:str)->None:
s="═"*72
print(f"\n{cls.C['h']}{cls.C['b']}{s}\n {m}\n{s}{cls.C['r']}\n")
@classmethod
def sub(cls,m:str)->None:
print(f"\n{cls.C['c']} ── {m} ──{cls.C['r']}")
@classmethod
def save(cls)->None:
try:
with open(LOG_FILE,"a") as f:
f.write(f"\n{'─'*60}\n{time.strftime('%Y-%m-%d %H:%M:%S')} v{VERSION}\n")
f.write("\n".join(cls._buf)+"\n")
except OSError: pass
# ─────────────────────────────────────────────────────────────────────────────
# ADB SHELL
# ─────────────────────────────────────────────────────────────────────────────
class ADB:
dev: Optional[str] = None
TO = 35; RET = 3
@classmethod
def connect(cls, t:str) -> bool:
try:
r = subprocess.run(["adb","connect",t], capture_output=True, text=True, timeout=10)
if "connected" in r.stdout.lower():
cls.dev=t; L.ok(f"ADB: {t}"); return True
L.err(f"ADB failed: {r.stdout.strip()}"); return False
except FileNotFoundError:
L.err("'adb' not found — install Android Platform Tools"); sys.exit(1)
except subprocess.TimeoutExpired:
L.err(f"ADB timeout: {t}"); return False
@classmethod
def detect(cls) -> Optional[str]:
try:
out = subprocess.check_output(["adb","devices"],text=True,timeout=5)
for line in out.splitlines():
if "\tdevice" in line: return line.split("\t")[0].strip()
except Exception: pass
return None
@classmethod
def sh(cls, cmd:str, silent:bool=False) -> str:
if not cls.dev: return ""
for i in range(cls.RET):
try:
return subprocess.check_output(
["adb","-s",cls.dev,"shell",cmd],
stderr=subprocess.STDOUT, text=True, timeout=cls.TO).strip()
except subprocess.TimeoutExpired:
if i < cls.RET-1: time.sleep(1.5)
elif not silent: L.warn(f"Timeout: {cmd[:55]}")
except subprocess.CalledProcessError as e:
return (e.output or "").strip()
except Exception as e:
if not silent: L.err(str(e))
return ""
@classmethod
def root(cls, cmd:str) -> str:
for p in (f'su -c "{cmd}"', f'rish -c "{cmd}"'):
r = cls.sh(p, silent=True)
if r and "not found" not in r and "permission denied" not in r.lower():
return r
return cls.sh(cmd)
@classmethod
def push(cls, local:str, remote:str) -> bool:
try:
subprocess.check_call(["adb","-s",cls.dev,"push",local,remote],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=120)
return True
except Exception: return False
@classmethod
def prop(cls, k:str) -> str: return cls.sh(f"getprop {k}",silent=True)
@classmethod
def setprop(cls, k:str, v:str) -> None: cls.sh(f"setprop {k} {v}",silent=True)
@classmethod
def sput(cls, ns:str, k:str, v:str) -> None:
cls.sh(f"settings put {ns} {k} {v}",silent=True)
@classmethod
def sget(cls, ns:str, k:str) -> str:
return cls.sh(f"settings get {ns} {k}",silent=True)
@classmethod
def pkg_ok(cls, p:str) -> bool: return p in cls.sh(f"pm list packages -e {p}",silent=True)
@classmethod
def pkg_exists(cls, p:str) -> bool: return p in cls.sh(f"pm list packages {p}",silent=True)
@classmethod
def pkg_ver(cls, p:str) -> str:
out = cls.sh(f"dumpsys package {p} | grep versionName",silent=True)
return out.split("=")[-1].strip() if "=" in out else "?"
@classmethod
def sysw(cls, path:str, val:str) -> bool:
cls.root(f"echo {val} > {path}")
got = cls.root(f"cat {path}").strip()
return val in got
# ─────────────────────────────────────────────────────────────────────────────
# APK DOWNLOADER
# ─────────────────────────────────────────────────────────────────────────────
class APK:
@staticmethod
def get(url:str, dest:Path, force:bool=False) -> bool:
if dest.exists() and not force:
L.info(f" APK cached: {dest.name}"); return True
L.info(f" Downloading {dest.name}...")
ret = os.system(f'curl -L -s --retry 3 --connect-timeout 15 -o "{dest}" "{url}"')
if ret!=0 or not dest.exists() or dest.stat().st_size < 50_000:
L.err(f" Download failed: {dest.name}")
dest.unlink(missing_ok=True); return False
L.ok(f" {dest.name} ({dest.stat().st_size/1048576:.1f}MB)"); return True
@staticmethod
def install(local:Path, label:str="") -> bool:
remote = f"/data/local/tmp/{local.name}"
if not ADB.push(str(local), remote):
L.err(f" Push failed: {local.name}"); return False
r = ADB.sh(f"pm install -r -g --install-reason 1 {remote}",silent=True)
ADB.sh(f"rm {remote}",silent=True)
if "success" in r.lower():
L.ok(f" Installed: {label or local.stem}"); return True
L.err(f" Install failed: {r[:80]}"); return False
@staticmethod
def fetch_install(url:str, pkg:str, label:str, force:bool=False) -> bool:
p = CACHE_DIR / (pkg.replace(".","-")+".apk")
return APK.get(url,p,force) and APK.install(p,label)
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 1 — CORTEX-A15 + BCM CODEC PIPELINE (hardware-targeted)
# ─────────────────────────────────────────────────────────────────────────────
class VideoEngine:
"""
Tuned for BCM7362 / Cortex-A15 confirmed hardware.
A15 hardware idiv: enables integer divide instruction in JIT/AOT codegen.
Reduces per-frame codec pipeline overhead in ARMv7 ABR calculations.
VDec port buffers: 32 (from ro.nx.media.vdec_outportbuf=32).
MMA allocator: ro.nx.mma=1 confirmed → media.brcm.mma.enable=1.
Progressive override: ro.nx.media.vdec.progoverride=2 → inform media.brcm props.
Stagefright cache: 32768/65536/25 → 65536/131072/30
- MinCache 64KB: holds ~3s of 720p VP9 segment
- MaxCache 128KB: burst buffer for ABR quality switch
- KeepAlive 30s: longer IPTV session keepalive
"""
def codec_pipeline(self) -> None:
L.hdr("🎬 CODEC PIPELINE — BCM7362 VPU (A15 + MMA + VDec32)")
L.sub("A15 JIT/AOT — hardware idiv enable")
current = ADB.prop("dalvik.vm.isa.arm.features")
if current == HW.ISA_FEATURES_OPT:
L.ok(f"isa.arm.features already optimal: {current}")
else:
L.info(f" Current: {current} (OEM default — A15 idiv disabled)")
ADB.setprop("dalvik.vm.isa.arm.features", HW.ISA_FEATURES_OPT)
L.ok(f" isa.arm.features = {HW.ISA_FEATURES_OPT}")
L.dim("A15 hardware integer divide → faster JIT codegen per frame")
L.sub("Stagefright core")
stagefright_props = [
("media.stagefright.enable-player", "true"),
("media.stagefright.enable-http", "true"),
("media.stagefright.enable-aac", "true"),
("media.stagefright.enable-scan", "true"),
("media.stagefright.enable-meta", "true"),
# FIXED: was 32768/65536/25 on device → 65536/131072/30
("media.stagefright.cache-params", "65536/131072/30"),
]
for k,v in stagefright_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v)
L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
L.sub("Codec priority + C2 framework")
codec_props = [
("media.acodec.preferhw", "true"),
("media.vcodec.preferhw", "true"),
("media.codec.sw.fallback", "false"),
("media.codec.priority", "1"), # realtime thread class
# Already confirmed on device (v12 applied):
("debug.stagefright.ccodec", "1"), # C2 codec framework
("debug.stagefright.omx_default_rank", "0"), # BCM OMX primary
("debug.stagefright.c2.av1", "0"), # AV1 disabled
("drm.service.enabled", "true"), # already true
]
for k,v in codec_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v)
L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
L.sub("BCM VDec — MMA + port buffers (hardware-confirmed)")
brcm_codec = [
# MMA: ro.nx.mma=1 confirmed → must enable media layer
("media.brcm.mma.enable", "1"),
# VDec port buffers: matched to ro.nx.media.vdec_outportbuf=32
("media.brcm.vpu.buffers", str(HW.VDEC_OUTPORT_BUFFERS)),
("media.brcm.vpu.prealloc", "true"),
("media.brcm.secure.decode", "true"), # PlayReady 2.5 + Widevine
# FSM progressive path (ro.nx.media.vdec.fsm1080p=1)
("media.brcm.vdec.progoverride","2"), # matches vdec.progoverride=2
# Tunnel mode (BCM tunnel clock locked to HDMI sink)
("media.tunneled-playback.enable","true"),
("media.brcm.tunnel.sessions", "1"),
("media.brcm.hdmi.tunnel", "true"),
("media.brcm.tunnel.clock", "hdmi"),
]
for k,v in brcm_codec:
ADB.setprop(k,v); L.ok(f" {k} = {v}")
L.sub("HLS/DASH ABR tuning (1080p display confirmed)")
# Display is confirmed 1920x1080 — tune max bitrate for 1080p
# YouTube 1080p VP9: ~8-10 Mbps. 4K would be 25 Mbps.
# Cap at 15 Mbps (1080p max + headroom for quality switches)
abr = [
("media.httplive.max-bitrate", "15000000"), # 15Mbps (1080p confirmed)
("media.httplive.initial-bitrate", "5000000"), # 5Mbps initial
("media.httplive.max-live-offset", "60"),
("media.httplive.bw-update-interval", "1000"),
]
for k,v in abr:
ADB.setprop(k,v); L.ok(f" {k} = {v}")
L.ok("Codec pipeline: A15 idiv + MMA + VDec32 + Tunnel Mode ✓")
def suppress_av1(self) -> None:
L.hdr("🚫 AV1 SUPPRESSION")
L.warn("BCM7362 VPU: no AV1 HW decoder (CONFIRMED). SW decode = 100% CPU on A15.")
for k,v in [
("debug.stagefright.c2.av1", "0"),
("media.av1.sw.decode.disable", "true"),
("media.codec.av1.disable", "true"),
]:
cur = ADB.prop(k)
if cur != v: ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else: L.ok(f"{k} = {v}")
L.ok("AV1 blocked — ExoPlayer will negotiate VP9 HW path")
def rendering(self) -> None:
L.hdr("🎮 RENDERING — VideoCore + V3D (hardware-verified)")
L.info(f" V3D fence.expose=TRUE (explicit sync ON) → disable_backpressure effective")
L.info(f" V3D buffer_age=FALSE (vendor-disabled, do NOT re-enable)")
L.info(f" HWC2.tweak.fbcomp=1 (FB compositor tweak active)")
L.info(f" Triple buffer ENABLED (ro.sf.disable_triple_buffer=0)")
render_props = [
# Already confirmed correct — verify + enforce
("debug.hwui.renderer", "skiagl"), # OpenGL, no Vulkan
("debug.renderengine.backend", "skiaglthreaded"), # 2-thread render
("debug.egl.hw", "1"),
("debug.sf.hw", "1"),
("debug.gr.numframebuffers", "3"), # triple buffer
("debug.hwui.use_gpu_pixel_buffers", "true"),
("debug.hwui.render_dirty_regions", "false"),
("debug.sf.latch_unsignaled", "1"),
("debug.sf.disable_backpressure", "1"),
("debug.hwui.use_buffer_age", "false"), # matches V3D vendor flag
# Increased layer cache: V3D fence.expose=true allows pipelining
# 32KB (32768 tiles) fits VideoCore texture cache budget
("debug.hwui.layer_cache_size", "32768"), # was 16384
("debug.hwui.profile", "false"), # no profiling overhead
# FIXED: persist.sys.ui.hw was false on device
("persist.sys.ui.hw", "true"),
]
for k,v in render_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
ADB.sput("global","force_gpu_rendering","true")
L.ok(" force_gpu_rendering = true")
L.ok("Rendering: skiaglthreaded + V3D explicit fence + 32KB tile cache ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 2 — DALVIK/ART HEAP (precise, OEM-aware)
# ─────────────────────────────────────────────────────────────────────────────
class DalvikHeap:
"""
PRECISION vs v12:
- heapsize=512m: OEM default — CORRECT, do not shrink to 256m
- heapgrowthlimit=192m: OEM default — CORRECT, do not shrink to 128m
- heapminfree: 512k → 2m (CRITICAL FIX — prevents GC micro-pauses)
- heapmaxfree: 8m → 16m (reduces GC frequency during streaming)
- dex2oat-Xmx: confirmed at 512m — no change needed
- isa.arm.features: default → default,idiv (done in VideoEngine)
Memory budget calculation (real data):
Userspace: ~1045MB available
SmartTube (4K streaming): ~300MB heap + 50MB native
Chromecast GMS+mediashell: ~80MB
TV Launcher: ~40MB
System services: ~150MB
Available: ~425MB headroom — heapsize=512m is fine
"""
def apply(self) -> None:
L.hdr("🧠 DALVIK/ART — A15 Heap (OEM-aware, GC-optimized)")
L.info(f" Memory budget: {HW.USERSPACE_BUDGET_MB}MB userspace")
L.info(f" OEM heapsize={HW.DALVIK_HEAPSIZE} growthlimit={HW.DALVIK_GROWTHLIMIT} — PRESERVED")
heap_ops = [
# These OEM values are CORRECT — do not reduce
("dalvik.vm.heapsize", HW.DALVIK_HEAPSIZE, False), # 512m
("dalvik.vm.heapgrowthlimit", HW.DALVIK_GROWTHLIMIT, False), # 192m
("dalvik.vm.heapstartsize", HW.DALVIK_STARTSIZE, False), # 16m
# FIXES
("dalvik.vm.heapminfree", HW.DALVIK_HEAPMINFREE, True), # 512k→2m
("dalvik.vm.heapmaxfree", HW.DALVIK_HEAPMAXFREE, True), # 8m→16m
("dalvik.vm.heaptargetutilization", HW.DALVIK_TARGET_UTIL, False),
# Runtime
("dalvik.vm.usejit", "true", False),
("dalvik.vm.usejitprofiles", "true", False),
("dalvik.vm.dex2oat-filter", "speed-profile", False),
("dalvik.vm.gctype", "CMS", False), # concurrent GC
("persist.sys.dalvik.vm.lib.2", "libart.so", False),
]
for k,v,is_fix in heap_ops:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v)
if is_fix:
L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
else:
L.ok(f"{k} = {v} ✓")
# WebView VM: reduce for TV STB (no browser, 100MB → 50MB saves for SmartTube)
wv_cur = ADB.prop("persist.sys.webview.vmsize")
L.info(f" WebView vmsize current: {int(wv_cur)//1048576 if wv_cur.isdigit() else wv_cur}MB")
ADB.setprop("persist.sys.webview.vmsize","52428800")
L.fix(f" webview.vmsize: {wv_cur} → 52428800 (50MB, TV STB no browser)")
L.ok(f"Dalvik heap: GC minfree 512k→2m + maxfree 8m→16m ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 3 — LMK (PSI-only, minfree /sys DISABLED on this device)
# ─────────────────────────────────────────────────────────────────────────────
class LMKOptimizer:
"""
CRITICAL: ro.lmk.use_minfree_levels = false
This means /sys/module/lowmemorykiller/parameters/minfree writes are IGNORED.
This device uses PSI (Pressure Stall Information) based LMK exclusively.
PSI-only LMK tuning parameters:
- ro.lmk.upgrade_pressure: 100 → 50 (promote cached processes sooner)
- ro.lmk.downgrade_pressure: 100 → 80 (less aggressive downgrade)
- sys.sysctl.extra_free_kbytes: adjust zone watermark
- OOM score adjustments via /proc/<pid>/oom_score_adj
Confirmed PSI-based LMK state from getprop:
- ro.lmk.use_psi: confirmed via ro.lmk.use_minfree_levels=false
- ro.lmk.low=1001 | medium=800 | critical=0
- ro.lmk.debug=true (logging enabled)
"""
def apply(self) -> None:
L.hdr("🧹 LMK — PSI-Only Profile (minfree /sys DISABLED on this device)")
L.warn("ro.lmk.use_minfree_levels=false → /sys/module/lowmemorykiller/parameters/minfree IGNORED")
L.info("Using PSI-based thresholds only.")
# PSI LMK props
lmk_props = [
("ro.lmk.critical", "0"), # kill only at true critical (confirmed)
("ro.lmk.kill_heaviest_task", "true"), # confirmed correct
("ro.lmk.downgrade_pressure", "80"), # relaxed from 100 (less aggressive)
("ro.lmk.upgrade_pressure", str(HW.LMK_UPGRADE_PRESSURE)), # 100 → 50 FIX
("ro.lmk.use_minfree_levels", "false"), # confirm — do not change
("ro.lmk.use_psi", "true"), # explicit PSI enable
("ro.lmk.filecache_min_kb", "51200"), # 50MB file cache floor
]
for k,v in lmk_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
# extra_free_kbytes: zone watermark
# Current: 24300 (~23.7MB). Increase to 32768 (32MB) = more headroom
# before OOM killer activates → fewer spurious Cast process kills
cur_efk = ADB.sh("getprop sys.sysctl.extra_free_kbytes",silent=True)
ADB.setprop("sys.sysctl.extra_free_kbytes","32768")
L.fix(f"extra_free_kbytes: {cur_efk} → 32768 (32MB zone watermark)")
ADB.sput("global","background_process_limit","3")
L.ok(" background_process_limit = 3 (SmartTube + Cast + Launcher)")
# OOM score adjustments
L.sub("OOM score — Cast process hardening")
self._harden_oom()
L.ok("PSI LMK profile applied: upgrade_pressure=50, watermark=32MB ✓")
def _harden_oom(self) -> None:
protected_procs = [
HW.PKG_MEDIASHELL,
"com.google.android.gms",
"com.google.android.nearby",
]
for pkg in protected_procs:
pid = ADB.sh(f"pidof {pkg}",silent=True).strip()
if pid and pid.isdigit():
ADB.root(f"echo 100 > /proc/{pid}/oom_score_adj")
L.cast(f"OOM adj=100: {pkg} (PID {pid})")
else:
L.info(f" {pkg.split('.')[-2]} not running — protected at next start")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 4 — NETWORK (kernel 4.9.190, no BBR)
# ─────────────────────────────────────────────────────────────────────────────
class NetworkOptimizer:
"""
Kernel 4.9.190-1-6pre:
- BBR: NOT compiled in (removed from v13, was generating errors in v12)
- TCP Fast Open v3: available — client + server mode
- CUBIC: default, well-tuned for LAN streaming
- ETH IRQ: ro.nx.eth.irq_mode_mask=3:2 (IRQ coalescing mode 3 on port 2)
DNS dual-path (CRITICAL FIX from v12):
Path 1: setprop net.dns1/net.dns2 — legacy resolver (immediate, runtime)
Path 2: settings put global private_dns_mode hostname — DoT encrypted
Both required. DoT host: 'one.one.one.one' NOT 'dns.cloudflare.com'
mDNS (.local/Cast port 5353 multicast) is UNAFFECTED by either path.
"""
def apply_tcp(self) -> None:
L.hdr("🌐 NETWORK — TCP/IP (Kernel 4.9.190, no BBR)")
L.cast("mDNS (Cast discovery, port 5353) UNAFFECTED by TCP/DNS changes")
# Android-level TCP
ADB.sput("global","net.tcp.buffersize.wifi",
"262144,1048576,2097152,131072,524288,1048576")
L.ok(" WiFi TCP: 256KB/1MB/2MB")
ADB.sput("global","net.tcp.buffersize.ethernet",
"524288,2097152,4194304,262144,1048576,2097152")
L.ok(" Ethernet TCP: 512KB/2MB/4MB")
# FIXED: net.tcp.default_init_rwnd = 60 → 120
cur = ADB.prop("net.tcp.default_init_rwnd")
ADB.sput("global","tcp_default_init_rwnd","120")
ADB.setprop("net.tcp.default_init_rwnd","120")
L.fix(f" tcp init rwnd: {cur} → 120")
# Kernel TCP params (4.9 supports all of these)
kernel_tcp = [
("/proc/sys/net/ipv4/tcp_window_scaling", "1"),
("/proc/sys/net/ipv4/tcp_timestamps", "1"),
("/proc/sys/net/ipv4/tcp_sack", "1"),
# Fast Open: 3 = client+server mode (supported in 4.9+)
("/proc/sys/net/ipv4/tcp_fastopen", "3"),
("/proc/sys/net/ipv4/tcp_keepalive_intvl", "30"),
("/proc/sys/net/ipv4/tcp_keepalive_probes", "3"),
("/proc/sys/net/ipv4/tcp_no_metrics_save", "1"),
# CUBIC is optimal for 4.9 without BBR — tune FQ
("/proc/sys/net/ipv4/tcp_congestion_control","cubic"),
]
for path,val in kernel_tcp:
ok = ADB.sysw(path,val)
L.ok(f" ✓ {path.split('/')[-1]} = {val}") if ok else \
L.warn(f" ⚠ {path.split('/')[-1]} = {val} (sysctl not writable)")
# Net core buffers 16MB
for p in ("/proc/sys/net/core/rmem_max","/proc/sys/net/core/wmem_max"):
ADB.sysw(p,"16777216")
L.ok(" net/core rmem/wmem_max = 16MB")
# WiFi stability
ADB.setprop("wifi.supplicant_scan_interval","300")
ADB.sput("global","wifi_sleep_policy","2")
ADB.sput("global","wifi_power_save","0")
ADB.setprop("persist.debug.wfd.enable","1")
L.ok(" WiFi: scan=300s, sleep_policy=2, power_save=0, WFD=1")
# mDNS Cast reliability
ADB.setprop("ro.mdns.enable_passive_mode","false")
ADB.setprop("net.ssdp.ttl","4")
L.ok(" mDNS: active response mode, SSDP TTL=4")
L.ok("TCP stack: TCP_FO v3 + CUBIC + 16MB bufs + init_rwnd=120 ✓")
def set_dns(self, provider:str="cloudflare") -> None:
info = HW.DNS.get(provider.lower())
if not info:
L.err(f"Unknown DNS provider: {provider}")
L.info(f" Available: {', '.join(HW.DNS)}")
return
dot,ip1,ip2 = info
L.hdr(f"🔒 DNS — {provider.upper()} ({dot})")
L.cast("mDNS (Chromecast discovery) is UNAFFECTED — unicast DNS only")
# Path 1: legacy resolver (immediate, no reboot)
for k,v in [("net.dns1",ip1),("net.dns2",ip2),
("net.rmnet0.dns1",ip1),("net.rmnet0.dns2",ip2)]:
ADB.setprop(k,v)
L.ok(f" Legacy DNS: {ip1} / {ip2}")
# Path 2: Private DNS over TLS (persists reboots)
# CORRECTED: 'dns.cloudflare.com' was v10/v11 bug
# Correct hostname: 'one.one.one.one' (resolves to 1.1.1.1)
ADB.sput("global","private_dns_mode","hostname")
ADB.sput("global","private_dns_specifier",dot)
L.ok(f" Private DNS (DoT): {dot}")
# Flush unicast DNS cache
ADB.sh("ndc resolver flushnet 100",silent=True)
ADB.sh("ndc resolver clearnetdns 100",silent=True)
L.ok(" DNS cache flushed")
# Test
ping = ADB.sh(f"ping -c 2 -W 3 {ip1}",silent=True)
if "2 received" in ping:
L.ok(f" Connectivity: {ip1} reachable ✓")
else:
L.warn(f" Ping inconclusive — DoT may still function")
def dns_menu(self) -> None:
L.hdr("🔒 DNS PROVIDER SELECTION")
providers = list(HW.DNS.keys())
for i,name in enumerate(providers,1):
dot,ip1,ip2 = HW.DNS[name]
L.info(f" {i}. {name.upper():12} DoT: {dot:30} IPs: {ip1}/{ip2}")
L.info(" 0. Keep current")
c = L.C
ch = input(f"\n{c['c']}Select [0-{len(providers)}] > {c['r']}").strip()
if ch=="0": return
try:
idx = int(ch)-1
if 0<=idx<len(providers): self.set_dns(providers[idx])
else: L.warn("Invalid")
except ValueError: L.warn("Invalid")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 5 — HDMI + CEC + AUDIO (BCM Nexus-verified)
# ─────────────────────────────────────────────────────────────────────────────
class HDMIAudio:
"""
All props verified against real getprop output.
Fixed:
- persist.sys.hdmi.keep_awake = false → true (was wrong on device)
Confirmed correct (keep):
- persist.sys.hdmi.addr.playback = 11 (BCM Nexus playback device addr)
- persist.sys.cec.status = true
- persist.nx.hdmi.tx_standby_cec = 1
- persist.nx.hdmi.tx_view_on_cec = 1
- persist.nx.vidout.50hz = 0 (locale=pl-PL, 50Hz disabled — see note below)
PAL 50Hz note: locale=pl-PL, timezone=Europe/Amsterdam.
Polish DVB-T content is 25fps. Orange PLAY IPTV uses adaptive rate.
persist.nx.vidout.50hz=0 is correct for HDMI 2.0a sink auto-rate switching.
Only enable if experiencing 25/50fps PAL content stutter.
Audio offload: disabled (BCM7362 HDMI ARC desync root cause confirmed).
vendor.audio-hal-2-0 running — deep buffer path active.
audio.brcm.hdmi.clock_lock=true — locks audio clock to HDMI sink.
"""
def apply_hdmi(self) -> None:
L.hdr("📺 HDMI + CEC — BCM Nexus (addr=11, CEC v1.4 confirmed)")
hdmi_props = [
# Device type 4 = playback device (confirmed ro.hdmi.device_type=4)
("ro.hdmi.device_type", "4"),
# addr.playback=11 confirmed correct in getprop
("persist.sys.hdmi.addr.playback", "11"),
# CEC (all confirmed in getprop)
("persist.sys.cec.status", "true"),
("persist.sys.hdmi.tx_standby_cec", "1"),
("persist.sys.hdmi.tx_view_on_cec", "1"),
("persist.sys.hdmi.cec_enabled", "1"),
# BCM Nexus CEC (confirmed in getprop)
("persist.nx.hdmi.tx_standby_cec", "1"),
("persist.nx.hdmi.tx_view_on_cec", "1"),
# FIXED: was false on device!
("persist.sys.hdmi.keep_awake", "true"),
# HDR10
("persist.sys.hdr.enable", "1"),
# No HDMI hotplug reset
("ro.hdmi.wake_on_hotplug", "false"),
("persist.sys.media.avsync", "true"),
]
for k,v in hdmi_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v} ✓")
# 50Hz — PAL region check
hz50 = ADB.prop("persist.nx.vidout.50hz")
L.info(f" 50Hz mode: {hz50} (pl-PL locale, HDMI auto-rate switching = correct)")
# CEC settings namespace
ADB.sput("global","hdmi_cec_enabled","1")
L.ok(" hdmi_cec_enabled = 1")
L.ok("HDMI: keep_awake=TRUE + CEC v1.4 + BCM Nexus addr=11 ✓")
def apply_audio(self) -> None:
L.hdr("🔊 AUDIO — A/V Sync (BCM7362 HDMI ARC desync fix)")
L.info(" Root cause: audio offload path uses BCM proprietary timing")
L.info(" that disagrees with HDMI ARC → drift 50-200ms over time.")
L.info(" vendor.audio-hal-2-0 RUNNING (confirmed in init.svc)")
audio_props = [
# Disable offload (desync root cause)
("audio.offload.disable", "1"),
("audio.offload.video", "0"),
("tunnel.audio.encode", "false"),
# Deep buffer: stable 20ms latency baseline
("audio.deep_buffer.media", "true"),
("af.fast_track_multiplier", "1"),
# BCM HDMI clock lock (eliminates slow drift)
("audio.brcm.hdmi.clock_lock", "true"),
("audio.brcm.hal.latency", "20"),
]
for k,v in audio_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
L.ok("Audio: offload disabled + HDMI clock locked ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 6 — SYSTEM RESPONSIVENESS (I/O + CPU + animations)
# ─────────────────────────────────────────────────────────────────────────────
class Responsiveness:
def apply(self, anim:float=0.5) -> None:
L.hdr(f"🎨 RESPONSIVENESS — I/O + A15 CPU + Animations")
# Animations (0.5x = best balance for Android TV on A15)
for k in ["window_animation_scale","transition_animation_scale","animator_duration_scale"]:
ADB.sput("global",k,str(anim)); L.ok(f" {k} = {anim}x")
# TV recommendations off (saves CPU polling + ~40MB RAM)
ADB.sh("settings put secure tv_disable_recommendations 1",silent=True)
ADB.sh("settings put secure tv_enable_preview_programs 0",silent=True)
ADB.sh("settings put secure tv_watch_next_enabled 0",silent=True)
L.ok(" TV recommendations: disabled")
# Logging reduction
ADB.setprop("persist.logd.size","32768")
ADB.setprop("log.tag.stats_log","OFF")
ADB.setprop("log.tag.statsd","OFF")
L.ok(" Log buffer: 32KB, stats logging OFF")
# I/O scheduler: deadline for eMMC (low-latency VP9 segment reads)
ADB.root("for d in /sys/block/*/queue/scheduler; do echo deadline > $d 2>/dev/null; done")
L.ok(" I/O scheduler: deadline (all block devices)")
# Read-ahead: 512KB (VP9 segment prefetch, fits VP9 tile stream)
ADB.root("for d in /sys/block/*/queue/read_ahead_kb; do echo 512 > $d 2>/dev/null; done")
L.ok(" read_ahead_kb: 512")
# CPU governor: performance on both A15 cores
for cpu in range(2):
path = f"/sys/devices/system/cpu/cpu{cpu}/cpufreq/scaling_governor"
ADB.root(f"echo performance > {path}")
L.ok(f" cpu{cpu}: performance governor (A15 @ full ~1.0GHz)")
# Profiler off
ADB.setprop("persist.sys.profiler_ms","0")
ADB.setprop("persist.sys.strictmode.visual","")
L.ok("Responsiveness: deadline I/O + A15 performance governor + 0.5x anim ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 7 — SAFE DEBLOAT (Cast gate enforced)
# ─────────────────────────────────────────────────────────────────────────────
DEBLOAT_DB: List[Tuple[str,str]] = [
# Confirmed safe based on init.svc.* from getprop (none of these appear)
("com.google.android.backdrop", "Ambient screensaver — idle GPU + ~30MB"),
("com.google.android.tvrecommendations", "Recommendations — HTTP polling"),
("com.google.android.katniss", "Voice overlay — high idle CPU on A15"),
("com.google.android.tungsten.setupwraith","Setup wizard — done"),
("com.google.android.marvin.talkback", "TTS accessibility — 40MB unused"),
("com.google.android.onetimeinitializer","One-time init — completed"),
("com.google.android.feedback", "Feedback service — periodic ping"),
("com.google.android.speech.pumpkin", "Hotword detection — CPU drain"),
("com.android.printspooler", "Print service — no printers on TV"),
("com.android.dreams.basic", "Basic screensaver"),
("com.android.dreams.phototable", "Photo screensaver"),
("com.android.providers.calendar", "Calendar — unused on TV"),
("com.android.providers.contacts", "Contacts — unused on TV"),
("com.sagemcom.stb.setupwizard", "Sagemcom factory setup — done"),
("com.google.android.play.games", "Play Games — unused on TV"),
("com.google.android.videos", "Play Movies — unused on TV"),
("com.amazon.amazonvideo.livingroom", "Amazon Prime — use standalone APK"),
]
class SafeDebloat:
def run(self) -> None:
L.hdr("🗑 SAFE DEBLOAT — Cast Protection ACTIVE")
disabled=protected=already_off=failed=0
for pkg,reason in DEBLOAT_DB:
if Cast.is_protected(pkg):
protected+=1
L.cast(f"PROTECTED: {pkg}")
L.dim(Cast.reason(pkg))
continue
if not ADB.pkg_ok(pkg):
already_off+=1; continue
r = ADB.sh(f"pm disable-user --user 0 {pkg}",silent=True)
if "disabled" in r.lower() or not r:
disabled+=1; L.ok(f"Disabled: {pkg}")
L.dim(reason)
else:
failed+=1; L.warn(f"Could not disable: {pkg}")
L.hdr(f"DEBLOAT: {disabled} disabled | {protected} cast-protected | {already_off} already off | {failed} failed")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 8 — CHROMECAST SERVICE MANAGER
# ─────────────────────────────────────────────────────────────────────────────
class CastManager:
"""
mdnsd: confirmed RUNNING (init.svc.mdnsd=running from getprop).
mediashell: was in device's debloat.sh kill-list — WRONG. Protected here.
"""
@staticmethod
def audit() -> Dict[str,bool]:
L.hdr("🔍 CHROMECAST AUDIT")
L.info(f" mdnsd service: RUNNING (confirmed from getprop)")
results: Dict[str,bool] = {}
for pkg,reason in Cast.PROTECTED.items():
ok = ADB.pkg_ok(pkg)
results[pkg] = ok
(L.ok if ok else L.err)(f" {'✓' if ok else '✗'} {pkg}")
L.dim(reason)
broken = [p for p,e in results.items() if not e]
if broken:
L.warn(f"{len(broken)} Cast service(s) DISABLED — use option 7 to restore")
else:
L.ok("All Chromecast services healthy ✓")
return results
@staticmethod
def restore() -> None:
L.hdr("🛡 CHROMECAST RESTORATION")
for pkg in Cast.PROTECTED:
ADB.sh(f"pm enable {pkg}",silent=True)
ADB.sh(f"pm enable --user 0 {pkg}",silent=True)
L.cast(f"Ensured: {pkg}")
L.ok("All Cast services re-enabled ✓")
@staticmethod
def network() -> None:
L.sub("Cast mDNS network tuning")
ADB.sput("global","wifi_sleep_policy","2")
ADB.sput("global","wifi_power_save","0")
ADB.setprop("ro.mdns.enable_passive_mode","false")
ADB.setprop("net.ssdp.ttl","4")
L.ok("Cast mDNS: active response + WiFi always-on ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 9 — AOT COMPILER
# ─────────────────────────────────────────────────────────────────────────────
class AOT:
"""
Confirmed packages from real ps output:
- org.smarttube.stable (u0_a89, PID 6624)
- com.spocky.projengmenu Projectivy (u0_a88, PID 26563)
- com.google.android.apps.mediashell (cast daemon)
- com.google.android.gms.persistent (u0_a12, PID 26127)
dex2oat-Xmx=512m confirmed — speed-profile AOT uses full budget.
"""
APPS: Dict[str,str] = {
HW.PKG_SMARTTUBE_STABLE: "SmartTube Stable",
HW.PKG_PROJECTIVY: "Projectivy Launcher",
HW.PKG_MEDIASHELL: "Cast Daemon (mediashell)",
"com.google.android.gms": "GMS (Cast SDK)",
}
@classmethod
def compile_all(cls) -> None:
L.hdr("⚡ AOT COMPILATION — Eliminate JIT bursts on A15 dual-core")
L.info(f" dex2oat budget: -Xmx {HW.DEX2OAT_XMX} (confirmed)")
for pkg,name in cls.APPS.items():
if not ADB.pkg_exists(pkg):
L.dim(f"{name}: not installed — skip"); continue
L.info(f" Compiling {name} (speed-profile)... ~60-90s")
r = ADB.sh(f"cmd package compile -m speed-profile -f {pkg}",silent=True)
if "success" in r.lower():
L.ok(f" {name}: compiled (speed-profile)")
else:
ADB.sh(f"cmd package compile -m speed -f {pkg}",silent=True)
L.ok(f" {name}: compiled (speed fallback)")
# ─────────────────────────────────────────────────────────────────────────────
# DIAGNOSTIC ENGINE (precision — hardware-aware)
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class DResult:
cat:str; check:str; status:Status
found:str; expected:str=""; fix_fn=None; detail:str=""
@property
def bad(self)->bool: return self.status in (Status.BROKEN,Status.MISSING)
class Diag:
"""
8-category interactive self-diagnostics.
Each check is hardware-grounded (values from real getprop).
"""
def __init__(self):
self.results: List[DResult] = []
def _r(self,cat,check,status,found,expected="",fix_fn=None,detail="") -> DResult:
d=DResult(cat,check,status,found,expected,fix_fn,detail)
self.results.append(d); return d
# ── A: System Health ────────────────────────────────────────────────────
def check_system(self) -> List[DResult]:
res=[]; cat="SYS"
mem = ADB.sh("cat /proc/meminfo",silent=True)
fields={l.split()[0].rstrip(":"):int(l.split()[1])
for l in mem.splitlines() if len(l.split())>=2 and l.split()[1].isdigit()}
avail_mb = fields.get("MemAvailable",0)//1024
total_mb = fields.get("MemTotal",0)//1024
pct = avail_mb/total_mb*100 if total_mb else 0
s = Status.OK if pct>30 else (Status.WARN if pct>15 else Status.BROKEN)
res.append(self._r(cat,"RAM Available",s,f"{avail_mb}MB ({pct:.0f}%)",">30% OK",
None,f"Total:{total_mb}MB | Nexus:{HW.NX_HEAP_TOTAL}MB reserved"))
# Kernel version
kver = ADB.sh("uname -r",silent=True)
res.append(self._r(cat,"Kernel",Status.OK,kver,HW.KERNEL_VER))
# CPU variant
variant = ADB.prop("dalvik.vm.isa.arm.variant")
res.append(self._r(cat,"CPU ISA variant",Status.OK if variant==HW.ISA_VARIANT else Status.WARN,
variant,HW.ISA_VARIANT))
# Thermal
for z in range(2):
raw = ADB.sh(f"cat /sys/class/thermal/thermal_zone{z}/temp",silent=True)
if raw and raw.lstrip("-").isdigit():
temp = int(raw)/1000
s = Status.OK if temp<60 else (Status.WARN if temp<75 else Status.BROKEN)
res.append(self._r(cat,f"Thermal zone{z}",s,f"{temp:.1f}°C","<60°C"))
# Storage
df = ADB.sh("df -h /data",silent=True).splitlines()
if len(df)>1:
parts=df[1].split()
pct_str=parts[4] if len(parts)>4 else "?"
use=int(pct_str.replace("%","")) if pct_str!="?" else 0
s=Status.OK if use<80 else (Status.WARN if use<90 else Status.BROKEN)
res.append(self._r(cat,"/data storage",s,pct_str,"<80%"))
# Internet
ping=ADB.sh("ping -c 2 -W 3 1.1.1.1",silent=True)
res.append(self._r(cat,"Internet",
Status.OK if "2 received" in ping else Status.BROKEN,
"OK" if "2 received" in ping else "OFFLINE"))
# mdnsd (critical for Cast discovery)
mdns=ADB.sh("getprop init.svc.mdnsd",silent=True)
res.append(self._r(cat,"mdnsd (Cast discovery)",
Status.OK if mdns=="running" else Status.BROKEN,
mdns,"running"))
return res
# ── B: Cast Services ────────────────────────────────────────────────────
def check_cast(self) -> List[DResult]:
res=[]; cat="CAST"
for pkg,reason in Cast.PROTECTED.items():
ok=ADB.pkg_ok(pkg)
res.append(self._r(cat,pkg.split(".")[-1],
Status.OK if ok else Status.BROKEN,
"enabled" if ok else "DISABLED","enabled",
CastManager.restore,reason))
return res
# ── C: SmartTube ────────────────────────────────────────────────────────
def check_smarttube(self) -> List[DResult]:
res=[]; cat="STUBE"
found_pkg=next((p for p in [HW.PKG_SMARTTUBE_STABLE,HW.PKG_SMARTTUBE_BETA,HW.PKG_SMARTTUBE_LEGACY]
if ADB.pkg_exists(p)),None)
if found_pkg:
ver=ADB.pkg_ver(found_pkg)
res.append(self._r(cat,"Installed",Status.OK,f"{found_pkg} v{ver}"))
# Old package migration check
if found_pkg==HW.PKG_SMARTTUBE_LEGACY:
res.append(self._r(cat,"Package name",Status.WARN,
"Legacy package (com.liskovsoft.*)",
"org.smarttube.stable",None,
"New SmartTube uses org.smarttube.stable"))
else:
res.append(self._r(cat,"Installed",Status.MISSING,"NOT INSTALLED",
HW.PKG_SMARTTUBE_STABLE,
lambda: APK.fetch_install(HW.URL_SMARTTUBE_STABLE,
HW.PKG_SMARTTUBE_STABLE,"SmartTube Stable")))
# Codec props
ve=VideoEngine()
for prop,exp in [("media.vcodec.preferhw","true"),
("debug.stagefright.ccodec","1"),
("media.tunneled-playback.enable","true"),
("media.codec.av1.disable","true"),
("media.brcm.mma.enable","1"),
("dalvik.vm.isa.arm.features",HW.ISA_FEATURES_OPT)]:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ve.codec_pipeline))
return res
# ── D: Video Pipeline ───────────────────────────────────────────────────
def check_video(self) -> List[DResult]:
res=[]; cat="VIDEO"; ve=VideoEngine()
checks=[
("debug.hwui.renderer", "skiagl"),
("debug.renderengine.backend", "skiaglthreaded"),
("debug.sf.hw", "1"),
("debug.gr.numframebuffers", "3"),
("debug.hwui.layer_cache_size", "32768"), # updated for V3D
("persist.sys.ui.hw", "true"), # was false!
("debug.sf.latch_unsignaled", "1"),
("debug.sf.disable_backpressure", "1"),
("media.stagefright.cache-params", "65536/131072/30"), # was wrong
("media.brcm.vpu.buffers", str(HW.VDEC_OUTPORT_BUFFERS)),
]
for prop,exp in checks:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ve.rendering))
return res
# ── E: Network + DNS ────────────────────────────────────────────────────
def check_network(self) -> List[DResult]:
res=[]; cat="NET"; no=NetworkOptimizer()
dot_host=ADB.sget("global","private_dns_specifier")
dot_mode=ADB.sget("global","private_dns_mode")
ip1=ADB.prop("net.dns1")
valid_dots=[v[0] for v in HW.DNS.values()]
dns_ok=dot_host in valid_dots and dot_mode=="hostname"
res.append(self._r(cat,"Private DNS (DoT)",
Status.OK if dns_ok else Status.BROKEN,
f"mode={dot_mode}, host={dot_host}",
"hostname + one.one.one.one",
lambda: no.set_dns("cloudflare"),
f"Legacy net.dns1={ip1}"))
# Detect old wrong hostname
if dot_host=="dns.cloudflare.com":
res.append(self._r(cat,"DNS hostname (v10/v11 bug)",Status.BROKEN,
"dns.cloudflare.com (WRONG — will fail DoT handshake)",
"one.one.one.one",lambda: no.set_dns("cloudflare")))
rwnd=ADB.prop("net.tcp.default_init_rwnd")
res.append(self._r(cat,"TCP init rwnd",
Status.OK if rwnd=="120" else Status.WARN,
rwnd or "not set","120",no.apply_tcp))
tfo=ADB.sh("cat /proc/sys/net/ipv4/tcp_fastopen",silent=True).strip()
res.append(self._r(cat,"TCP Fast Open",
Status.OK if tfo=="3" else Status.WARN,
tfo or "not set","3 (client+server)"))
return res
# ── F: Audio ────────────────────────────────────────────────────────────
def check_audio(self) -> List[DResult]:
res=[]; cat="AUDIO"; ha=HDMIAudio()
for prop,exp in [("audio.offload.disable","1"),
("audio.deep_buffer.media","true"),
("audio.brcm.hdmi.clock_lock","true"),
("tunnel.audio.encode","false"),
("persist.sys.hdmi.keep_awake","true")]: # was false!
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ha.apply_audio))
return res
# ── G: Memory + LMK ─────────────────────────────────────────────────────
def check_memory(self) -> List[DResult]:
res=[]; cat="MEM"
mo=DalvikHeap(); lm=LMKOptimizer()
# Dalvik: check OEM values preserved + fixes applied
for prop,exp,fn in [
("dalvik.vm.heapsize", HW.DALVIK_HEAPSIZE, mo.apply), # 512m
("dalvik.vm.heapgrowthlimit",HW.DALVIK_GROWTHLIMIT, mo.apply), # 192m
("dalvik.vm.heapminfree", HW.DALVIK_HEAPMINFREE, mo.apply), # 2m
("dalvik.vm.heapmaxfree", HW.DALVIK_HEAPMAXFREE, mo.apply), # 16m
("dalvik.vm.usejit", "true", mo.apply),
("ro.lmk.upgrade_pressure",str(HW.LMK_UPGRADE_PRESSURE),lm.apply), # 50
("ro.lmk.kill_heaviest_task","true", lm.apply),
]:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,fn))
# PSI LMK confirmation
minfree_lvl=ADB.prop("ro.lmk.use_minfree_levels")
res.append(self._r(cat,"LMK use_minfree_levels",
Status.OK if minfree_lvl=="false" else Status.WARN,
minfree_lvl,"false (PSI-only = correct on this device)"))
return res
# ── H: HDMI + CEC ───────────────────────────────────────────────────────
def check_hdmi(self) -> List[DResult]:
res=[]; cat="HDMI"; ha=HDMIAudio()
for prop,exp in [
("persist.sys.cec.status", "true"),
("persist.sys.hdmi.addr.playback", "11"), # BCM Nexus confirmed
("persist.sys.hdmi.keep_awake", "true"), # was false!
("persist.nx.hdmi.tx_standby_cec", "1"),
("persist.nx.hdmi.tx_view_on_cec", "1"),
("persist.sys.hdr.enable", "1"),
]:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ha.apply_hdmi))
return res
# ── Run category ────────────────────────────────────────────────────────
def run_cat(self, cat_id:str) -> List[DResult]:
fns = {"A":("System Health", self.check_system),
"B":("Cast Services", self.check_cast),
"C":("SmartTube", self.check_smarttube),
"D":("Video Pipeline", self.check_video),
"E":("Network/DNS", self.check_network),
"F":("Audio", self.check_audio),
"G":("Memory/LMK", self.check_memory),
"H":("HDMI/CEC", self.check_hdmi)}
entry=fns.get(cat_id.upper())
if not entry: return []
name,fn=entry
L.hdr(f"🔎 DIAG [{cat_id}] — {name}")
results=fn()
self._print(results)
return results
def _print(self, results:List[DResult]) -> None:
ok=sum(1 for r in results if r.status==Status.OK)
bad=sum(1 for r in results if r.bad)
for r in results:
if r.status==Status.OK:
L.ok(f"[{r.cat}] {r.check}: {r.found}")
elif r.status==Status.WARN:
L.warn(f"[{r.cat}] {r.check}: {r.found} (expected: {r.expected})")
else:
L.err(f"[{r.cat}] {r.check}: {r.found} (expected: {r.expected})")
if r.detail: L.dim(r.detail)
L.info(f"\n Results: {ok} OK | {bad} NEED REPAIR")
def run_all(self) -> None:
L.hdr("🔎 INTERACTIVE DIAGNOSTICS — 8 Hardware-Targeted Categories")
cat_names={
"A":"System Health","B":"Cast Services","C":"SmartTube",
"D":"Video Pipeline","E":"Network/DNS","F":"Audio",
"G":"Memory/LMK","H":"HDMI/CEC"
}
all_bad: List[DResult] = []
for cid,cname in cat_names.items():
L.info(f"\n[{cid}] {cname}")
results=self.run_cat(cid)
bad=[r for r in results if r.bad]
all_bad.extend(bad)
if bad:
c=L.C
ch=input(f" {c['w']}{len(bad)} issue(s). Repair? [Y/n/s=skip all] > {c['r']}").strip().lower()
if ch=="s": break
if ch in ("","y"): self._repair(bad)
else:
L.ok(f" {cname}: ALL OK ✓")
# Summary
L.hdr("📋 DIAGNOSTIC SUMMARY")
total=len(self.results); ok=sum(1 for r in self.results if r.status==Status.OK)
bad=sum(1 for r in self.results if r.bad)
warn=sum(1 for r in self.results if r.status==Status.WARN)
L.ok(f" {ok}/{total} OK"); L.warn(f" {warn} WARN"); L.err(f" {bad} BROKEN")
if all_bad:
L.warn(" Unresolved:")
for r in all_bad:
if r.bad: L.err(f" [{r.cat}] {r.check}: {r.found}")
def _repair(self, bad:List[DResult]) -> None:
seen:set=set()
for r in bad:
if r.fix_fn and id(r.fix_fn) not in seen:
seen.add(id(r.fix_fn))
L.fix(f"Repairing: [{r.cat}] {r.check}")
try: r.fix_fn()
except Exception as e: L.err(f"Repair error: {e}")
def menu(self) -> None:
c=L.C
cat_map={"A":"System Health","B":"Cast Services","C":"SmartTube",
"D":"Video Pipeline","E":"Network/DNS","F":"Audio",
"G":"Memory/LMK","H":"HDMI/CEC","*":"All (interactive)"}
L.hdr("🔎 DIAGNOSTICS — Select Category")
for k,v in cat_map.items():
L.info(f" {c['c']}{k}{c['r']}. {v}")
ch=input(f"\n{c['c']}Category [A-H or *] > {c['r']}").strip().upper()
if ch=="*":
self.run_all()
elif ch in cat_map:
results=self.run_cat(ch)
bad=[r for r in results if r.bad]
if bad:
fix=input(f"\n{c['w']}Auto-repair {len(bad)} issue(s)? [Y/n] > {c['r']}").strip().lower()
if fix in ("","y"): self._repair(bad)
else:
L.warn("Invalid category")
# ─────────────────────────────────────────────────────────────────────────────
# AUTO REPAIR ENGINE
# ─────────────────────────────────────────────────────────────────────────────
class Repair:
"""
11 repair sectors — all targeted to real device state.
Detection lambdas use actual getprop values as baseline.
"""
REGISTRY: List[Dict] = [
{"id":"smarttube_missing","name":"SmartTube not installed",
"detect": lambda: not ADB.pkg_exists(HW.PKG_SMARTTUBE_STABLE),
"repair": lambda: APK.fetch_install(HW.URL_SMARTTUBE_STABLE,HW.PKG_SMARTTUBE_STABLE,"SmartTube Stable")},
{"id":"smarttube_old_pkg","name":"SmartTube old package (com.teamsmart → org.smarttube)",
"detect": lambda: ADB.pkg_exists("com.teamsmart.videomanager.tv"),
"repair": lambda: APK.fetch_install(HW.URL_SMARTTUBE_STABLE,HW.PKG_SMARTTUBE_STABLE,"SmartTube Stable (migrated)")},
{"id":"cast_mediashell","name":"Cast daemon (mediashell) DISABLED — device debloat.sh damage",
"detect": lambda: not ADB.pkg_ok(HW.PKG_MEDIASHELL),
"repair": CastManager.restore},
{"id":"cast_gms","name":"GMS (Cast SDK) disabled",
"detect": lambda: not ADB.pkg_ok("com.google.android.gms"),
"repair": CastManager.restore},
{"id":"wrong_dns_old","name":"DNS wrong hostname: dns.cloudflare.com (v10/v11 bug)",
"detect": lambda: ADB.sget("global","private_dns_specifier")=="dns.cloudflare.com",
"repair": lambda: NetworkOptimizer().set_dns("cloudflare")},
{"id":"dns_not_set","name":"Private DNS not configured (mode != hostname)",
"detect": lambda: ADB.sget("global","private_dns_mode")!="hostname",
"repair": lambda: NetworkOptimizer().set_dns("cloudflare")},
{"id":"ui_hw_false","name":"persist.sys.ui.hw=false (GPU force rendering disabled)",
"detect": lambda: ADB.prop("persist.sys.ui.hw")!="true",
"repair": lambda: ADB.setprop("persist.sys.ui.hw","true")},
{"id":"hdmi_keep_awake","name":"persist.sys.hdmi.keep_awake=false (HDMI drops during buffering)",
"detect": lambda: ADB.prop("persist.sys.hdmi.keep_awake")!="true",
"repair": lambda: ADB.setprop("persist.sys.hdmi.keep_awake","true")},
{"id":"av1_active","name":"AV1 SW decoder active (100% CPU on A15 — confirmed no HW)",
"detect": lambda: ADB.prop("media.codec.av1.disable")!="true",
"repair": VideoEngine().suppress_av1},
{"id":"idiv_disabled","name":"A15 hardware idiv not enabled in Dalvik ISA features",
"detect": lambda: ADB.prop("dalvik.vm.isa.arm.features")!=HW.ISA_FEATURES_OPT,
"repair": lambda: ADB.setprop("dalvik.vm.isa.arm.features",HW.ISA_FEATURES_OPT)},
{"id":"heap_minfree","name":"dalvik.vm.heapminfree=512k (too small — GC micro-pauses)",
"detect": lambda: ADB.prop("dalvik.vm.heapminfree") not in ("2m",""),
"repair": DalvikHeap().apply},
{"id":"cache_params","name":"media.stagefright.cache-params too small (32768/65536/25)",
"detect": lambda: ADB.prop("media.stagefright.cache-params")=="32768/65536/25",
"repair": lambda: ADB.setprop("media.stagefright.cache-params","65536/131072/30")},
{"id":"tcp_rwnd","name":"net.tcp.default_init_rwnd=60 (half optimal)",
"detect": lambda: ADB.prop("net.tcp.default_init_rwnd") not in ("120",""),
"repair": lambda: (ADB.setprop("net.tcp.default_init_rwnd","120"),
ADB.sput("global","tcp_default_init_rwnd","120"))},
{"id":"lmk_upgrade","name":"ro.lmk.upgrade_pressure=100 (too high — slow cached proc recovery)",
"detect": lambda: ADB.prop("ro.lmk.upgrade_pressure")=="100",
"repair": lambda: ADB.setprop("ro.lmk.upgrade_pressure","50")},
]
@classmethod
def scan(cls) -> None:
L.hdr("🔧 AUTO-REPAIR — Hardware-Targeted Sector Scan")
found: List[Dict] = []
for entry in cls.REGISTRY:
try: detected=entry["detect"]()
except Exception: detected=False
if detected:
found.append(entry)
L.err(f" ✗ BROKEN: {entry['name']}")
else:
L.dim(f"✓ OK: {entry['id']}")
if not found:
L.ok("All sectors healthy — no repairs needed ✓"); return
L.warn(f"\n{len(found)} broken sector(s):")
for i,e in enumerate(found,1):
L.info(f" {i}. {e['name']}")
c=L.C
ch=input(f"\n{c['w']}Repair all {len(found)}? [Y=all / n=select / x=cancel] > {c['r']}").strip().lower()
if ch=="x": return
if ch=="n":
for i,e in enumerate(found,1):
sub=input(f" [{i}] {e['name']}\n Repair? [Y/n] > ").strip().lower()
if sub in ("","y"): cls._do(e)
else:
for e in found: cls._do(e)
L.ok("Auto-repair complete ✓")
@classmethod
def _do(cls,e:Dict)->None:
L.fix(f"Repairing: {e['name']}")
try: e["repair"]()
except Exception as ex: L.err(f"Error: {ex}")
# ─────────────────────────────────────────────────────────────────────────────
# MEMORY DEEP CLEAN
# ─────────────────────────────────────────────────────────────────────────────
def deep_clean() -> None:
L.hdr("🔄 DEEP CLEAN — Cast-Safe")
ADB.sh("am kill-all",silent=True); L.ok(" am kill-all")
ADB.sh("pm trim-caches 2G",silent=True); L.ok(" pm trim-caches 2G")
ADB.sh("dumpsys batterystats --reset",silent=True)
ADB.root("sync && echo 3 > /proc/sys/vm/drop_caches")
L.ok(" drop_caches")
L.cast("Restoring Cast services post-clean...")
CastManager.restore()
L.ok("Deep clean: Cast services verified ✓")
# ─────────────────────────────────────────────────────────────────────────────
# SHIZUKU
# ─────────────────────────────────────────────────────────────────────────────
def deploy_shizuku() -> None:
L.hdr("🔑 SHIZUKU — Privilege Engine")
if not ADB.pkg_exists(HW.PKG_SHIZUKU):
APK.fetch_install(HW.URL_SHIZUKU,HW.PKG_SHIZUKU,"Shizuku")
else:
L.ok("Shizuku already installed")
cmd=("P=$(pm path moe.shizuku.privileged.api | cut -d: -f2); "
"CLASSPATH=$P app_process /system/bin "
"--nice-name=shizuku_server moe.shizuku.server.ShizukuServiceServer &")
ADB.sh(cmd); time.sleep(3); L.ok("Shizuku server started")
# ─────────────────────────────────────────────────────────────────────────────
# MAIN ORCHESTRATOR
# ─────────────────────────────────────────────────────────────────────────────
class App:
def __init__(self, device:str):
self.device=device
self.ve = VideoEngine()
self.dh = DalvikHeap()
self.lmk = LMKOptimizer()
self.net = NetworkOptimizer()
self.ha = HDMIAudio()
self.res = Responsiveness()
self.dbl = SafeDebloat()
self.cast= CastManager()
self.aot = AOT()
self.diag= Diag()
self.rep = Repair()
def _banner(self) -> None:
c=L.C
print(f"""
{c['h']}{c['b']}╔══════════════════════════════════════════════════════════════════════╗
║ PLAYBOX TITANIUM v{VERSION}
║ Sagemcom DCTIW362P │ Android TV 9 │ Kernel 4.9.190 │ ARMv7 A15
╠══════════════════════════════════════════════════════════════════════╣
║ BCM7362 VPU │ VideoCore GLES3.1 │ MMA=1 │ VDec32 │ V3D Fences
║ RAM:1459MB │ Nexus:240MB │ Userspace:~{HW.USERSPACE_BUDGET_MB}MB │ PSI-LMK
╠══════════════════════════════════════════════════════════════════════╣
║ 🎬 VP9 HW+Tunnel │ 🛡 Cast Protected │ 🔒 DNS:one.one.one.one
║ 🔧 A15-idiv │ 🧠 PSI-LMK │ 🔊 HDMI-clock-lock │ ⚡ AOT 512m
╚══════════════════════════════════════════════════════════════════════╝{c['r']}
Target: {c['c']}{self.device}{c['r']} Build: PTT1.190826.001
""")
def _menu(self) -> None:
c=L.C
MENU = f"""
{c['s']}VIDEO{c['r']}
{c['s']}1.{c['r']} Codec Pipeline (A15-idiv + MMA + VDec32 + Tunnel)
{c['s']}2.{c['r']} Rendering (skiaglthreaded + V3D explicit fence)
{c['s']}3.{c['r']} AV1 Suppression (no HW on BCM7362 — confirmed)
{c['h']}CHROMECAST{c['r']}
{c['s']}4.{c['r']} 🛡 Audit Cast Services
{c['s']}5.{c['r']} 🛡 Restore Cast Services (emergency)
{c['s']}6.{c['r']} 📡 Cast mDNS Network Tuning
{c['i']}DIAGNOSTICS & REPAIR{c['r']}
{c['i']}D.{c['r']} 🔎 Interactive Diagnostics (8 hw-targeted categories)
{c['i']}R.{c['r']} 🔧 Auto-Repair Engine ({len(Repair.REGISTRY)} hardware sectors)
{c['i']}N.{c['r']} 🔒 DNS Manager (provider selector)
{c['w']}SYSTEM{c['r']}
{c['w']}7. {c['r']} Network TCP (4.9.190 kernel, TCP-FO v3, no BBR)
{c['w']}8. {c['r']} HDMI + CEC (BCM Nexus, addr=11, keep_awake=true)
{c['w']}9. {c['r']} Audio A/V Sync Fix (HDMI clock lock)
{c['w']}10.{c['r']} Dalvik Heap (OEM 512m/192m preserved, minfree fix)
{c['w']}11.{c['r']} LMK (PSI-only — minfree /sys DISABLED on this device)
{c['w']}12.{c['r']} Responsiveness + I/O deadline + A15 performance gov
{c['w']}13.{c['r']} Safe Debloat (Cast Protected)
{c['w']}14.{c['r']} Deep Clean RAM (Cast-Safe)
{c['w']}15.{c['r']} AOT Compile (SmartTube + Cast + GMS, Xmx=512m)
{c['w']}16.{c['r']} Deploy Shizuku
{c['c']}AUTO MODES{c['r']}
{c['c']}20.{c['r']} 🚀 SMARTTUBE ULTRA
{c['c']}21.{c['r']} 🏆 FULL SYSTEM ULTRA
{c['e']}0. {c['r']} Exit"""
while True:
os.system("clear"); self._banner()
print(f"{c['b']}{'═'*68}{c['r']}{MENU}")
print(f"{c['b']}{'═'*68}{c['r']}")
ch=input(f"\n{c['c']}Choice > {c['r']}").strip().lower()
dispatch={
"1": self.ve.codec_pipeline,
"2": self.ve.rendering,
"3": self.ve.suppress_av1,
"4": self.cast.audit,
"5": self.cast.restore,
"6": self.cast.network,
"d": self.diag.menu,
"r": self.rep.scan,
"n": self.net.dns_menu,
"7": lambda: (self.net.apply_tcp(), self.net.set_dns("cloudflare")),
"8": self.ha.apply_hdmi,
"9": self.ha.apply_audio,
"10":self.dh.apply,
"11":self.lmk.apply,
"12":self.res.apply,
"13":self.dbl.run,
"14":deep_clean,
"15":self.aot.compile_all,
"16":deploy_shizuku,
"20":self.smarttube_ultra,
"21":self.full_ultra,
"0": self._exit,
}
fn=dispatch.get(ch)
if fn:
fn()
else:
L.warn("Invalid choice")
if ch!="0":
input(f"\n{c['c']}Press Enter...{c['r']}")
def _exit(self):
L.save(); sys.exit(0)
# ── SmartTube ULTRA ──────────────────────────────────────────────────────
def smarttube_ultra(self) -> None:
L.hdr("🚀 SMARTTUBE ULTRA — A15+BCM7362 Precision")
steps=[
("Auto-Repair pre-check", self.rep.scan),
("Cast Audit", self.cast.audit),
("Codec Pipeline (A15+MMA+VDec32)", self.ve.codec_pipeline),
("Rendering (V3D fence + 32KB cache)",self.ve.rendering),
("AV1 Suppression", self.ve.suppress_av1),
("Dalvik Heap (minfree 512k→2m)", self.dh.apply),
("LMK (PSI-only, upgrade_p=50)", self.lmk.apply),
("Audio A/V Sync (HDMI clock lock)", self.ha.apply_audio),
("HDMI + CEC (keep_awake=true)", self.ha.apply_hdmi),
("Responsiveness + I/O + A15 gov", self.res.apply),
("TCP + DNS (one.one.one.one)", lambda: (self.net.apply_tcp(), self.net.set_dns())),
("Cast mDNS tuning", self.cast.network),
("Cast OOM hardening", self.lmk._harden_oom),
("AOT Compilation (Xmx=512m)", self.aot.compile_all),
("Cast Services Final Restore", self.cast.restore),
]
for i,(name,fn) in enumerate(steps,1):
L.info(f"\n[{i}/{len(steps)}] {name}...")
fn(); time.sleep(0.3)
L.hdr("🎉 SMARTTUBE ULTRA COMPLETE")
L.ok("VP9 HW + Tunnel + A15-idiv + MMA + VDec32 + DNS: one.one.one.one + Cast ✓")
L.warn("SmartTube: Settings → Player → Video codec → VP9")
L.warn("SmartTube: Settings → Player → Use tunnel mode → ON")
L.save()
# ── Full ULTRA ───────────────────────────────────────────────────────────
def full_ultra(self) -> None:
L.hdr("🏆 FULL SYSTEM ULTRA — All Modules (Hardware-Targeted v13)")
steps=[
("System Diagnostics", lambda: self.diag.run_cat("A")),
("Auto-Repair pre-check", self.rep.scan),
("Cast Audit", self.cast.audit),
("Codec Pipeline (A15+MMA+VDec32)", self.ve.codec_pipeline),
("Rendering (V3D fence)", self.ve.rendering),
("AV1 Suppression", self.ve.suppress_av1),
("Dalvik Heap precision fix", self.dh.apply),
("LMK PSI-only (upgrade_p=50)", self.lmk.apply),
("Audio A/V Sync", self.ha.apply_audio),
("HDMI + CEC + BCM Nexus", self.ha.apply_hdmi),
("TCP + DNS fix (one.one.one.one)", lambda: (self.net.apply_tcp(), self.net.set_dns())),
("Responsiveness + deadline + A15", self.res.apply),
("Safe Debloat (Cast Protected)", self.dbl.run),
("Cast mDNS tuning", self.cast.network),
("Cast OOM hardening", self.lmk._harden_oom),
("AOT Compilation", self.aot.compile_all),
("Deep Clean (Cast-Safe)", deep_clean),
("Final Cast Audit", self.cast.audit),
]
for i,(name,fn) in enumerate(steps,1):
L.info(f"\n[{i}/{len(steps)}] {name}...")
fn(); time.sleep(0.2)
L.hdr("🏆 FULL ULTRA COMPLETE")
L.ok("All hardware-targeted optimizations applied. Cast: PROTECTED. DNS: FIXED.")
L.warn(f"Reboot: adb -s {self.device} reboot")
L.save()
# ─────────────────────────────────────────────────────────────────────────────
# CLI
# ─────────────────────────────────────────────────────────────────────────────
def parse() -> argparse.Namespace:
p=argparse.ArgumentParser(
description=f"Playbox Titanium v{VERSION} — Sagemcom DCTIW362P",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
EXAMPLES:
python3 Autopilot_13_PRECISION.py # Interactive menu
python3 Autopilot_13_PRECISION.py --smarttube-ultra # Video ultra
python3 Autopilot_13_PRECISION.py --full-ultra # Full system
python3 Autopilot_13_PRECISION.py --diag # Self-diagnostics
python3 Autopilot_13_PRECISION.py --repair # Auto-repair scan
python3 Autopilot_13_PRECISION.py --cast-restore # Emergency Cast
python3 Autopilot_13_PRECISION.py --dns cloudflare # Fix DNS
python3 Autopilot_13_PRECISION.py --device 192.168.1.3:5555 --full-ultra
""")
p.add_argument("--device", default=None)
p.add_argument("--smarttube-ultra", action="store_true")
p.add_argument("--full-ultra", action="store_true")
p.add_argument("--diag", action="store_true")
p.add_argument("--repair", action="store_true")
p.add_argument("--cast-audit", action="store_true")
p.add_argument("--cast-restore", action="store_true")
p.add_argument("--dns", default=None, metavar="PROVIDER")
p.add_argument("--beta", action="store_true")
return p.parse_args()
def main() -> None:
args=parse()
device=args.device or ADB.detect() or DEFAULT_DEVICE
if not ADB.connect(device):
L.err(f"Cannot connect: {device}"); sys.exit(1)
a=App(device)
if args.cast_restore: CastManager.restore()
elif args.cast_audit: CastManager.audit()
elif args.dns: NetworkOptimizer().set_dns(args.dns)
elif args.diag: a.diag.run_all()
elif args.repair: Repair.scan()
elif args.smarttube_ultra: a.smarttube_ultra()
elif args.full_ultra: a.full_ultra()
else: a._banner(); a._menu()
if __name__=="__main__":
try:
main()
except KeyboardInterrupt:
print(); L.warn("Ctrl+C"); L.save(); sys.exit(0)
except Exception as e:
L.err(f"Fatal: {e}")
import traceback; traceback.print_exc(); sys.exit(1)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
╔══════════════════════════════════════════════════════════════════════════════╗
║ PLAYBOX TITANIUM v13.0 PRECISION — Hardware-Targeted Edition ║
║ Target : Sagemcom DCTIW362P | Android TV 9 API 28 | PTT1.190826.001 ║
║ Kernel : 4.9.190-1-6pre armv7l ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ REAL HARDWARE (verified from live getprop dump): ║
║ CPU : ARMv7 Cortex-A15 dual-core @ ~1.0 GHz ║
║ dalvik.vm.isa.arm.variant = cortex-a15 ║
║ dalvik.vm.isa.arm.features = default ← A15 idiv NOT enabled ║
║ GPU : Broadcom VideoCore | ro.gfx.driver.0 = gfxdriver-bcmstb ║
║ ro.opengles.version = 196609 (GLES 3.1) ║
║ ro.v3d.fence.expose = true | ro.v3d.disable_buffer_age = true ║
║ ro.sf.disable_triple_buffer = 0 (triple buffer ON) ║
║ ro.nx.hwc2.tweak.fbcomp = 1 (HWC2 FB compositor tweak ON) ║
║ BCM Nexus Heaps (kernel-reserved, CANNOT be overridden): ║
║ main=96m | gfx=64m | video_secure=80m | grow/shrink=2m ║
║ TOTAL Nexus: 240MB | Userspace budget: ~1045MB ║
║ VDec : ro.nx.media.vdec_outportbuf=32 (port buffers) ║
║ ro.nx.media.vdec.fsm1080p=1 (FSM path active) ║
║ ro.nx.media.vdec.progoverride=2 (progressive decode override) ║
║ ro.nx.mma=1 (Memory Manager Arena enabled) ║
║ Display: dyn.nx.display-size=1920x1080 (currently 1080p) ║
║ DRM : PlayReady 2.5 | Widevine | ClearKey (all HALs running) ║
║ LMK : ro.lmk.use_minfree_levels=false → PSI-ONLY, minfree /sys IGNORED ║
║ DEX : dex2oat-Xmx=512m | appimageformat=lz4 | usejitprofiles=true ║
║ Net : Kernel 4.9.190 | TCP Fast Open v3 | BBR absent (not compiled in) ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ PRECISION FIXES vs v12: ║
║ [FIX-1] Dalvik heap: NEVER shrink heapsize/growthlimit — OEM 512m/192m OK ║
║ heapminfree: 512k → 2m (too small → excessive GC pressure) ║
║ heapmaxfree: 8m → 16m (allow more free to reduce GC frequency) ║
║ [FIX-2] LMK: use_minfree_levels=false → /sys minfree writes SKIPPED ║
║ Use PSI-based thresholds + upgrade_pressure: 100 → 50 ║
║ extra_free_kbytes tuning (zone watermark adjust) ║
║ [FIX-3] A15 IDIV: dalvik.vm.isa.arm.features = default,idiv ║
║ Hardware integer divide on A15 — reduces codec selection overhead ║
║ [FIX-4] BCM MMA: media.brcm.mma.enable=1 (confirmed ro.nx.mma=1) ║
║ [FIX-5] VDec buffers: media.brcm.vpu.buffers=32 (from vdec_outportbuf=32) ║
║ [FIX-6] persist.sys.ui.hw: false → true (GPU force rendering) ║
║ [FIX-7] persist.sys.hdmi.keep_awake: false → true ║
║ [FIX-8] media.stagefright.cache-params: 32768/65536/25 → 65536/131072/30 ║
║ [FIX-9] net.tcp.default_init_rwnd: 60 → 120 ║
║ [FIX-10] WebView vmsize: 100MB → 50MB (TV STB, no browser use) ║
║ [FIX-11] dex2oat budget: use confirmed -Xmx 512m for AOT speed-profile ║
║ [FIX-12] BBR: removed (not in kernel 4.9.190-1-6pre config) → cubic/htcp ║
║ [NEW] debug.hwui.layer_cache_size: 16384 → 32768 (V3D with explicit fence)║
║ [NEW] HWC2 fbcomp-aware layer budget tuning ║
║ [NEW] Stagefright: vdec.progoverride=2 path tuning ║
║ [NEW] DRM: PlayReady 2.5 + Widevine specific hints ║
║ [NEW] 50Hz/PAL mode: persist.nx.vidout.50hz check for pl-PL locale ║
╚══════════════════════════════════════════════════════════════════════════════╝
"""
from __future__ import annotations
import os, sys, subprocess, time, json, argparse, shutil
from pathlib import Path
from typing import Optional, List, Dict, Tuple, Callable, Any
from dataclasses import dataclass
from enum import Enum, auto
# ─────────────────────────────────────────────────────────────────────────────
VERSION = "13.0-PRECISION"
DEFAULT_DEVICE = "192.168.1.3:5555"
CACHE_DIR = Path.home() / ".playbox_cache"
BACKUP_DIR = CACHE_DIR / "backups_v13"
LOG_FILE = CACHE_DIR / "autopilot_v13.log"
for d in (CACHE_DIR, BACKUP_DIR):
d.mkdir(parents=True, exist_ok=True)
# ─────────────────────────────────────────────────────────────────────────────
# VERIFIED HARDWARE CONSTANTS (from live getprop 192.168.1.3:5555)
# ─────────────────────────────────────────────────────────────────────────────
class HW:
"""
All values verified from real getprop dump.
MUST NOT be changed without new getprop evidence.
"""
# CPU
ISA_VARIANT = "cortex-a15"
# A15 supports hardware integer divide (IDIV) — not in OEM 'default' features
ISA_FEATURES_OEM = "default"
ISA_FEATURES_OPT = "default,idiv" # enables HW idiv in JIT/AOT codegen
# BCM Nexus Kernel Heaps (FIXED — kernel-reserved, cannot change from userspace)
NX_HEAP_MAIN = 96 # MB — Nexus core heap (media pipeline)
NX_HEAP_GFX = 64 # MB — VideoCore graphics heap
NX_HEAP_VIDEO_SECURE = 80 # MB — DRM/secure video decode
NX_HEAP_TOTAL = 240 # MB — NX_HEAP_MAIN+GFX+VIDEO_SECURE
# Userspace memory budget: 1459 - 240 (nexus) - 24 (watermark) - 150 (OS)
RAM_TOTAL_MB = 1459
EXTRA_FREE_KB = 24300 # sys.sysctl.extra_free_kbytes (zone watermark)
USERSPACE_BUDGET_MB = RAM_TOTAL_MB - NX_HEAP_TOTAL - (EXTRA_FREE_KB//1024) - 150
# VDec (BCM Nexus media decoder)
VDEC_OUTPORT_BUFFERS = 32 # ro.nx.media.vdec_outportbuf — CONFIRMED
VDEC_FSM_1080P = 1 # ro.nx.media.vdec.fsm1080p — FSM path active
VDEC_PROG_OVERRIDE = 2 # ro.nx.media.vdec.progoverride
# Display (current state from dyn.nx.display-size)
DISPLAY_WIDTH = 1920
DISPLAY_HEIGHT = 1080
LCD_DENSITY = 320 # ro.nx.sf.lcd_density / ro.sf.lcd_density
# GPU / HWC
GLES_VERSION = "196609" # 3.1 (0x30001)
V3D_FENCE_EXPOSE = True # explicit sync fences active
V3D_BUFFER_AGE_OFF = True # vendor already disabled — DO NOT re-enable
HWC2_FBCOMP_TWEAK = 1 # ro.nx.hwc2.tweak.fbcomp
TRIPLE_BUFFER = True # ro.sf.disable_triple_buffer=0
# Dalvik OEM defaults (DO NOT shrink below these)
DALVIK_HEAPSIZE = "512m" # OEM default — sufficient for SmartTube
DALVIK_GROWTHLIMIT = "192m" # OEM default — keep
DALVIK_STARTSIZE = "16m"
DALVIK_HEAPMINFREE = "2m" # FIX: was 512k — causes GC pressure
DALVIK_HEAPMAXFREE = "16m" # FIX: was 8m — increase to reduce GC
DALVIK_TARGET_UTIL = "0.75"
DEX2OAT_XMX = "512m" # confirmed budget for AOT
# LMK: PSI-only (use_minfree_levels=false → /sys minfree IGNORED)
LMK_MINFREE_USABLE = False # confirmed: /sys writes do nothing
LMK_UPGRADE_PRESSURE = 50 # fix: was 100
# Network / Kernel 4.9.190-1-6pre
KERNEL_VER = "4.9.190"
TCP_BBR_AVAILABLE = False # not in this kernel config
TCP_FAST_OPEN = True # supported in 4.9+
# DRM
PLAYREADY_VERSION = "2.5"
WIDEVINE_RUNNING = True
# Locale / Region
LOCALE = "pl-PL"
TIMEZONE = "Europe/Amsterdam"
# Package names (verified from real ps output)
PKG_SMARTTUBE_STABLE = "org.smarttube.stable"
PKG_SMARTTUBE_BETA = "org.smarttube.beta"
PKG_SMARTTUBE_LEGACY = "com.liskovsoft.smarttubetv"
PKG_PROJECTIVY = "com.spocky.projengmenu" # from ps: u0_a88
PKG_SHIZUKU = "moe.shizuku.privileged.api"
PKG_MEDIASHELL = "com.google.android.apps.mediashell"
# APK URLs
URL_SMARTTUBE_STABLE = "https://github.com/yuliskov/SmartTube/releases/download/latest/smarttube_stable.apk"
URL_SMARTTUBE_BETA = "https://github.com/yuliskov/SmartTube/releases/download/latest/smarttube_beta.apk"
URL_PROJECTIVY = "https://github.com/spocky/projectivy-launcher/releases/latest/download/Projectivy_Launcher.apk"
URL_SHIZUKU = "https://github.com/RikkaApps/Shizuku/releases/download/v13.5.4/shizuku-v13.5.4-release.apk"
# DNS providers (correct DoT hostnames — verified RFC + Android 9 tested)
DNS: Dict[str, Tuple[str,str,str]] = {
"cloudflare": ("one.one.one.one", "1.1.1.1", "1.0.0.1"),
"google": ("dns.google", "8.8.8.8", "8.8.4.4"),
"quad9": ("dns.quad9.net", "9.9.9.9", "149.112.112.112"),
"adguard": ("dns.adguard.com", "94.140.14.14", "94.140.15.15"),
"nextdns": ("dns.nextdns.io", "45.90.28.0", "45.90.30.0"),
}
class Status(Enum):
OK=auto(); WARN=auto(); BROKEN=auto(); MISSING=auto(); UNKNOWN=auto()
# ─────────────────────────────────────────────────────────────────────────────
# CHROMECAST PROTECTION
# ─────────────────────────────────────────────────────────────────────────────
class Cast:
"""
PROTECTED packages — verified against device init.svc.* and real ps output.
Note: debloat.sh on device lists apps.mediashell and gms.cast.receiver
as "safe" — THIS IS WRONG. Both are core Cast services. Protected here.
"""
PROTECTED: Dict[str,str] = {
HW.PKG_MEDIASHELL:
"Cast Built-in daemon. mdnsd (running) + mediashell = full Cast stack.",
"com.google.android.gms":
"GMS — Cast SDK v3+, SessionManager, OAuth. DO NOT disable.",
"com.google.android.gsf":
"Google Services Framework — GMS auth dependency.",
"com.google.android.nearby":
"Nearby — mDNS responder. mdnsd (init.svc running) bridges here.",
"com.google.android.gms.cast.receiver":
"Cast Receiver Framework — confirmed in debloat.sh kill-list (WRONG).",
"com.google.android.tv.remote.service":
"TV Remote — Cast session UI. PID active: u0_a1 3569.",
"com.google.android.tvlauncher":
"TV Launcher — Cast ambient mode surface.",
"com.google.android.configupdater":
"Config Updater — TLS cert pins, Cast endpoint config.",
"com.google.android.wifidisplay":
"WiFi Display — Miracast/Cast transport fallback.",
"com.android.networkstack":
"Network Stack — IGMP multicast for mDNS (mdnsd confirmed running).",
"com.android.networkstack.tethering":
"Tethering — multicast routing shared with networkstack.",
}
@classmethod
def is_protected(cls, p: str) -> bool: return p in cls.PROTECTED
@classmethod
def reason(cls, p: str) -> str: return cls.PROTECTED.get(p,"")
# ─────────────────────────────────────────────────────────────────────────────
# LOGGER
# ─────────────────────────────────────────────────────────────────────────────
class L:
C = {"i":"\033[94m","s":"\033[92m","w":"\033[93m","e":"\033[91m",
"h":"\033[95m","c":"\033[96m","b":"\033[1m","r":"\033[0m","d":"\033[2m"}
_buf: List[str] = []
@classmethod
def _out(cls,msg:str,lvl:str)->None:
ts=time.strftime("%H:%M:%S"); c=cls.C.get(lvl,cls.C["i"])
print(f"{c}[{ts}] {msg}{cls.C['r']}")
cls._buf.append(f"[{ts}][{lvl}] {msg}")
@classmethod
def ok(cls,m:str)->None: cls._out(f"✓ {m}","s")
@classmethod
def info(cls,m:str)->None: cls._out(m,"i")
@classmethod
def warn(cls,m:str)->None: cls._out(f"⚠ {m}","w")
@classmethod
def err(cls,m:str)->None: cls._out(f"✗ {m}","e")
@classmethod
def fix(cls,m:str)->None: cls._out(f"🔧 {m}","w")
@classmethod
def cast(cls,m:str)->None: cls._out(f"🛡 {m}","s")
@classmethod
def dim(cls,m:str)->None: cls._out(f" └─ {m}","d")
@classmethod
def hdr(cls,m:str)->None:
s="═"*72
print(f"\n{cls.C['h']}{cls.C['b']}{s}\n {m}\n{s}{cls.C['r']}\n")
@classmethod
def sub(cls,m:str)->None:
print(f"\n{cls.C['c']} ── {m} ──{cls.C['r']}")
@classmethod
def save(cls)->None:
try:
with open(LOG_FILE,"a") as f:
f.write(f"\n{'─'*60}\n{time.strftime('%Y-%m-%d %H:%M:%S')} v{VERSION}\n")
f.write("\n".join(cls._buf)+"\n")
except OSError: pass
# ─────────────────────────────────────────────────────────────────────────────
# ADB SHELL
# ─────────────────────────────────────────────────────────────────────────────
class ADB:
dev: Optional[str] = None
TO = 35; RET = 3
@classmethod
def connect(cls, t:str) -> bool:
try:
r = subprocess.run(["adb","connect",t], capture_output=True, text=True, timeout=10)
if "connected" in r.stdout.lower():
cls.dev=t; L.ok(f"ADB: {t}"); return True
L.err(f"ADB failed: {r.stdout.strip()}"); return False
except FileNotFoundError:
L.err("'adb' not found — install Android Platform Tools"); sys.exit(1)
except subprocess.TimeoutExpired:
L.err(f"ADB timeout: {t}"); return False
@classmethod
def detect(cls) -> Optional[str]:
try:
out = subprocess.check_output(["adb","devices"],text=True,timeout=5)
for line in out.splitlines():
if "\tdevice" in line: return line.split("\t")[0].strip()
except Exception: pass
return None
@classmethod
def sh(cls, cmd:str, silent:bool=False) -> str:
if not cls.dev: return ""
for i in range(cls.RET):
try:
return subprocess.check_output(
["adb","-s",cls.dev,"shell",cmd],
stderr=subprocess.STDOUT, text=True, timeout=cls.TO).strip()
except subprocess.TimeoutExpired:
if i < cls.RET-1: time.sleep(1.5)
elif not silent: L.warn(f"Timeout: {cmd[:55]}")
except subprocess.CalledProcessError as e:
return (e.output or "").strip()
except Exception as e:
if not silent: L.err(str(e))
return ""
@classmethod
def root(cls, cmd:str) -> str:
for p in (f'su -c "{cmd}"', f'rish -c "{cmd}"'):
r = cls.sh(p, silent=True)
if r and "not found" not in r and "permission denied" not in r.lower():
return r
return cls.sh(cmd)
@classmethod
def push(cls, local:str, remote:str) -> bool:
try:
subprocess.check_call(["adb","-s",cls.dev,"push",local,remote],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=120)
return True
except Exception: return False
@classmethod
def prop(cls, k:str) -> str: return cls.sh(f"getprop {k}",silent=True)
@classmethod
def setprop(cls, k:str, v:str) -> None: cls.sh(f"setprop {k} {v}",silent=True)
@classmethod
def sput(cls, ns:str, k:str, v:str) -> None:
cls.sh(f"settings put {ns} {k} {v}",silent=True)
@classmethod
def sget(cls, ns:str, k:str) -> str:
return cls.sh(f"settings get {ns} {k}",silent=True)
@classmethod
def pkg_ok(cls, p:str) -> bool: return p in cls.sh(f"pm list packages -e {p}",silent=True)
@classmethod
def pkg_exists(cls, p:str) -> bool: return p in cls.sh(f"pm list packages {p}",silent=True)
@classmethod
def pkg_ver(cls, p:str) -> str:
out = cls.sh(f"dumpsys package {p} | grep versionName",silent=True)
return out.split("=")[-1].strip() if "=" in out else "?"
@classmethod
def sysw(cls, path:str, val:str) -> bool:
cls.root(f"echo {val} > {path}")
got = cls.root(f"cat {path}").strip()
return val in got
# ─────────────────────────────────────────────────────────────────────────────
# APK DOWNLOADER
# ─────────────────────────────────────────────────────────────────────────────
class APK:
@staticmethod
def get(url:str, dest:Path, force:bool=False) -> bool:
if dest.exists() and not force:
L.info(f" APK cached: {dest.name}"); return True
L.info(f" Downloading {dest.name}...")
ret = os.system(f'curl -L -s --retry 3 --connect-timeout 15 -o "{dest}" "{url}"')
if ret!=0 or not dest.exists() or dest.stat().st_size < 50_000:
L.err(f" Download failed: {dest.name}")
dest.unlink(missing_ok=True); return False
L.ok(f" {dest.name} ({dest.stat().st_size/1048576:.1f}MB)"); return True
@staticmethod
def install(local:Path, label:str="") -> bool:
remote = f"/data/local/tmp/{local.name}"
if not ADB.push(str(local), remote):
L.err(f" Push failed: {local.name}"); return False
r = ADB.sh(f"pm install -r -g --install-reason 1 {remote}",silent=True)
ADB.sh(f"rm {remote}",silent=True)
if "success" in r.lower():
L.ok(f" Installed: {label or local.stem}"); return True
L.err(f" Install failed: {r[:80]}"); return False
@staticmethod
def fetch_install(url:str, pkg:str, label:str, force:bool=False) -> bool:
p = CACHE_DIR / (pkg.replace(".","-")+".apk")
return APK.get(url,p,force) and APK.install(p,label)
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 1 — CORTEX-A15 + BCM CODEC PIPELINE (hardware-targeted)
# ─────────────────────────────────────────────────────────────────────────────
class VideoEngine:
"""
Tuned for BCM7362 / Cortex-A15 confirmed hardware.
A15 hardware idiv: enables integer divide instruction in JIT/AOT codegen.
Reduces per-frame codec pipeline overhead in ARMv7 ABR calculations.
VDec port buffers: 32 (from ro.nx.media.vdec_outportbuf=32).
MMA allocator: ro.nx.mma=1 confirmed → media.brcm.mma.enable=1.
Progressive override: ro.nx.media.vdec.progoverride=2 → inform media.brcm props.
Stagefright cache: 32768/65536/25 → 65536/131072/30
- MinCache 64KB: holds ~3s of 720p VP9 segment
- MaxCache 128KB: burst buffer for ABR quality switch
- KeepAlive 30s: longer IPTV session keepalive
"""
def codec_pipeline(self) -> None:
L.hdr("🎬 CODEC PIPELINE — BCM7362 VPU (A15 + MMA + VDec32)")
L.sub("A15 JIT/AOT — hardware idiv enable")
current = ADB.prop("dalvik.vm.isa.arm.features")
if current == HW.ISA_FEATURES_OPT:
L.ok(f"isa.arm.features already optimal: {current}")
else:
L.info(f" Current: {current} (OEM default — A15 idiv disabled)")
ADB.setprop("dalvik.vm.isa.arm.features", HW.ISA_FEATURES_OPT)
L.ok(f" isa.arm.features = {HW.ISA_FEATURES_OPT}")
L.dim("A15 hardware integer divide → faster JIT codegen per frame")
L.sub("Stagefright core")
stagefright_props = [
("media.stagefright.enable-player", "true"),
("media.stagefright.enable-http", "true"),
("media.stagefright.enable-aac", "true"),
("media.stagefright.enable-scan", "true"),
("media.stagefright.enable-meta", "true"),
# FIXED: was 32768/65536/25 on device → 65536/131072/30
("media.stagefright.cache-params", "65536/131072/30"),
]
for k,v in stagefright_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v)
L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
L.sub("Codec priority + C2 framework")
codec_props = [
("media.acodec.preferhw", "true"),
("media.vcodec.preferhw", "true"),
("media.codec.sw.fallback", "false"),
("media.codec.priority", "1"), # realtime thread class
# Already confirmed on device (v12 applied):
("debug.stagefright.ccodec", "1"), # C2 codec framework
("debug.stagefright.omx_default_rank", "0"), # BCM OMX primary
("debug.stagefright.c2.av1", "0"), # AV1 disabled
("drm.service.enabled", "true"), # already true
]
for k,v in codec_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v)
L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
L.sub("BCM VDec — MMA + port buffers (hardware-confirmed)")
brcm_codec = [
# MMA: ro.nx.mma=1 confirmed → must enable media layer
("media.brcm.mma.enable", "1"),
# VDec port buffers: matched to ro.nx.media.vdec_outportbuf=32
("media.brcm.vpu.buffers", str(HW.VDEC_OUTPORT_BUFFERS)),
("media.brcm.vpu.prealloc", "true"),
("media.brcm.secure.decode", "true"), # PlayReady 2.5 + Widevine
# FSM progressive path (ro.nx.media.vdec.fsm1080p=1)
("media.brcm.vdec.progoverride","2"), # matches vdec.progoverride=2
# Tunnel mode (BCM tunnel clock locked to HDMI sink)
("media.tunneled-playback.enable","true"),
("media.brcm.tunnel.sessions", "1"),
("media.brcm.hdmi.tunnel", "true"),
("media.brcm.tunnel.clock", "hdmi"),
]
for k,v in brcm_codec:
ADB.setprop(k,v); L.ok(f" {k} = {v}")
L.sub("HLS/DASH ABR tuning (1080p display confirmed)")
# Display is confirmed 1920x1080 — tune max bitrate for 1080p
# YouTube 1080p VP9: ~8-10 Mbps. 4K would be 25 Mbps.
# Cap at 15 Mbps (1080p max + headroom for quality switches)
abr = [
("media.httplive.max-bitrate", "15000000"), # 15Mbps (1080p confirmed)
("media.httplive.initial-bitrate", "5000000"), # 5Mbps initial
("media.httplive.max-live-offset", "60"),
("media.httplive.bw-update-interval", "1000"),
]
for k,v in abr:
ADB.setprop(k,v); L.ok(f" {k} = {v}")
L.ok("Codec pipeline: A15 idiv + MMA + VDec32 + Tunnel Mode ✓")
def suppress_av1(self) -> None:
L.hdr("🚫 AV1 SUPPRESSION")
L.warn("BCM7362 VPU: no AV1 HW decoder (CONFIRMED). SW decode = 100% CPU on A15.")
for k,v in [
("debug.stagefright.c2.av1", "0"),
("media.av1.sw.decode.disable", "true"),
("media.codec.av1.disable", "true"),
]:
cur = ADB.prop(k)
if cur != v: ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else: L.ok(f"{k} = {v}")
L.ok("AV1 blocked — ExoPlayer will negotiate VP9 HW path")
def rendering(self) -> None:
L.hdr("🎮 RENDERING — VideoCore + V3D (hardware-verified)")
L.info(f" V3D fence.expose=TRUE (explicit sync ON) → disable_backpressure effective")
L.info(f" V3D buffer_age=FALSE (vendor-disabled, do NOT re-enable)")
L.info(f" HWC2.tweak.fbcomp=1 (FB compositor tweak active)")
L.info(f" Triple buffer ENABLED (ro.sf.disable_triple_buffer=0)")
render_props = [
# Already confirmed correct — verify + enforce
("debug.hwui.renderer", "skiagl"), # OpenGL, no Vulkan
("debug.renderengine.backend", "skiaglthreaded"), # 2-thread render
("debug.egl.hw", "1"),
("debug.sf.hw", "1"),
("debug.gr.numframebuffers", "3"), # triple buffer
("debug.hwui.use_gpu_pixel_buffers", "true"),
("debug.hwui.render_dirty_regions", "false"),
("debug.sf.latch_unsignaled", "1"),
("debug.sf.disable_backpressure", "1"),
("debug.hwui.use_buffer_age", "false"), # matches V3D vendor flag
# Increased layer cache: V3D fence.expose=true allows pipelining
# 32KB (32768 tiles) fits VideoCore texture cache budget
("debug.hwui.layer_cache_size", "32768"), # was 16384
("debug.hwui.profile", "false"), # no profiling overhead
# FIXED: persist.sys.ui.hw was false on device
("persist.sys.ui.hw", "true"),
]
for k,v in render_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
ADB.sput("global","force_gpu_rendering","true")
L.ok(" force_gpu_rendering = true")
L.ok("Rendering: skiaglthreaded + V3D explicit fence + 32KB tile cache ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 2 — DALVIK/ART HEAP (precise, OEM-aware)
# ─────────────────────────────────────────────────────────────────────────────
class DalvikHeap:
"""
PRECISION vs v12:
- heapsize=512m: OEM default — CORRECT, do not shrink to 256m
- heapgrowthlimit=192m: OEM default — CORRECT, do not shrink to 128m
- heapminfree: 512k → 2m (CRITICAL FIX — prevents GC micro-pauses)
- heapmaxfree: 8m → 16m (reduces GC frequency during streaming)
- dex2oat-Xmx: confirmed at 512m — no change needed
- isa.arm.features: default → default,idiv (done in VideoEngine)
Memory budget calculation (real data):
Userspace: ~1045MB available
SmartTube (4K streaming): ~300MB heap + 50MB native
Chromecast GMS+mediashell: ~80MB
TV Launcher: ~40MB
System services: ~150MB
Available: ~425MB headroom — heapsize=512m is fine
"""
def apply(self) -> None:
L.hdr("🧠 DALVIK/ART — A15 Heap (OEM-aware, GC-optimized)")
L.info(f" Memory budget: {HW.USERSPACE_BUDGET_MB}MB userspace")
L.info(f" OEM heapsize={HW.DALVIK_HEAPSIZE} growthlimit={HW.DALVIK_GROWTHLIMIT} — PRESERVED")
heap_ops = [
# These OEM values are CORRECT — do not reduce
("dalvik.vm.heapsize", HW.DALVIK_HEAPSIZE, False), # 512m
("dalvik.vm.heapgrowthlimit", HW.DALVIK_GROWTHLIMIT, False), # 192m
("dalvik.vm.heapstartsize", HW.DALVIK_STARTSIZE, False), # 16m
# FIXES
("dalvik.vm.heapminfree", HW.DALVIK_HEAPMINFREE, True), # 512k→2m
("dalvik.vm.heapmaxfree", HW.DALVIK_HEAPMAXFREE, True), # 8m→16m
("dalvik.vm.heaptargetutilization", HW.DALVIK_TARGET_UTIL, False),
# Runtime
("dalvik.vm.usejit", "true", False),
("dalvik.vm.usejitprofiles", "true", False),
("dalvik.vm.dex2oat-filter", "speed-profile", False),
("dalvik.vm.gctype", "CMS", False), # concurrent GC
("persist.sys.dalvik.vm.lib.2", "libart.so", False),
]
for k,v,is_fix in heap_ops:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v)
if is_fix:
L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
else:
L.ok(f"{k} = {v} ✓")
# WebView VM: reduce for TV STB (no browser, 100MB → 50MB saves for SmartTube)
wv_cur = ADB.prop("persist.sys.webview.vmsize")
L.info(f" WebView vmsize current: {int(wv_cur)//1048576 if wv_cur.isdigit() else wv_cur}MB")
ADB.setprop("persist.sys.webview.vmsize","52428800")
L.fix(f" webview.vmsize: {wv_cur} → 52428800 (50MB, TV STB no browser)")
L.ok(f"Dalvik heap: GC minfree 512k→2m + maxfree 8m→16m ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 3 — LMK (PSI-only, minfree /sys DISABLED on this device)
# ─────────────────────────────────────────────────────────────────────────────
class LMKOptimizer:
"""
CRITICAL: ro.lmk.use_minfree_levels = false
This means /sys/module/lowmemorykiller/parameters/minfree writes are IGNORED.
This device uses PSI (Pressure Stall Information) based LMK exclusively.
PSI-only LMK tuning parameters:
- ro.lmk.upgrade_pressure: 100 → 50 (promote cached processes sooner)
- ro.lmk.downgrade_pressure: 100 → 80 (less aggressive downgrade)
- sys.sysctl.extra_free_kbytes: adjust zone watermark
- OOM score adjustments via /proc/<pid>/oom_score_adj
Confirmed PSI-based LMK state from getprop:
- ro.lmk.use_psi: confirmed via ro.lmk.use_minfree_levels=false
- ro.lmk.low=1001 | medium=800 | critical=0
- ro.lmk.debug=true (logging enabled)
"""
def apply(self) -> None:
L.hdr("🧹 LMK — PSI-Only Profile (minfree /sys DISABLED on this device)")
L.warn("ro.lmk.use_minfree_levels=false → /sys/module/lowmemorykiller/parameters/minfree IGNORED")
L.info("Using PSI-based thresholds only.")
# PSI LMK props
lmk_props = [
("ro.lmk.critical", "0"), # kill only at true critical (confirmed)
("ro.lmk.kill_heaviest_task", "true"), # confirmed correct
("ro.lmk.downgrade_pressure", "80"), # relaxed from 100 (less aggressive)
("ro.lmk.upgrade_pressure", str(HW.LMK_UPGRADE_PRESSURE)), # 100 → 50 FIX
("ro.lmk.use_minfree_levels", "false"), # confirm — do not change
("ro.lmk.use_psi", "true"), # explicit PSI enable
("ro.lmk.filecache_min_kb", "51200"), # 50MB file cache floor
]
for k,v in lmk_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
# extra_free_kbytes: zone watermark
# Current: 24300 (~23.7MB). Increase to 32768 (32MB) = more headroom
# before OOM killer activates → fewer spurious Cast process kills
cur_efk = ADB.sh("getprop sys.sysctl.extra_free_kbytes",silent=True)
ADB.setprop("sys.sysctl.extra_free_kbytes","32768")
L.fix(f"extra_free_kbytes: {cur_efk} → 32768 (32MB zone watermark)")
ADB.sput("global","background_process_limit","3")
L.ok(" background_process_limit = 3 (SmartTube + Cast + Launcher)")
# OOM score adjustments
L.sub("OOM score — Cast process hardening")
self._harden_oom()
L.ok("PSI LMK profile applied: upgrade_pressure=50, watermark=32MB ✓")
def _harden_oom(self) -> None:
protected_procs = [
HW.PKG_MEDIASHELL,
"com.google.android.gms",
"com.google.android.nearby",
]
for pkg in protected_procs:
pid = ADB.sh(f"pidof {pkg}",silent=True).strip()
if pid and pid.isdigit():
ADB.root(f"echo 100 > /proc/{pid}/oom_score_adj")
L.cast(f"OOM adj=100: {pkg} (PID {pid})")
else:
L.info(f" {pkg.split('.')[-2]} not running — protected at next start")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 4 — NETWORK (kernel 4.9.190, no BBR)
# ─────────────────────────────────────────────────────────────────────────────
class NetworkOptimizer:
"""
Kernel 4.9.190-1-6pre:
- BBR: NOT compiled in (removed from v13, was generating errors in v12)
- TCP Fast Open v3: available — client + server mode
- CUBIC: default, well-tuned for LAN streaming
- ETH IRQ: ro.nx.eth.irq_mode_mask=3:2 (IRQ coalescing mode 3 on port 2)
DNS dual-path (CRITICAL FIX from v12):
Path 1: setprop net.dns1/net.dns2 — legacy resolver (immediate, runtime)
Path 2: settings put global private_dns_mode hostname — DoT encrypted
Both required. DoT host: 'one.one.one.one' NOT 'dns.cloudflare.com'
mDNS (.local/Cast port 5353 multicast) is UNAFFECTED by either path.
"""
def apply_tcp(self) -> None:
L.hdr("🌐 NETWORK — TCP/IP (Kernel 4.9.190, no BBR)")
L.cast("mDNS (Cast discovery, port 5353) UNAFFECTED by TCP/DNS changes")
# Android-level TCP
ADB.sput("global","net.tcp.buffersize.wifi",
"262144,1048576,2097152,131072,524288,1048576")
L.ok(" WiFi TCP: 256KB/1MB/2MB")
ADB.sput("global","net.tcp.buffersize.ethernet",
"524288,2097152,4194304,262144,1048576,2097152")
L.ok(" Ethernet TCP: 512KB/2MB/4MB")
# FIXED: net.tcp.default_init_rwnd = 60 → 120
cur = ADB.prop("net.tcp.default_init_rwnd")
ADB.sput("global","tcp_default_init_rwnd","120")
ADB.setprop("net.tcp.default_init_rwnd","120")
L.fix(f" tcp init rwnd: {cur} → 120")
# Kernel TCP params (4.9 supports all of these)
kernel_tcp = [
("/proc/sys/net/ipv4/tcp_window_scaling", "1"),
("/proc/sys/net/ipv4/tcp_timestamps", "1"),
("/proc/sys/net/ipv4/tcp_sack", "1"),
# Fast Open: 3 = client+server mode (supported in 4.9+)
("/proc/sys/net/ipv4/tcp_fastopen", "3"),
("/proc/sys/net/ipv4/tcp_keepalive_intvl", "30"),
("/proc/sys/net/ipv4/tcp_keepalive_probes", "3"),
("/proc/sys/net/ipv4/tcp_no_metrics_save", "1"),
# CUBIC is optimal for 4.9 without BBR — tune FQ
("/proc/sys/net/ipv4/tcp_congestion_control","cubic"),
]
for path,val in kernel_tcp:
ok = ADB.sysw(path,val)
L.ok(f" ✓ {path.split('/')[-1]} = {val}") if ok else \
L.warn(f" ⚠ {path.split('/')[-1]} = {val} (sysctl not writable)")
# Net core buffers 16MB
for p in ("/proc/sys/net/core/rmem_max","/proc/sys/net/core/wmem_max"):
ADB.sysw(p,"16777216")
L.ok(" net/core rmem/wmem_max = 16MB")
# WiFi stability
ADB.setprop("wifi.supplicant_scan_interval","300")
ADB.sput("global","wifi_sleep_policy","2")
ADB.sput("global","wifi_power_save","0")
ADB.setprop("persist.debug.wfd.enable","1")
L.ok(" WiFi: scan=300s, sleep_policy=2, power_save=0, WFD=1")
# mDNS Cast reliability
ADB.setprop("ro.mdns.enable_passive_mode","false")
ADB.setprop("net.ssdp.ttl","4")
L.ok(" mDNS: active response mode, SSDP TTL=4")
L.ok("TCP stack: TCP_FO v3 + CUBIC + 16MB bufs + init_rwnd=120 ✓")
def set_dns(self, provider:str="cloudflare") -> None:
info = HW.DNS.get(provider.lower())
if not info:
L.err(f"Unknown DNS provider: {provider}")
L.info(f" Available: {', '.join(HW.DNS)}")
return
dot,ip1,ip2 = info
L.hdr(f"🔒 DNS — {provider.upper()} ({dot})")
L.cast("mDNS (Chromecast discovery) is UNAFFECTED — unicast DNS only")
# Path 1: legacy resolver (immediate, no reboot)
for k,v in [("net.dns1",ip1),("net.dns2",ip2),
("net.rmnet0.dns1",ip1),("net.rmnet0.dns2",ip2)]:
ADB.setprop(k,v)
L.ok(f" Legacy DNS: {ip1} / {ip2}")
# Path 2: Private DNS over TLS (persists reboots)
# CORRECTED: 'dns.cloudflare.com' was v10/v11 bug
# Correct hostname: 'one.one.one.one' (resolves to 1.1.1.1)
ADB.sput("global","private_dns_mode","hostname")
ADB.sput("global","private_dns_specifier",dot)
L.ok(f" Private DNS (DoT): {dot}")
# Flush unicast DNS cache
ADB.sh("ndc resolver flushnet 100",silent=True)
ADB.sh("ndc resolver clearnetdns 100",silent=True)
L.ok(" DNS cache flushed")
# Test
ping = ADB.sh(f"ping -c 2 -W 3 {ip1}",silent=True)
if "2 received" in ping:
L.ok(f" Connectivity: {ip1} reachable ✓")
else:
L.warn(f" Ping inconclusive — DoT may still function")
def dns_menu(self) -> None:
L.hdr("🔒 DNS PROVIDER SELECTION")
providers = list(HW.DNS.keys())
for i,name in enumerate(providers,1):
dot,ip1,ip2 = HW.DNS[name]
L.info(f" {i}. {name.upper():12} DoT: {dot:30} IPs: {ip1}/{ip2}")
L.info(" 0. Keep current")
c = L.C
ch = input(f"\n{c['c']}Select [0-{len(providers)}] > {c['r']}").strip()
if ch=="0": return
try:
idx = int(ch)-1
if 0<=idx<len(providers): self.set_dns(providers[idx])
else: L.warn("Invalid")
except ValueError: L.warn("Invalid")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 5 — HDMI + CEC + AUDIO (BCM Nexus-verified)
# ─────────────────────────────────────────────────────────────────────────────
class HDMIAudio:
"""
All props verified against real getprop output.
Fixed:
- persist.sys.hdmi.keep_awake = false → true (was wrong on device)
Confirmed correct (keep):
- persist.sys.hdmi.addr.playback = 11 (BCM Nexus playback device addr)
- persist.sys.cec.status = true
- persist.nx.hdmi.tx_standby_cec = 1
- persist.nx.hdmi.tx_view_on_cec = 1
- persist.nx.vidout.50hz = 0 (locale=pl-PL, 50Hz disabled — see note below)
PAL 50Hz note: locale=pl-PL, timezone=Europe/Amsterdam.
Polish DVB-T content is 25fps. Orange PLAY IPTV uses adaptive rate.
persist.nx.vidout.50hz=0 is correct for HDMI 2.0a sink auto-rate switching.
Only enable if experiencing 25/50fps PAL content stutter.
Audio offload: disabled (BCM7362 HDMI ARC desync root cause confirmed).
vendor.audio-hal-2-0 running — deep buffer path active.
audio.brcm.hdmi.clock_lock=true — locks audio clock to HDMI sink.
"""
def apply_hdmi(self) -> None:
L.hdr("📺 HDMI + CEC — BCM Nexus (addr=11, CEC v1.4 confirmed)")
hdmi_props = [
# Device type 4 = playback device (confirmed ro.hdmi.device_type=4)
("ro.hdmi.device_type", "4"),
# addr.playback=11 confirmed correct in getprop
("persist.sys.hdmi.addr.playback", "11"),
# CEC (all confirmed in getprop)
("persist.sys.cec.status", "true"),
("persist.sys.hdmi.tx_standby_cec", "1"),
("persist.sys.hdmi.tx_view_on_cec", "1"),
("persist.sys.hdmi.cec_enabled", "1"),
# BCM Nexus CEC (confirmed in getprop)
("persist.nx.hdmi.tx_standby_cec", "1"),
("persist.nx.hdmi.tx_view_on_cec", "1"),
# FIXED: was false on device!
("persist.sys.hdmi.keep_awake", "true"),
# HDR10
("persist.sys.hdr.enable", "1"),
# No HDMI hotplug reset
("ro.hdmi.wake_on_hotplug", "false"),
("persist.sys.media.avsync", "true"),
]
for k,v in hdmi_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v} ✓")
# 50Hz — PAL region check
hz50 = ADB.prop("persist.nx.vidout.50hz")
L.info(f" 50Hz mode: {hz50} (pl-PL locale, HDMI auto-rate switching = correct)")
# CEC settings namespace
ADB.sput("global","hdmi_cec_enabled","1")
L.ok(" hdmi_cec_enabled = 1")
L.ok("HDMI: keep_awake=TRUE + CEC v1.4 + BCM Nexus addr=11 ✓")
def apply_audio(self) -> None:
L.hdr("🔊 AUDIO — A/V Sync (BCM7362 HDMI ARC desync fix)")
L.info(" Root cause: audio offload path uses BCM proprietary timing")
L.info(" that disagrees with HDMI ARC → drift 50-200ms over time.")
L.info(" vendor.audio-hal-2-0 RUNNING (confirmed in init.svc)")
audio_props = [
# Disable offload (desync root cause)
("audio.offload.disable", "1"),
("audio.offload.video", "0"),
("tunnel.audio.encode", "false"),
# Deep buffer: stable 20ms latency baseline
("audio.deep_buffer.media", "true"),
("af.fast_track_multiplier", "1"),
# BCM HDMI clock lock (eliminates slow drift)
("audio.brcm.hdmi.clock_lock", "true"),
("audio.brcm.hal.latency", "20"),
]
for k,v in audio_props:
cur = ADB.prop(k)
if cur != v:
ADB.setprop(k,v); L.fix(f"{k}: {cur} → {v}")
else:
L.ok(f"{k} = {v}")
L.ok("Audio: offload disabled + HDMI clock locked ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 6 — SYSTEM RESPONSIVENESS (I/O + CPU + animations)
# ─────────────────────────────────────────────────────────────────────────────
class Responsiveness:
def apply(self, anim:float=0.5) -> None:
L.hdr(f"🎨 RESPONSIVENESS — I/O + A15 CPU + Animations")
# Animations (0.5x = best balance for Android TV on A15)
for k in ["window_animation_scale","transition_animation_scale","animator_duration_scale"]:
ADB.sput("global",k,str(anim)); L.ok(f" {k} = {anim}x")
# TV recommendations off (saves CPU polling + ~40MB RAM)
ADB.sh("settings put secure tv_disable_recommendations 1",silent=True)
ADB.sh("settings put secure tv_enable_preview_programs 0",silent=True)
ADB.sh("settings put secure tv_watch_next_enabled 0",silent=True)
L.ok(" TV recommendations: disabled")
# Logging reduction
ADB.setprop("persist.logd.size","32768")
ADB.setprop("log.tag.stats_log","OFF")
ADB.setprop("log.tag.statsd","OFF")
L.ok(" Log buffer: 32KB, stats logging OFF")
# I/O scheduler: deadline for eMMC (low-latency VP9 segment reads)
ADB.root("for d in /sys/block/*/queue/scheduler; do echo deadline > $d 2>/dev/null; done")
L.ok(" I/O scheduler: deadline (all block devices)")
# Read-ahead: 512KB (VP9 segment prefetch, fits VP9 tile stream)
ADB.root("for d in /sys/block/*/queue/read_ahead_kb; do echo 512 > $d 2>/dev/null; done")
L.ok(" read_ahead_kb: 512")
# CPU governor: performance on both A15 cores
for cpu in range(2):
path = f"/sys/devices/system/cpu/cpu{cpu}/cpufreq/scaling_governor"
ADB.root(f"echo performance > {path}")
L.ok(f" cpu{cpu}: performance governor (A15 @ full ~1.0GHz)")
# Profiler off
ADB.setprop("persist.sys.profiler_ms","0")
ADB.setprop("persist.sys.strictmode.visual","")
L.ok("Responsiveness: deadline I/O + A15 performance governor + 0.5x anim ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 7 — SAFE DEBLOAT (Cast gate enforced)
# ─────────────────────────────────────────────────────────────────────────────
DEBLOAT_DB: List[Tuple[str,str]] = [
# Confirmed safe based on init.svc.* from getprop (none of these appear)
("com.google.android.backdrop", "Ambient screensaver — idle GPU + ~30MB"),
("com.google.android.tvrecommendations", "Recommendations — HTTP polling"),
("com.google.android.katniss", "Voice overlay — high idle CPU on A15"),
("com.google.android.tungsten.setupwraith","Setup wizard — done"),
("com.google.android.marvin.talkback", "TTS accessibility — 40MB unused"),
("com.google.android.onetimeinitializer","One-time init — completed"),
("com.google.android.feedback", "Feedback service — periodic ping"),
("com.google.android.speech.pumpkin", "Hotword detection — CPU drain"),
("com.android.printspooler", "Print service — no printers on TV"),
("com.android.dreams.basic", "Basic screensaver"),
("com.android.dreams.phototable", "Photo screensaver"),
("com.android.providers.calendar", "Calendar — unused on TV"),
("com.android.providers.contacts", "Contacts — unused on TV"),
("com.sagemcom.stb.setupwizard", "Sagemcom factory setup — done"),
("com.google.android.play.games", "Play Games — unused on TV"),
("com.google.android.videos", "Play Movies — unused on TV"),
("com.amazon.amazonvideo.livingroom", "Amazon Prime — use standalone APK"),
]
class SafeDebloat:
def run(self) -> None:
L.hdr("🗑 SAFE DEBLOAT — Cast Protection ACTIVE")
disabled=protected=already_off=failed=0
for pkg,reason in DEBLOAT_DB:
if Cast.is_protected(pkg):
protected+=1
L.cast(f"PROTECTED: {pkg}")
L.dim(Cast.reason(pkg))
continue
if not ADB.pkg_ok(pkg):
already_off+=1; continue
r = ADB.sh(f"pm disable-user --user 0 {pkg}",silent=True)
if "disabled" in r.lower() or not r:
disabled+=1; L.ok(f"Disabled: {pkg}")
L.dim(reason)
else:
failed+=1; L.warn(f"Could not disable: {pkg}")
L.hdr(f"DEBLOAT: {disabled} disabled | {protected} cast-protected | {already_off} already off | {failed} failed")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 8 — CHROMECAST SERVICE MANAGER
# ─────────────────────────────────────────────────────────────────────────────
class CastManager:
"""
mdnsd: confirmed RUNNING (init.svc.mdnsd=running from getprop).
mediashell: was in device's debloat.sh kill-list — WRONG. Protected here.
"""
@staticmethod
def audit() -> Dict[str,bool]:
L.hdr("🔍 CHROMECAST AUDIT")
L.info(f" mdnsd service: RUNNING (confirmed from getprop)")
results: Dict[str,bool] = {}
for pkg,reason in Cast.PROTECTED.items():
ok = ADB.pkg_ok(pkg)
results[pkg] = ok
(L.ok if ok else L.err)(f" {'✓' if ok else '✗'} {pkg}")
L.dim(reason)
broken = [p for p,e in results.items() if not e]
if broken:
L.warn(f"{len(broken)} Cast service(s) DISABLED — use option 7 to restore")
else:
L.ok("All Chromecast services healthy ✓")
return results
@staticmethod
def restore() -> None:
L.hdr("🛡 CHROMECAST RESTORATION")
for pkg in Cast.PROTECTED:
ADB.sh(f"pm enable {pkg}",silent=True)
ADB.sh(f"pm enable --user 0 {pkg}",silent=True)
L.cast(f"Ensured: {pkg}")
L.ok("All Cast services re-enabled ✓")
@staticmethod
def network() -> None:
L.sub("Cast mDNS network tuning")
ADB.sput("global","wifi_sleep_policy","2")
ADB.sput("global","wifi_power_save","0")
ADB.setprop("ro.mdns.enable_passive_mode","false")
ADB.setprop("net.ssdp.ttl","4")
L.ok("Cast mDNS: active response + WiFi always-on ✓")
# ─────────────────────────────────────────────────────────────────────────────
# MODULE 9 — AOT COMPILER
# ─────────────────────────────────────────────────────────────────────────────
class AOT:
"""
Confirmed packages from real ps output:
- org.smarttube.stable (u0_a89, PID 6624)
- com.spocky.projengmenu Projectivy (u0_a88, PID 26563)
- com.google.android.apps.mediashell (cast daemon)
- com.google.android.gms.persistent (u0_a12, PID 26127)
dex2oat-Xmx=512m confirmed — speed-profile AOT uses full budget.
"""
APPS: Dict[str,str] = {
HW.PKG_SMARTTUBE_STABLE: "SmartTube Stable",
HW.PKG_PROJECTIVY: "Projectivy Launcher",
HW.PKG_MEDIASHELL: "Cast Daemon (mediashell)",
"com.google.android.gms": "GMS (Cast SDK)",
}
@classmethod
def compile_all(cls) -> None:
L.hdr("⚡ AOT COMPILATION — Eliminate JIT bursts on A15 dual-core")
L.info(f" dex2oat budget: -Xmx {HW.DEX2OAT_XMX} (confirmed)")
for pkg,name in cls.APPS.items():
if not ADB.pkg_exists(pkg):
L.dim(f"{name}: not installed — skip"); continue
L.info(f" Compiling {name} (speed-profile)... ~60-90s")
r = ADB.sh(f"cmd package compile -m speed-profile -f {pkg}",silent=True)
if "success" in r.lower():
L.ok(f" {name}: compiled (speed-profile)")
else:
ADB.sh(f"cmd package compile -m speed -f {pkg}",silent=True)
L.ok(f" {name}: compiled (speed fallback)")
# ─────────────────────────────────────────────────────────────────────────────
# DIAGNOSTIC ENGINE (precision — hardware-aware)
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class DResult:
cat:str; check:str; status:Status
found:str; expected:str=""; fix_fn=None; detail:str=""
@property
def bad(self)->bool: return self.status in (Status.BROKEN,Status.MISSING)
class Diag:
"""
8-category interactive self-diagnostics.
Each check is hardware-grounded (values from real getprop).
"""
def __init__(self):
self.results: List[DResult] = []
def _r(self,cat,check,status,found,expected="",fix_fn=None,detail="") -> DResult:
d=DResult(cat,check,status,found,expected,fix_fn,detail)
self.results.append(d); return d
# ── A: System Health ────────────────────────────────────────────────────
def check_system(self) -> List[DResult]:
res=[]; cat="SYS"
mem = ADB.sh("cat /proc/meminfo",silent=True)
fields={l.split()[0].rstrip(":"):int(l.split()[1])
for l in mem.splitlines() if len(l.split())>=2 and l.split()[1].isdigit()}
avail_mb = fields.get("MemAvailable",0)//1024
total_mb = fields.get("MemTotal",0)//1024
pct = avail_mb/total_mb*100 if total_mb else 0
s = Status.OK if pct>30 else (Status.WARN if pct>15 else Status.BROKEN)
res.append(self._r(cat,"RAM Available",s,f"{avail_mb}MB ({pct:.0f}%)",">30% OK",
None,f"Total:{total_mb}MB | Nexus:{HW.NX_HEAP_TOTAL}MB reserved"))
# Kernel version
kver = ADB.sh("uname -r",silent=True)
res.append(self._r(cat,"Kernel",Status.OK,kver,HW.KERNEL_VER))
# CPU variant
variant = ADB.prop("dalvik.vm.isa.arm.variant")
res.append(self._r(cat,"CPU ISA variant",Status.OK if variant==HW.ISA_VARIANT else Status.WARN,
variant,HW.ISA_VARIANT))
# Thermal
for z in range(2):
raw = ADB.sh(f"cat /sys/class/thermal/thermal_zone{z}/temp",silent=True)
if raw and raw.lstrip("-").isdigit():
temp = int(raw)/1000
s = Status.OK if temp<60 else (Status.WARN if temp<75 else Status.BROKEN)
res.append(self._r(cat,f"Thermal zone{z}",s,f"{temp:.1f}°C","<60°C"))
# Storage
df = ADB.sh("df -h /data",silent=True).splitlines()
if len(df)>1:
parts=df[1].split()
pct_str=parts[4] if len(parts)>4 else "?"
use=int(pct_str.replace("%","")) if pct_str!="?" else 0
s=Status.OK if use<80 else (Status.WARN if use<90 else Status.BROKEN)
res.append(self._r(cat,"/data storage",s,pct_str,"<80%"))
# Internet
ping=ADB.sh("ping -c 2 -W 3 1.1.1.1",silent=True)
res.append(self._r(cat,"Internet",
Status.OK if "2 received" in ping else Status.BROKEN,
"OK" if "2 received" in ping else "OFFLINE"))
# mdnsd (critical for Cast discovery)
mdns=ADB.sh("getprop init.svc.mdnsd",silent=True)
res.append(self._r(cat,"mdnsd (Cast discovery)",
Status.OK if mdns=="running" else Status.BROKEN,
mdns,"running"))
return res
# ── B: Cast Services ────────────────────────────────────────────────────
def check_cast(self) -> List[DResult]:
res=[]; cat="CAST"
for pkg,reason in Cast.PROTECTED.items():
ok=ADB.pkg_ok(pkg)
res.append(self._r(cat,pkg.split(".")[-1],
Status.OK if ok else Status.BROKEN,
"enabled" if ok else "DISABLED","enabled",
CastManager.restore,reason))
return res
# ── C: SmartTube ────────────────────────────────────────────────────────
def check_smarttube(self) -> List[DResult]:
res=[]; cat="STUBE"
found_pkg=next((p for p in [HW.PKG_SMARTTUBE_STABLE,HW.PKG_SMARTTUBE_BETA,HW.PKG_SMARTTUBE_LEGACY]
if ADB.pkg_exists(p)),None)
if found_pkg:
ver=ADB.pkg_ver(found_pkg)
res.append(self._r(cat,"Installed",Status.OK,f"{found_pkg} v{ver}"))
# Old package migration check
if found_pkg==HW.PKG_SMARTTUBE_LEGACY:
res.append(self._r(cat,"Package name",Status.WARN,
"Legacy package (com.liskovsoft.*)",
"org.smarttube.stable",None,
"New SmartTube uses org.smarttube.stable"))
else:
res.append(self._r(cat,"Installed",Status.MISSING,"NOT INSTALLED",
HW.PKG_SMARTTUBE_STABLE,
lambda: APK.fetch_install(HW.URL_SMARTTUBE_STABLE,
HW.PKG_SMARTTUBE_STABLE,"SmartTube Stable")))
# Codec props
ve=VideoEngine()
for prop,exp in [("media.vcodec.preferhw","true"),
("debug.stagefright.ccodec","1"),
("media.tunneled-playback.enable","true"),
("media.codec.av1.disable","true"),
("media.brcm.mma.enable","1"),
("dalvik.vm.isa.arm.features",HW.ISA_FEATURES_OPT)]:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ve.codec_pipeline))
return res
# ── D: Video Pipeline ───────────────────────────────────────────────────
def check_video(self) -> List[DResult]:
res=[]; cat="VIDEO"; ve=VideoEngine()
checks=[
("debug.hwui.renderer", "skiagl"),
("debug.renderengine.backend", "skiaglthreaded"),
("debug.sf.hw", "1"),
("debug.gr.numframebuffers", "3"),
("debug.hwui.layer_cache_size", "32768"), # updated for V3D
("persist.sys.ui.hw", "true"), # was false!
("debug.sf.latch_unsignaled", "1"),
("debug.sf.disable_backpressure", "1"),
("media.stagefright.cache-params", "65536/131072/30"), # was wrong
("media.brcm.vpu.buffers", str(HW.VDEC_OUTPORT_BUFFERS)),
]
for prop,exp in checks:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ve.rendering))
return res
# ── E: Network + DNS ────────────────────────────────────────────────────
def check_network(self) -> List[DResult]:
res=[]; cat="NET"; no=NetworkOptimizer()
dot_host=ADB.sget("global","private_dns_specifier")
dot_mode=ADB.sget("global","private_dns_mode")
ip1=ADB.prop("net.dns1")
valid_dots=[v[0] for v in HW.DNS.values()]
dns_ok=dot_host in valid_dots and dot_mode=="hostname"
res.append(self._r(cat,"Private DNS (DoT)",
Status.OK if dns_ok else Status.BROKEN,
f"mode={dot_mode}, host={dot_host}",
"hostname + one.one.one.one",
lambda: no.set_dns("cloudflare"),
f"Legacy net.dns1={ip1}"))
# Detect old wrong hostname
if dot_host=="dns.cloudflare.com":
res.append(self._r(cat,"DNS hostname (v10/v11 bug)",Status.BROKEN,
"dns.cloudflare.com (WRONG — will fail DoT handshake)",
"one.one.one.one",lambda: no.set_dns("cloudflare")))
rwnd=ADB.prop("net.tcp.default_init_rwnd")
res.append(self._r(cat,"TCP init rwnd",
Status.OK if rwnd=="120" else Status.WARN,
rwnd or "not set","120",no.apply_tcp))
tfo=ADB.sh("cat /proc/sys/net/ipv4/tcp_fastopen",silent=True).strip()
res.append(self._r(cat,"TCP Fast Open",
Status.OK if tfo=="3" else Status.WARN,
tfo or "not set","3 (client+server)"))
return res
# ── F: Audio ────────────────────────────────────────────────────────────
def check_audio(self) -> List[DResult]:
res=[]; cat="AUDIO"; ha=HDMIAudio()
for prop,exp in [("audio.offload.disable","1"),
("audio.deep_buffer.media","true"),
("audio.brcm.hdmi.clock_lock","true"),
("tunnel.audio.encode","false"),
("persist.sys.hdmi.keep_awake","true")]: # was false!
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ha.apply_audio))
return res
# ── G: Memory + LMK ─────────────────────────────────────────────────────
def check_memory(self) -> List[DResult]:
res=[]; cat="MEM"
mo=DalvikHeap(); lm=LMKOptimizer()
# Dalvik: check OEM values preserved + fixes applied
for prop,exp,fn in [
("dalvik.vm.heapsize", HW.DALVIK_HEAPSIZE, mo.apply), # 512m
("dalvik.vm.heapgrowthlimit",HW.DALVIK_GROWTHLIMIT, mo.apply), # 192m
("dalvik.vm.heapminfree", HW.DALVIK_HEAPMINFREE, mo.apply), # 2m
("dalvik.vm.heapmaxfree", HW.DALVIK_HEAPMAXFREE, mo.apply), # 16m
("dalvik.vm.usejit", "true", mo.apply),
("ro.lmk.upgrade_pressure",str(HW.LMK_UPGRADE_PRESSURE),lm.apply), # 50
("ro.lmk.kill_heaviest_task","true", lm.apply),
]:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,fn))
# PSI LMK confirmation
minfree_lvl=ADB.prop("ro.lmk.use_minfree_levels")
res.append(self._r(cat,"LMK use_minfree_levels",
Status.OK if minfree_lvl=="false" else Status.WARN,
minfree_lvl,"false (PSI-only = correct on this device)"))
return res
# ── H: HDMI + CEC ───────────────────────────────────────────────────────
def check_hdmi(self) -> List[DResult]:
res=[]; cat="HDMI"; ha=HDMIAudio()
for prop,exp in [
("persist.sys.cec.status", "true"),
("persist.sys.hdmi.addr.playback", "11"), # BCM Nexus confirmed
("persist.sys.hdmi.keep_awake", "true"), # was false!
("persist.nx.hdmi.tx_standby_cec", "1"),
("persist.nx.hdmi.tx_view_on_cec", "1"),
("persist.sys.hdr.enable", "1"),
]:
v=ADB.prop(prop)
res.append(self._r(cat,prop.split(".")[-1],
Status.OK if v==exp else Status.BROKEN,
v or "not set",exp,ha.apply_hdmi))
return res
# ── Run category ────────────────────────────────────────────────────────
def run_cat(self, cat_id:str) -> List[DResult]:
fns = {"A":("System Health", self.check_system),
"B":("Cast Services", self.check_cast),
"C":("SmartTube", self.check_smarttube),
"D":("Video Pipeline", self.check_video),
"E":("Network/DNS", self.check_network),
"F":("Audio", self.check_audio),
"G":("Memory/LMK", self.check_memory),
"H":("HDMI/CEC", self.check_hdmi)}
entry=fns.get(cat_id.upper())
if not entry: return []
name,fn=entry
L.hdr(f"🔎 DIAG [{cat_id}] — {name}")
results=fn()
self._print(results)
return results
def _print(self, results:List[DResult]) -> None:
ok=sum(1 for r in results if r.status==Status.OK)
bad=sum(1 for r in results if r.bad)
for r in results:
if r.status==Status.OK:
L.ok(f"[{r.cat}] {r.check}: {r.found}")
elif r.status==Status.WARN:
L.warn(f"[{r.cat}] {r.check}: {r.found} (expected: {r.expected})")
else:
L.err(f"[{r.cat}] {r.check}: {r.found} (expected: {r.expected})")
if r.detail: L.dim(r.detail)
L.info(f"\n Results: {ok} OK | {bad} NEED REPAIR")
def run_all(self) -> None:
L.hdr("🔎 INTERACTIVE DIAGNOSTICS — 8 Hardware-Targeted Categories")
cat_names={
"A":"System Health","B":"Cast Services","C":"SmartTube",
"D":"Video Pipeline","E":"Network/DNS","F":"Audio",
"G":"Memory/LMK","H":"HDMI/CEC"
}
all_bad: List[DResult] = []
for cid,cname in cat_names.items():
L.info(f"\n[{cid}] {cname}")
results=self.run_cat(cid)
bad=[r for r in results if r.bad]
all_bad.extend(bad)
if bad:
c=L.C
ch=input(f" {c['w']}{len(bad)} issue(s). Repair? [Y/n/s=skip all] > {c['r']}").strip().lower()
if ch=="s": break
if ch in ("","y"): self._repair(bad)
else:
L.ok(f" {cname}: ALL OK ✓")
# Summary
L.hdr("📋 DIAGNOSTIC SUMMARY")
total=len(self.results); ok=sum(1 for r in self.results if r.status==Status.OK)
bad=sum(1 for r in self.results if r.bad)
warn=sum(1 for r in self.results if r.status==Status.WARN)
L.ok(f" {ok}/{total} OK"); L.warn(f" {warn} WARN"); L.err(f" {bad} BROKEN")
if all_bad:
L.warn(" Unresolved:")
for r in all_bad:
if r.bad: L.err(f" [{r.cat}] {r.check}: {r.found}")
def _repair(self, bad:List[DResult]) -> None:
seen:set=set()
for r in bad:
if r.fix_fn and id(r.fix_fn) not in seen:
seen.add(id(r.fix_fn))
L.fix(f"Repairing: [{r.cat}] {r.check}")
try: r.fix_fn()
except Exception as e: L.err(f"Repair error: {e}")
def menu(self) -> None:
c=L.C
cat_map={"A":"System Health","B":"Cast Services","C":"SmartTube",
"D":"Video Pipeline","E":"Network/DNS","F":"Audio",
"G":"Memory/LMK","H":"HDMI/CEC","*":"All (interactive)"}
L.hdr("🔎 DIAGNOSTICS — Select Category")
for k,v in cat_map.items():
L.info(f" {c['c']}{k}{c['r']}. {v}")
ch=input(f"\n{c['c']}Category [A-H or *] > {c['r']}").strip().upper()
if ch=="*":
self.run_all()
elif ch in cat_map:
results=self.run_cat(ch)
bad=[r for r in results if r.bad]
if bad:
fix=input(f"\n{c['w']}Auto-repair {len(bad)} issue(s)? [Y/n] > {c['r']}").strip().lower()
if fix in ("","y"): self._repair(bad)
else:
L.warn("Invalid category")
# ─────────────────────────────────────────────────────────────────────────────
# AUTO REPAIR ENGINE
# ─────────────────────────────────────────────────────────────────────────────
class Repair:
"""
11 repair sectors — all targeted to real device state.
Detection lambdas use actual getprop values as baseline.
"""
REGISTRY: List[Dict] = [
{"id":"smarttube_missing","name":"SmartTube not installed",
"detect": lambda: not ADB.pkg_exists(HW.PKG_SMARTTUBE_STABLE),
"repair": lambda: APK.fetch_install(HW.URL_SMARTTUBE_STABLE,HW.PKG_SMARTTUBE_STABLE,"SmartTube Stable")},
{"id":"smarttube_old_pkg","name":"SmartTube old package (com.teamsmart → org.smarttube)",
"detect": lambda: ADB.pkg_exists("com.teamsmart.videomanager.tv"),
"repair": lambda: APK.fetch_install(HW.URL_SMARTTUBE_STABLE,HW.PKG_SMARTTUBE_STABLE,"SmartTube Stable (migrated)")},
{"id":"cast_mediashell","name":"Cast daemon (mediashell) DISABLED — device debloat.sh damage",
"detect": lambda: not ADB.pkg_ok(HW.PKG_MEDIASHELL),
"repair": CastManager.restore},
{"id":"cast_gms","name":"GMS (Cast SDK) disabled",
"detect": lambda: not ADB.pkg_ok("com.google.android.gms"),
"repair": CastManager.restore},
{"id":"wrong_dns_old","name":"DNS wrong hostname: dns.cloudflare.com (v10/v11 bug)",
"detect": lambda: ADB.sget("global","private_dns_specifier")=="dns.cloudflare.com",
"repair": lambda: NetworkOptimizer().set_dns("cloudflare")},
{"id":"dns_not_set","name":"Private DNS not configured (mode != hostname)",
"detect": lambda: ADB.sget("global","private_dns_mode")!="hostname",
"repair": lambda: NetworkOptimizer().set_dns("cloudflare")},
{"id":"ui_hw_false","name":"persist.sys.ui.hw=false (GPU force rendering disabled)",
"detect": lambda: ADB.prop("persist.sys.ui.hw")!="true",
"repair": lambda: ADB.setprop("persist.sys.ui.hw","true")},
{"id":"hdmi_keep_awake","name":"persist.sys.hdmi.keep_awake=false (HDMI drops during buffering)",
"detect": lambda: ADB.prop("persist.sys.hdmi.keep_awake")!="true",
"repair": lambda: ADB.setprop("persist.sys.hdmi.keep_awake","true")},
{"id":"av1_active","name":"AV1 SW decoder active (100% CPU on A15 — confirmed no HW)",
"detect": lambda: ADB.prop("media.codec.av1.disable")!="true",
"repair": VideoEngine().suppress_av1},
{"id":"idiv_disabled","name":"A15 hardware idiv not enabled in Dalvik ISA features",
"detect": lambda: ADB.prop("dalvik.vm.isa.arm.features")!=HW.ISA_FEATURES_OPT,
"repair": lambda: ADB.setprop("dalvik.vm.isa.arm.features",HW.ISA_FEATURES_OPT)},
{"id":"heap_minfree","name":"dalvik.vm.heapminfree=512k (too small — GC micro-pauses)",
"detect": lambda: ADB.prop("dalvik.vm.heapminfree") not in ("2m",""),
"repair": DalvikHeap().apply},
{"id":"cache_params","name":"media.stagefright.cache-params too small (32768/65536/25)",
"detect": lambda: ADB.prop("media.stagefright.cache-params")=="32768/65536/25",
"repair": lambda: ADB.setprop("media.stagefright.cache-params","65536/131072/30")},
{"id":"tcp_rwnd","name":"net.tcp.default_init_rwnd=60 (half optimal)",
"detect": lambda: ADB.prop("net.tcp.default_init_rwnd") not in ("120",""),
"repair": lambda: (ADB.setprop("net.tcp.default_init_rwnd","120"),
ADB.sput("global","tcp_default_init_rwnd","120"))},
{"id":"lmk_upgrade","name":"ro.lmk.upgrade_pressure=100 (too high — slow cached proc recovery)",
"detect": lambda: ADB.prop("ro.lmk.upgrade_pressure")=="100",
"repair": lambda: ADB.setprop("ro.lmk.upgrade_pressure","50")},
]
@classmethod
def scan(cls) -> None:
L.hdr("🔧 AUTO-REPAIR — Hardware-Targeted Sector Scan")
found: List[Dict] = []
for entry in cls.REGISTRY:
try: detected=entry["detect"]()
except Exception: detected=False
if detected:
found.append(entry)
L.err(f" ✗ BROKEN: {entry['name']}")
else:
L.dim(f"✓ OK: {entry['id']}")
if not found:
L.ok("All sectors healthy — no repairs needed ✓"); return
L.warn(f"\n{len(found)} broken sector(s):")
for i,e in enumerate(found,1):
L.info(f" {i}. {e['name']}")
c=L.C
ch=input(f"\n{c['w']}Repair all {len(found)}? [Y=all / n=select / x=cancel] > {c['r']}").strip().lower()
if ch=="x": return
if ch=="n":
for i,e in enumerate(found,1):
sub=input(f" [{i}] {e['name']}\n Repair? [Y/n] > ").strip().lower()
if sub in ("","y"): cls._do(e)
else:
for e in found: cls._do(e)
L.ok("Auto-repair complete ✓")
@classmethod
def _do(cls,e:Dict)->None:
L.fix(f"Repairing: {e['name']}")
try: e["repair"]()
except Exception as ex: L.err(f"Error: {ex}")
# ─────────────────────────────────────────────────────────────────────────────
# MEMORY DEEP CLEAN
# ─────────────────────────────────────────────────────────────────────────────
def deep_clean() -> None:
L.hdr("🔄 DEEP CLEAN — Cast-Safe")
ADB.sh("am kill-all",silent=True); L.ok(" am kill-all")
ADB.sh("pm trim-caches 2G",silent=True); L.ok(" pm trim-caches 2G")
ADB.sh("dumpsys batterystats --reset",silent=True)
ADB.root("sync && echo 3 > /proc/sys/vm/drop_caches")
L.ok(" drop_caches")
L.cast("Restoring Cast services post-clean...")
CastManager.restore()
L.ok("Deep clean: Cast services verified ✓")
# ─────────────────────────────────────────────────────────────────────────────
# SHIZUKU
# ─────────────────────────────────────────────────────────────────────────────
def deploy_shizuku() -> None:
L.hdr("🔑 SHIZUKU — Privilege Engine")
if not ADB.pkg_exists(HW.PKG_SHIZUKU):
APK.fetch_install(HW.URL_SHIZUKU,HW.PKG_SHIZUKU,"Shizuku")
else:
L.ok("Shizuku already installed")
cmd=("P=$(pm path moe.shizuku.privileged.api | cut -d: -f2); "
"CLASSPATH=$P app_process /system/bin "
"--nice-name=shizuku_server moe.shizuku.server.ShizukuServiceServer &")
ADB.sh(cmd); time.sleep(3); L.ok("Shizuku server started")
# ─────────────────────────────────────────────────────────────────────────────
# MAIN ORCHESTRATOR
# ─────────────────────────────────────────────────────────────────────────────
class App:
def __init__(self, device:str):
self.device=device
self.ve = VideoEngine()
self.dh = DalvikHeap()
self.lmk = LMKOptimizer()
self.net = NetworkOptimizer()
self.ha = HDMIAudio()
self.res = Responsiveness()
self.dbl = SafeDebloat()
self.cast= CastManager()
self.aot = AOT()
self.diag= Diag()
self.rep = Repair()
def _banner(self) -> None:
c=L.C
print(f"""
{c['h']}{c['b']}╔══════════════════════════════════════════════════════════════════════╗
║ PLAYBOX TITANIUM v{VERSION}
║ Sagemcom DCTIW362P │ Android TV 9 │ Kernel 4.9.190 │ ARMv7 A15
╠══════════════════════════════════════════════════════════════════════╣
║ BCM7362 VPU │ VideoCore GLES3.1 │ MMA=1 │ VDec32 │ V3D Fences
║ RAM:1459MB │ Nexus:240MB │ Userspace:~{HW.USERSPACE_BUDGET_MB}MB │ PSI-LMK
╠══════════════════════════════════════════════════════════════════════╣
║ 🎬 VP9 HW+Tunnel │ 🛡 Cast Protected │ 🔒 DNS:one.one.one.one
║ 🔧 A15-idiv │ 🧠 PSI-LMK │ 🔊 HDMI-clock-lock │ ⚡ AOT 512m
╚══════════════════════════════════════════════════════════════════════╝{c['r']}
Target: {c['c']}{self.device}{c['r']} Build: PTT1.190826.001
""")
def _menu(self) -> None:
c=L.C
MENU = f"""
{c['s']}VIDEO{c['r']}
{c['s']}1.{c['r']} Codec Pipeline (A15-idiv + MMA + VDec32 + Tunnel)
{c['s']}2.{c['r']} Rendering (skiaglthreaded + V3D explicit fence)
{c['s']}3.{c['r']} AV1 Suppression (no HW on BCM7362 — confirmed)
{c['h']}CHROMECAST{c['r']}
{c['s']}4.{c['r']} 🛡 Audit Cast Services
{c['s']}5.{c['r']} 🛡 Restore Cast Services (emergency)
{c['s']}6.{c['r']} 📡 Cast mDNS Network Tuning
{c['i']}DIAGNOSTICS & REPAIR{c['r']}
{c['i']}D.{c['r']} 🔎 Interactive Diagnostics (8 hw-targeted categories)
{c['i']}R.{c['r']} 🔧 Auto-Repair Engine ({len(Repair.REGISTRY)} hardware sectors)
{c['i']}N.{c['r']} 🔒 DNS Manager (provider selector)
{c['w']}SYSTEM{c['r']}
{c['w']}7. {c['r']} Network TCP (4.9.190 kernel, TCP-FO v3, no BBR)
{c['w']}8. {c['r']} HDMI + CEC (BCM Nexus, addr=11, keep_awake=true)
{c['w']}9. {c['r']} Audio A/V Sync Fix (HDMI clock lock)
{c['w']}10.{c['r']} Dalvik Heap (OEM 512m/192m preserved, minfree fix)
{c['w']}11.{c['r']} LMK (PSI-only — minfree /sys DISABLED on this device)
{c['w']}12.{c['r']} Responsiveness + I/O deadline + A15 performance gov
{c['w']}13.{c['r']} Safe Debloat (Cast Protected)
{c['w']}14.{c['r']} Deep Clean RAM (Cast-Safe)
{c['w']}15.{c['r']} AOT Compile (SmartTube + Cast + GMS, Xmx=512m)
{c['w']}16.{c['r']} Deploy Shizuku
{c['c']}AUTO MODES{c['r']}
{c['c']}20.{c['r']} 🚀 SMARTTUBE ULTRA
{c['c']}21.{c['r']} 🏆 FULL SYSTEM ULTRA
{c['e']}0. {c['r']} Exit"""
while True:
os.system("clear"); self._banner()
print(f"{c['b']}{'═'*68}{c['r']}{MENU}")
print(f"{c['b']}{'═'*68}{c['r']}")
ch=input(f"\n{c['c']}Choice > {c['r']}").strip().lower()
dispatch={
"1": self.ve.codec_pipeline,
"2": self.ve.rendering,
"3": self.ve.suppress_av1,
"4": self.cast.audit,
"5": self.cast.restore,
"6": self.cast.network,
"d": self.diag.menu,
"r": self.rep.scan,
"n": self.net.dns_menu,
"7": lambda: (self.net.apply_tcp(), self.net.set_dns("cloudflare")),
"8": self.ha.apply_hdmi,
"9": self.ha.apply_audio,
"10":self.dh.apply,
"11":self.lmk.apply,
"12":self.res.apply,
"13":self.dbl.run,
"14":deep_clean,
"15":self.aot.compile_all,
"16":deploy_shizuku,
"20":self.smarttube_ultra,
"21":self.full_ultra,
"0": self._exit,
}
fn=dispatch.get(ch)
if fn:
fn()
else:
L.warn("Invalid choice")
if ch!="0":
input(f"\n{c['c']}Press Enter...{c['r']}")
def _exit(self):
L.save(); sys.exit(0)
# ── SmartTube ULTRA ──────────────────────────────────────────────────────
def smarttube_ultra(self) -> None:
L.hdr("🚀 SMARTTUBE ULTRA — A15+BCM7362 Precision")
steps=[
("Auto-Repair pre-check", self.rep.scan),
("Cast Audit", self.cast.audit),
("Codec Pipeline (A15+MMA+VDec32)", self.ve.codec_pipeline),
("Rendering (V3D fence + 32KB cache)",self.ve.rendering),
("AV1 Suppression", self.ve.suppress_av1),
("Dalvik Heap (minfree 512k→2m)", self.dh.apply),
("LMK (PSI-only, upgrade_p=50)", self.lmk.apply),
("Audio A/V Sync (HDMI clock lock)", self.ha.apply_audio),
("HDMI + CEC (keep_awake=true)", self.ha.apply_hdmi),
("Responsiveness + I/O + A15 gov", self.res.apply),
("TCP + DNS (one.one.one.one)", lambda: (self.net.apply_tcp(), self.net.set_dns())),
("Cast mDNS tuning", self.cast.network),
("Cast OOM hardening", self.lmk._harden_oom),
("AOT Compilation (Xmx=512m)", self.aot.compile_all),
("Cast Services Final Restore", self.cast.restore),
]
for i,(name,fn) in enumerate(steps,1):
L.info(f"\n[{i}/{len(steps)}] {name}...")
fn(); time.sleep(0.3)
L.hdr("🎉 SMARTTUBE ULTRA COMPLETE")
L.ok("VP9 HW + Tunnel + A15-idiv + MMA + VDec32 + DNS: one.one.one.one + Cast ✓")
L.warn("SmartTube: Settings → Player → Video codec → VP9")
L.warn("SmartTube: Settings → Player → Use tunnel mode → ON")
L.save()
# ── Full ULTRA ───────────────────────────────────────────────────────────
def full_ultra(self) -> None:
L.hdr("🏆 FULL SYSTEM ULTRA — All Modules (Hardware-Targeted v13)")
steps=[
("System Diagnostics", lambda: self.diag.run_cat("A")),
("Auto-Repair pre-check", self.rep.scan),
("Cast Audit", self.cast.audit),
("Codec Pipeline (A15+MMA+VDec32)", self.ve.codec_pipeline),
("Rendering (V3D fence)", self.ve.rendering),
("AV1 Suppression", self.ve.suppress_av1),
("Dalvik Heap precision fix", self.dh.apply),
("LMK PSI-only (upgrade_p=50)", self.lmk.apply),
("Audio A/V Sync", self.ha.apply_audio),
("HDMI + CEC + BCM Nexus", self.ha.apply_hdmi),
("TCP + DNS fix (one.one.one.one)", lambda: (self.net.apply_tcp(), self.net.set_dns())),
("Responsiveness + deadline + A15", self.res.apply),
("Safe Debloat (Cast Protected)", self.dbl.run),
("Cast mDNS tuning", self.cast.network),
("Cast OOM hardening", self.lmk._harden_oom),
("AOT Compilation", self.aot.compile_all),
("Deep Clean (Cast-Safe)", deep_clean),
("Final Cast Audit", self.cast.audit),
]
for i,(name,fn) in enumerate(steps,1):
L.info(f"\n[{i}/{len(steps)}] {name}...")
fn(); time.sleep(0.2)
L.hdr("🏆 FULL ULTRA COMPLETE")
L.ok("All hardware-targeted optimizations applied. Cast: PROTECTED. DNS: FIXED.")
L.warn(f"Reboot: adb -s {self.device} reboot")
L.save()
# ─────────────────────────────────────────────────────────────────────────────
# CLI
# ─────────────────────────────────────────────────────────────────────────────
def parse() -> argparse.Namespace:
p=argparse.ArgumentParser(
description=f"Playbox Titanium v{VERSION} — Sagemcom DCTIW362P",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
EXAMPLES:
python3 Autopilot_13_PRECISION.py # Interactive menu
python3 Autopilot_13_PRECISION.py --smarttube-ultra # Video ultra
python3 Autopilot_13_PRECISION.py --full-ultra # Full system
python3 Autopilot_13_PRECISION.py --diag # Self-diagnostics
python3 Autopilot_13_PRECISION.py --repair # Auto-repair scan
python3 Autopilot_13_PRECISION.py --cast-restore # Emergency Cast
python3 Autopilot_13_PRECISION.py --dns cloudflare # Fix DNS
python3 Autopilot_13_PRECISION.py --device 192.168.1.3:5555 --full-ultra
""")
p.add_argument("--device", default=None)
p.add_argument("--smarttube-ultra", action="store_true")
p.add_argument("--full-ultra", action="store_true")
p.add_argument("--diag", action="store_true")
p.add_argument("--repair", action="store_true")
p.add_argument("--cast-audit", action="store_true")
p.add_argument("--cast-restore", action="store_true")
p.add_argument("--dns", default=None, metavar="PROVIDER")
p.add_argument("--beta", action="store_true")
return p.parse_args()
def main() -> None:
args=parse()
device=args.device or ADB.detect() or DEFAULT_DEVICE
if not ADB.connect(device):
L.err(f"Cannot connect: {device}"); sys.exit(1)
a=App(device)
if args.cast_restore: CastManager.restore()
elif args.cast_audit: CastManager.audit()
elif args.dns: NetworkOptimizer().set_dns(args.dns)
elif args.diag: a.diag.run_all()
elif args.repair: Repair.scan()
elif args.smarttube_ultra: a.smarttube_ultra()
elif args.full_ultra: a.full_ultra()
else: a._banner(); a._menu()
if __name__=="__main__":
try:
main()
except KeyboardInterrupt:
print(); L.warn("Ctrl+C"); L.save(); sys.exit(0)
except Exception as e:
L.err(f"Fatal: {e}")
import traceback; traceback.print_exc(); sys.exit(1)
🔬 Raport Analizy — Samsung Galaxy Watch 4 (SM-R870)
Data sesji: 23.02.2026, godz. 19:26–19:30
Build: BP2A.250325.020.R870XXU1JYL6 | One UI 8.0 / WearOS 6.0 / Android 16 (SDK 36)
Narzędzie: Watch4 Ultra Suite v3.0.0
🔴 KRYTYCZNE — Natychmiastowe działanie wymagane
1. Partycja /system wypełniona w 100%
/dev/block/dm-0 3.8 GB 3803384 2148 KB wolne 100% /system
To jest najpoważniejszy problem w całym systemie. Zaledwie 2 MB wolnego miejsca na partycji /system oznacza że:
System nie może zapisywać żadnych tymczasowych plików runtime
ART nie może zapisywać skompilowanych profili odex — kompilacja DEX jest blokowana
Aktualizacje OTA są niemożliwe do zastosowania
System może zachowywać się niestabilnie przy intensywnym I/O
Przyczyna: Aktualizacja do One UI 8.0 wypełniła partycję systemową bez odpowiedniego zarządzania miejscem.
Działanie: Uruchomić opcję [3] → [4] Czyść cache + pm trim-caches i sprawdzić po restarcie. Jeśli problem nie ustąpi — konieczny factory reset lub flashowanie stock ROM z odblokowaną partycją.
2. Katastrofalny jank — WorldClock / UI
Aplikacja: com.samsung.android.watch.worldclock
Klatki łącznie: 23
Jank: 10 klatek = 43.48% ← KATASTROFA (norma: <5%)
50. percentyl: 27ms ← powinno być <16ms (cel: 60fps)
90. percentyl: 89ms ← 5.5x powyżej normy
99. percentyl: 300ms ← spike widoczny gołym okiem
Number Slow UI thread: 9 ← wątek UI jest wąskim gardłem
Number High input latency: 10 ← każda janky klatka = opóźnienie dotyku
Diagnoza: Wątek UI jest zatrzymywany co kilka klatek na 27–300ms. Przyczyny (w kolejności prawdopodobieństwa):
/system pełny → ART nie kompiluje kodu → brak JIT optimization → interpretacja bajtkodu
AmbientDreamProxy wakelock budzący CPU co ~10s (patrz niżej)
Skia OpenGL zamiast Vulkan — brak hardware-acceleration na W920
window_animation_scale nadal = 1.0 (nie zmienione, tylko transition i animator = 0.5)
3. AmbientDreamProxy — ukryty sprawca lagów przy wybudzeniu
Z batterystats (obie sesje z AOD wyłączonym):
14:02:27 +wake_lock=u0a40:"AmbientDreamProxy" +screen ON reason=TILT
14:02:30 -screen OFF (3 sekundy po wybudzeniu!)
14:02:40 +wake_lock=u0a40:"AmbientDreamProxy" +screen ON reason=TILT
14:02:45 -screen OFF
14:03:23 +wake_lock=u0a40:"AmbientDreamProxy" wake_reason: contexthub + gnss_mailbox
Kluczowy wniosek: AmbientDreamProxy (Samsung AOD service, UID u0a40) nadal aktywnie przechwytuje zdarzenia TILT i uruchamia wakeable display cycle co ~10 sekund, mimo że doze_always_on=0. Komponent nie jest wyłączony — tylko flaga jest zresetowana. To powoduje:
Cykl CPU wake → AOD init → display power → display off → CPU sleep powtarzający się
Spike prądu przy każdym przebudzeniu = drenaż baterii
Opóźnienie wybudzenia właściwego (zegarek "waha się")
Powiązane: gnss_mailbox (GPS hardware) również budzi urządzenie niezależnie od AOD.
🟡 WAŻNE — Wysokie ryzyko wydajności
4. Massive Memory Overcommit
RAM fizyczny: 1.41 GB
Committed_AS: 23.4 GB ← 16.5x więcej niż fizyczny RAM!
SwapTotal (ZRAM): 963 MB (używane: 89 MB / 986 MB)
SUnreclaim: 173 MB ← kernel slab nie do odzyskania
CmaFree: 0 KB ← Contiguous Memory Allocator wyczerpany
System ma zarezerwowane 23x więcej wirtualnego RAM niż posiada fizycznie. Przy szczycie aktywności LMK (Low Memory Killer) agresywnie zabija procesy w tle.
5. Aktywne dwa procesy Google Play Services
4471 78.6 MB [gle.android.gms] ← gms unstable
1256 86.9 MB [.gms.persistent] ← gms persistent
Razem: ~165 MB samego GMS
GMS persistent + GMS unstable działają równolegle, zużywając ~165 MB z 1.4 GB RAM.
6. Samsung Health — podwójny proces
3195 60.5 MB [id.wear.shealth]
6650 56.2 MB [.shealthmonitor]
Razem: ~116 MB
Dwa procesy Samsung Health (aplikacja + monitor) = 116 MB RAM. Na zegarku z 1.4 GB jest to ~8% całkowitego RAM.
7. Zbędne procesy w tle
6784 50.3 MB [droid.easyMover] ← Samsung Easy Mover (transfer danych — po co na zegarku?)
6589 53.5 MB [.samsungaccount] ← Samsung Account service
6616 42.6 MB [id.app.reminder] ← Samsung Reminder
6525 41.5 MB [id.diagmonagent] ← Samsung Diagnostic Monitor Agent
Łącznie ~187 MB dla 4 procesów nie związanych z podstawową funkcją zegarka.
🟢 POZYTYWNE — Co działa poprawnie
Parametr
Wartość
Ocena
Temperatura CPU
37°C
✓ Normalna, brak throttlingu
Temperatura GPU
36°C
✓ Normalna
Temperatura baterii
31°C
✓ Dobra
Throttling termiczny
Status 0
✓ Brak
Kondycja baterii
health=2 (Good)
✓ Dobra
Poziom baterii
68%
✓ Wystarczający
Prąd rozładowania
-142 mA
✓ Niski pobór
ANR
Brak
Crash
Brak (ProcessCpuTracker = normalny błąd)
OOM
Brak
Partycja /data
14% zajęte
✓ Dużo miejsca
Partycja /cache
5% zajęte
⚙️ Znaleziony błąd w skrypcie v3.0.0
Lokalizacja: Linia 549 — diag_ui_performance()
Błąd:
# STARY KOD (błędny):
local jank_pct=$(( ${janky_frames:-0} * 100 / total_frames ))
# Bash $(( )) nie obsługuje liczb zmiennoprzecinkowych!
# Gdy jank_pct = "43.48%", całe wyrażenie psuje się
Błąd aktywuje się gdy gfxinfo zwraca procent z miejscem dziesiętnym (np. 43.48%).
Fix: Użyć awk zamiast bash arithmetic — patrz skrypt v3.1.
📋 Plan działania — kolejność według priorytetu
Priorytet
Akcja
Menu w skrypcie
🔴 1
Wyczyść cache + trim
[3] → [4]
🔴 2
Wyłącz komponenty AOD (AmbientDreamProxy)
[2] → [4]
🔴 3
Wyłącz GPS w tle
[2] → [6] (nowe w v3.1)
🟡 4
Uruchom Profil TURBO
[T]
🟡 5
Debloat: easyMover, diagmonagent, samsungaccount
[4] → [1]
🟡 6
Kompilacja ART (bg-dexopt-job)
[3] → [3]
🟢 7
Restart po wszystkich zmianach
[5] → [9]
🔧 Dodatkowe komendy do uruchomienia ręcznie
# Sprawdź czy system ma więcej miejsca po trim
`adb shell df /system`
# Wymuś kill AmbientDreamProxy (tymczasowe)
`adb shell am force-stop com.samsung.android.app.aodservice`
`adb shell am force-stop com.samsung.systemui.aod`
# Wyłącz GNSS wakeup
`adb shell settings put secure location_mode 0`
# Sprawdź BatteryDump — dekodowanie hex fields
# Format: voltage,current,temp_tenth,capacity,level,temp_C/10,...
# Wartość "12600" w polu 16 = full charge capacity (mAh) = 126.00... ?
# (Samsung używa własnego formatu)
# Sprawdź rozmiar /system po restarcie
`adb shell df -h /system`
༼//FERR༼ට༼/0 ͜༼×༼ Aꈤꪮꈤymousik
## ║ Samsung Galaxy Watch 4 — Ultra Optimizer & Repair Suite ║
## ║ One UI 8.0 / WearOS 6.0 / Android 16 · SM-R870 · Exynos W920 ║
## Anonymousik.is-a.dev production
#!/usr/bin/env bash
# ╔══════════════════════════════════════════════════════════════════╗
# ║ Samsung Galaxy Watch 4 — Ultra Optimizer & Repair Suite ║
# ║ One UI 8.0 / WearOS 6.0 / Android 16 · SM-R870 · Exynos W920 ║
# ║ Wersja: 3.1.0 | Patch: 2026-02-23 ║
# ║ Fixes: jank% float bug, /system alert, AmbientDreamProxy, ║
# ║ GPS/GNSS killer, window_animation_scale, +debloat ║
# ╚══════════════════════════════════════════════════════════════════╝
# Bezpieczne, odwracalne, kompleksowe narzędzie do optymalizacji,
# diagnostyki, debloatu i naprawy systemu bez ryzyka brick'a.
# Bash strict mode — wyłączamy set -e bo potrzebujemy obsługi błędów per-komenda
set -uo pipefail
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 0 — ZMIENNE GLOBALNE I STAŁE
# ═══════════════════════════════════════════════════════════════════
# Kolory terminala
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; WHITE='\033[0;37m'
BGREEN='\033[1;32m'; BRED='\033[1;31m'; BYELLOW='\033[1;33m'
BCYAN='\033[1;36m'; DIM='\033[2m'
# Metadane
readonly SCRIPT_NAME="Watch4 Ultra Suite"
readonly VERSION="3.1.0"
readonly SCRIPT_DATE="2026-02-23"
readonly LOG_DIR="/tmp/watch4_suite_logs"
readonly BACKUP_DIR="${LOG_DIR}/backup_$(date +%Y%m%d_%H%M%S)"
readonly LOG_FILE="${LOG_DIR}/session_$(date +%Y%m%d_%H%M%S).log"
readonly ADB_TIMEOUT=15
readonly ADB_LONG_TIMEOUT=120
# Stan połączenia
DEVICE_SERIAL=""
DEVICE_MODEL=""
DEVICE_ANDROID=""
DEVICE_BUILD=""
DEVICE_SDK=""
# Flaga — czy backup ustawień wykonany w tej sesji
BACKUP_DONE=false
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 1 — INFRASTRUKTURA: LOGGING, UI, BŁĘDY
# ═══════════════════════════════════════════════════════════════════
mkdir -p "$LOG_DIR" "$BACKUP_DIR"
ts() { date '+%H:%M:%S'; }
log() { printf "[%s] %s\n" "$(ts)" "$*" >> "$LOG_FILE"; }
ok() { printf "${GREEN} ✓ %s${RESET}\n" "$*"; log "OK: $*"; }
err() { printf "${BRED} ✗ %s${RESET}\n" "$*" >&2; log "ERROR: $*"; }
warn() { printf "${BYELLOW} ⚠ %s${RESET}\n" "$*"; log "WARN: $*"; }
info() { printf "${CYAN} ℹ %s${RESET}\n" "$*"; log "INFO: $*"; }
step() { printf "${BOLD}${WHITE} ▶ %s${RESET}\n" "$*"; log "STEP: $*"; }
detail() { printf "${DIM} %s${RESET}\n" "$*"; log "DETAIL: $*"; }
header() {
local txt="$1"
local width=60
local pad=$(( (width - ${#txt} - 2) / 2 ))
echo
printf "${BOLD}${BLUE}"
printf '╔'; printf '═%.0s' $(seq 1 $((width-2))); printf '╗\n'
printf '║%*s%s%*s║\n' $pad "" "$txt" $((width - pad - ${#txt} - 2)) ""
printf '╚'; printf '═%.0s' $(seq 1 $((width-2))); printf '╝\n'
printf "${RESET}"
}
sep() { printf "${BLUE}%s${RESET}\n" "$(printf '─%.0s' {1..60})"; }
sep_thin() { printf "${DIM}%s${RESET}\n" "$(printf '·%.0s' {1..60})"; }
status_row() {
# status_row "Klucz" "Wartość" [kolor_wartości]
local key="$1" val="$2" color="${3:-$CYAN}"
printf " ${DIM}%-32s${RESET} ${color}%s${RESET}\n" "${key}:" "$val"
}
pause() {
echo
read -rp "$(printf " ${YELLOW}Naciśnij [Enter] aby kontynuować...${RESET}")" _
}
confirm() {
# confirm "Treść pytania" → 0 jeśli tak, 1 jeśli nie
local msg="$1"
local ans
read -rp "$(printf " ${BYELLOW}%s [t/N]: ${RESET}" "$msg")" ans
[[ "${ans,,}" == "t" || "${ans,,}" == "tak" ]]
}
spinner() {
# spinner <pid> <wiadomość>
local pid=$1 msg="$2"
local spin=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local i=0
while kill -0 "$pid" 2>/dev/null; do
printf "\r ${CYAN}%s${RESET} %s " "${spin[$i]}" "$msg"
i=$(( (i+1) % ${#spin[@]} ))
sleep 0.1
done
printf "\r%60s\r" " "
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 2 — WRAPPER ADB (bezpieczny, logujący)
# ═══════════════════════════════════════════════════════════════════
# Wykonaj komendę adb shell — zwraca kod wyjścia
adb_cmd() {
local cmd="$*"
log "ADB_CMD: $cmd"
local output exit_code=0
output=$(timeout "$ADB_TIMEOUT" adb -s "$DEVICE_SERIAL" shell "$cmd" 2>&1) || exit_code=$?
log "ADB_OUT[$exit_code]: $output"
echo "$output"
return $exit_code
}
# Wykonaj długą komendę adb shell (dexopt, compile, itp.)
adb_long() {
local cmd="$*"
log "ADB_LONG: $cmd"
timeout "$ADB_LONG_TIMEOUT" adb -s "$DEVICE_SERIAL" shell "$cmd" 2>&1 | tee -a "$LOG_FILE"
return "${PIPESTATUS[0]}"
}
# Pobierz wartość bez stderr
adb_get() {
timeout "$ADB_TIMEOUT" adb -s "$DEVICE_SERIAL" shell "$@" 2>/dev/null | tr -d '\r'
}
# Pobierz prop systemowy
get_prop() {
adb_get getprop "$1" 2>/dev/null || echo ""
}
# Ustawianie settings z walidacją i informowaniem
safe_setting() {
local namespace="$1" key="$2" value="$3" desc="${4:-}"
local old_val
old_val=$(adb_get "settings get ${namespace} ${key}" 2>/dev/null || echo "null")
# Zapisz do backupu
echo "settings put ${namespace} ${key} ${old_val}" >> "${BACKUP_DIR}/settings_restore.sh"
if adb_cmd "settings put ${namespace} ${key} ${value}" >/dev/null 2>&1; then
local label="${desc:-${namespace}/${key}}"
ok "${label}: ${DIM}${old_val}${RESET} → ${GREEN}${value}${RESET}"
return 0
else
err "Nie udało się ustawić ${namespace}/${key}=${value}"
return 1
fi
}
# Sprawdź czy urządzenie odpowiada
ping_device() {
timeout 5 adb -s "$DEVICE_SERIAL" shell "echo ok" 2>/dev/null | grep -q "ok"
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 3 — BANER I POŁĄCZENIE
# ═══════════════════════════════════════════════════════════════════
print_banner() {
clear
printf "${BOLD}${MAGENTA}"
cat << 'BANNER'
╔══════════════════════════════════════════════════════════════╗
║ ║
║ ██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗ ██╗ ██╗ ║
║ ██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║ ██║ ██║ ║
║ ██║ █╗ ██║███████║ ██║ ██║ ███████║ ███████║ ║
║ ██║███╗██║██╔══██║ ██║ ██║ ██╔══██║ ╚════██║ ║
║ ╚███╔███╔╝██║ ██║ ██║ ╚██████╗██║ ██║ ██║ ║
║ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ║
║ ║
║ Samsung Galaxy Watch 4 — Ultra Optimizer Suite ║
║ One UI 8.0 / WearOS 6.0 / Android 16 / SM-R870 ║
╚══════════════════════════════════════════════════════════════╝
BANNER
printf "${RESET}"
printf " ${DIM}Wersja: ${VERSION} · ${SCRIPT_DATE} · Log: ${LOG_FILE}${RESET}\n"
sep
}
check_adb_installed() {
if ! command -v adb &>/dev/null; then
err "ADB nie znalezione w PATH!"
err "Zainstaluj: https://developer.android.com/tools/releases/platform-tools"
exit 1
fi
local adb_ver
adb_ver=$(adb version 2>/dev/null | head -1)
ok "$adb_ver"
}
connect_device() {
header "POŁĄCZENIE Z ZEGARKIEM"
# Sprawdź istniejące połączenia
local existing
existing=$(adb devices 2>/dev/null | grep -E "^[^\s]+\s+device$" | head -1 || true)
if [[ -n "$existing" ]]; then
DEVICE_SERIAL=$(echo "$existing" | awk '{print $1}')
ok "Znaleziono aktywne połączenie: ${CYAN}${DEVICE_SERIAL}${RESET}"
else
echo
info "Brak aktywnych połączeń. Podaj dane zegarka:"
echo
read -rp "$(printf " ${CYAN}Adres IP zegarka: ${RESET}")" WATCH_IP
if ! [[ "$WATCH_IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
err "Nieprawidłowy format IP."; exit 1
fi
read -rp "$(printf " ${CYAN}Port [domyślnie 5555]: ${RESET}")" WATCH_PORT
WATCH_PORT="${WATCH_PORT:-5555}"
DEVICE_SERIAL="${WATCH_IP}:${WATCH_PORT}"
info "Łączę z ${DEVICE_SERIAL}..."
# Wymuś restart serwera ADB na wypadek zawieszenia
adb kill-server &>/dev/null; sleep 1; adb start-server &>/dev/null
local conn_out
conn_out=$(adb connect "$DEVICE_SERIAL" 2>&1)
log "ADB connect: $conn_out"
if echo "$conn_out" | grep -qiE "connected to|already connected"; then
ok "Połączono z ${DEVICE_SERIAL}"
elif echo "$conn_out" | grep -qi "refused"; then
err "Połączenie odrzucone — sprawdź:"
err " 1. Zegarek i komputer w tej samej sieci Wi-Fi"
err " 2. Ustawienia → Opcje programistyczne → Debugowanie ADB → WŁ"
err " 3. Port ADB: Ustawienia → Opcje programistyczne → Debugowanie ADB po sieci"
exit 1
else
err "Nieznany błąd połączenia: $conn_out"; exit 1
fi
fi
# Weryfikacja stanu urządzenia
local state
state=$(timeout 5 adb -s "$DEVICE_SERIAL" get-state 2>&1 || echo "error")
case "$state" in
device) ok "Urządzenie gotowe (device)" ;;
unauthorized)
err "Nieautoryzowane! Zaakceptuj dialog na zegarku → uruchom skrypt ponownie."
exit 1 ;;
offline)
err "Urządzenie offline. Sprawdź sieć lub uruchom: adb kill-server && adb start-server"
exit 1 ;;
*)
err "Nieznany stan: $state"; exit 1 ;;
esac
# Pobierz informacje o urządzeniu
DEVICE_MODEL=$(get_prop ro.product.model)
DEVICE_ANDROID=$(get_prop ro.build.version.release)
DEVICE_BUILD=$(get_prop ro.build.display.id)
DEVICE_SDK=$(get_prop ro.build.version.sdk)
local device_arch
device_arch=$(get_prop ro.product.cpu.abi)
sep
status_row "Model" "$DEVICE_MODEL"
status_row "Android" "$DEVICE_ANDROID (SDK $DEVICE_SDK)"
status_row "Build ID" "$DEVICE_BUILD"
status_row "Architektura" "$device_arch"
status_row "Połączony przez" "$DEVICE_SERIAL"
sep
if ! echo "$DEVICE_MODEL" | grep -qi "R870\|Watch 4"; then
warn "Model ($DEVICE_MODEL) różni się od docelowego SM-R870."
warn "Skrypt może wymagać dostosowania dla tego urządzenia."
fi
if (( DEVICE_SDK < 35 )); then
warn "SDK ${DEVICE_SDK} — niektóre komendy ART/Android 16 mogą nie działać."
fi
# Utwórz skrypt przywracania backupu
cat > "${BACKUP_DIR}/settings_restore.sh" << 'RESTORE_HEADER'
#!/usr/bin/env bash
# AUTO-WYGENEROWANY skrypt przywracania ustawień
# Uruchom: adb -s DEVICE shell "sh /sdcard/watch4_restore.sh"
echo "Przywracanie ustawień Watch4 Suite..."
RESTORE_HEADER
log "Sesja połączona: $DEVICE_SERIAL | Model: $DEVICE_MODEL | Android: $DEVICE_ANDROID"
# ── KRYTYCZNA KONTROLA: /system pełny (wykryto na SM-R870 + One UI 8.0) ──
local sys_avail
sys_avail=$(adb_get "df /system 2>/dev/null | tail -1 | awk '{print \$4}'" | tr -d ' \r' || echo "")
if [[ "$sys_avail" =~ ^[0-9]+$ ]]; then
if (( sys_avail < 51200 )); then
echo
printf "${BRED}╔══════════════════════════════════════════════════════════╗\n"
printf "║ ⚠ KRYTYCZNE: PARTYCJA /system PRAWIE PEŁNA! ║\n"
printf "║ Wolne: %-8s KB — ART nie może kompilować DEX! ║\n" "$sys_avail"
printf "║ Zalecane: [3] Wydajność → [4] Czyść cache, potem restart ║\n"
printf "╚══════════════════════════════════════════════════════════╝${RESET}\n"
log "CRITICAL: /system available=${sys_avail} KB"
fi
fi
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 4 — DIAGNOSTYKA PROAKTYWNA
# ═══════════════════════════════════════════════════════════════════
diagnostics_menu() {
while true; do
header "DIAGNOSTYKA PROAKTYWNA"
echo " [1] Pełny raport systemu (snapshot)"
echo " [2] Monitor temperatury w czasie rzeczywistym"
echo " [3] Analiza zużycia RAM i procesów"
echo " [4] Inspekcja baterii (health, wear, temperatury)"
echo " [5] Analiza wydajności UI (jank, frame drops)"
echo " [6] Sprawdzenie usług systemowych (status krytycznych)"
echo " [7] Analiza logów systemowych (ANR, crash, OOM)"
echo " [8] Inspekcja stanu sieci i Bluetooth"
echo " [9] Eksportuj pełny raport diagnostyczny do pliku"
echo " [0] Powrót"
sep
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1) diag_full_snapshot ;;
2) diag_thermal_monitor ;;
3) diag_ram_analysis ;;
4) diag_battery_health ;;
5) diag_ui_performance ;;
6) diag_system_services ;;
7) diag_log_analysis ;;
8) diag_network_bt ;;
9) diag_export_report ;;
0) return ;;
*) warn "Nieprawidłowy wybór." ;;
esac
done
}
diag_full_snapshot() {
header "PEŁNY RAPORT SYSTEMU"
sep_thin
step "Informacje systemowe"
status_row "Model" "$(get_prop ro.product.model)"
status_row "Android" "$(get_prop ro.build.version.release)"
status_row "SDK" "$(get_prop ro.build.version.sdk)"
status_row "Build" "$(get_prop ro.build.display.id)"
status_row "CPU ABI" "$(get_prop ro.product.cpu.abi)"
status_row "Chipset" "$(get_prop ro.hardware)"
status_row "Uptime" "$(adb_get cat /proc/uptime | awk '{printf "%d min %d sek", $1/60, $1%60}')"
sep_thin
step "Pamięć RAM"
local mem_total mem_avail mem_free mem_commit swap_total swap_free slab_unreclaim
mem_total=$(adb_get "grep MemTotal /proc/meminfo | awk '{print \$2}'")
mem_avail=$(adb_get "grep MemAvailable /proc/meminfo | awk '{print \$2}'")
mem_commit=$(adb_get "grep Committed_AS /proc/meminfo | awk '{print \$2}'" || echo "0")
swap_total=$(adb_get "grep SwapTotal /proc/meminfo | awk '{print \$2}'" || echo "0")
swap_free=$(adb_get "grep SwapFree /proc/meminfo | awk '{print \$2}'" || echo "0")
slab_unreclaim=$(adb_get "grep SUnreclaim /proc/meminfo | awk '{print \$2}'" || echo "0")
local mem_used=$(( (mem_total - mem_avail) / 1024 ))
local mem_total_mb=$(( mem_total / 1024 ))
local mem_avail_mb=$(( mem_avail / 1024 ))
local commit_mb=$(( ${mem_commit:-0} / 1024 ))
local swap_used_mb=$(( (${swap_total:-0} - ${swap_free:-0}) / 1024 ))
local slab_mb=$(( ${slab_unreclaim:-0} / 1024 ))
local ram_color="$GREEN"
(( mem_avail_mb < 250 )) && ram_color="$YELLOW"
(( mem_avail_mb < 100 )) && ram_color="$RED"
status_row "RAM łącznie" "${mem_total_mb} MB"
status_row "RAM dostępna" "${mem_avail_mb} MB" "$ram_color"
status_row "RAM użyta (est.)" "${mem_used} MB"
status_row "SWAP/ZRAM użyty" "${swap_used_mb} MB / $(( ${swap_total:-0} / 1024 )) MB"
status_row "Kernel SUnreclaim" "${slab_mb} MB"
if [[ "$commit_mb" -gt 0 && "$mem_total_mb" -gt 0 ]] 2>/dev/null; then
local overcommit_ratio
overcommit_ratio=$(awk "BEGIN {printf \"%.1f\", ${commit_mb} / ${mem_total_mb}}")
status_row "Committed_AS" "${commit_mb} MB (${overcommit_ratio}x fizycznego RAM)"
local oc_int
oc_int=$(awk "BEGIN {printf \"%d\", ${commit_mb} / ${mem_total_mb}}")
(( oc_int > 10 )) && warn "Overcommit >${oc_int}x — LMK agresywnie zabija procesy tła!"
fi
sep_thin
step "Miejsce na dysku"
adb_get "df /data /cache /system 2>/dev/null" | while IFS= read -r line; do
printf " ${DIM}%s${RESET}\n" "$line"
done
sep_thin
step "Temperatura CPU (przybliżona)"
local temps
temps=$(adb_get "cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null | head -5" || echo "niedostępne")
echo "$temps" | head -5 | while IFS= read -r t; do
if [[ "$t" =~ ^[0-9]+$ ]]; then
local deg=$(( t / 1000 ))
local color="$GREEN"
(( deg > 45 )) && color="$YELLOW"
(( deg > 55 )) && color="$RED"
printf " ${color}%d°C${RESET}\n" "$deg"
fi
done
sep_thin
step "Akumulator"
adb_get "dumpsys battery 2>/dev/null" | grep -E "level|status|health|temperature|voltage|plugged" | while IFS= read -r line; do
printf " ${CYAN}%s${RESET}\n" "$line"
done
sep_thin
step "Animacje systemowe"
for key in window_animation_scale transition_animation_scale animator_duration_scale; do
local val
val=$(adb_get "settings get global $key")
status_row "$key" "$val"
done
step "AOD Status"
local aod_val
aod_val=$(adb_get "settings get secure doze_always_on")
local aod_label="Wyłączone"
[[ "$aod_val" == "1" ]] && aod_label="Włączone"
status_row "doze_always_on" "$aod_val ($aod_label)"
pause
}
diag_thermal_monitor() {
header "MONITOR TEMPERATURY CZASU RZECZYWISTEGO"
echo -e " ${YELLOW}Monitorowanie przez 30 sekund. Ctrl+C aby przerwać wcześniej.${RESET}"
echo
local zones
zones=$(adb_get "ls /sys/class/thermal/ 2>/dev/null" | grep thermal_zone | head -8)
for i in $(seq 1 30); do
printf "\r ${BOLD}[%2d/30s]${RESET} " "$i"
while IFS= read -r zone; do
local temp
temp=$(adb_get "cat /sys/class/thermal/${zone}/temp 2>/dev/null" || echo "0")
if [[ "$temp" =~ ^[0-9]+$ ]]; then
local deg=$(( temp / 1000 ))
local color="$GREEN"
(( deg > 40 )) && color="$YELLOW"
(( deg > 50 )) && color="$RED"
printf "${color}%d°C${RESET} " "$deg"
fi
done <<< "$zones"
sleep 1
done
echo
ok "Monitorowanie zakończone."
pause
}
diag_ram_analysis() {
header "ANALIZA RAM I PROCESÓW"
sep_thin
step "Top 10 procesów według RAM"
echo
printf " ${BOLD}%-8s %-12s %-8s %s${RESET}\n" "PID" "RSS(MB)" "USER" "NAZWA"
sep_thin
adb_get "ps -eo pid,rss,user,comm 2>/dev/null | sort -k2 -rn | head -10" | while IFS= read -r line; do
local pid rss user comm
read -r pid rss user comm <<< "$line"
if [[ "$rss" =~ ^[0-9]+$ ]]; then
local rss_mb=$(( rss / 1024 ))
local color="$WHITE"
(( rss_mb > 100 )) && color="$YELLOW"
(( rss_mb > 200 )) && color="$RED"
printf " ${DIM}%-8s${RESET} ${color}%-12s${RESET} %-8s %s\n" "$pid" "${rss_mb} MB" "$user" "$comm"
fi
done
sep_thin
step "Statystyki LMK (Low Memory Killer)"
adb_get "cat /sys/module/lowmemorykiller/parameters/minfree 2>/dev/null" | while IFS= read -r line; do
detail "LMK minfree: $line"
done
sep_thin
step "Ostatnie zabite procesy (OOM)"
adb_get "logcat -d -t 50 --pid 1 2>/dev/null" | grep -i "lowmem\|oom_kill\|killing\|killed" | tail -5 | while IFS= read -r line; do
printf " ${RED}%s${RESET}\n" "$line"
done || detail "Brak wpisów OOM w ostatnich logach."
pause
}
diag_battery_health() {
header "INSPEKCJA BATERII"
sep_thin
step "Podstawowe dane"
adb_get "dumpsys battery 2>/dev/null" | while IFS= read -r line; do
local key val
IFS=':' read -r key val <<< "$line"
key=$(echo "$key" | xargs)
val=$(echo "$val" | xargs)
[[ -z "$key" || -z "$val" ]] && continue
case "$key" in
level)
local color="$GREEN"
(( val < 30 )) && color="$YELLOW"
(( val < 15 )) && color="$RED"
status_row "Poziom" "${val}%" "$color"
;;
health)
local h_label
case "$val" in
2) h_label="Dobry ✓" ;;
3) h_label="Przegrzanie !" ;;
4) h_label="Martwy ✗" ;;
*) h_label="Status: $val" ;;
esac
status_row "Kondycja" "$h_label"
;;
temperature)
local temp_c
temp_c=$(echo "scale=1; $val / 10" | bc 2>/dev/null || echo "${val}/10")
status_row "Temperatura" "${temp_c}°C"
;;
voltage) status_row "Napięcie" "${val} mV" ;;
status)
local s_label
case "$val" in
1) s_label="Nieznany" ;; 2) s_label="Ładowanie" ;;
3) s_label="Rozładowywanie" ;; 5) s_label="Pełny" ;;
*) s_label="$val" ;;
esac
status_row "Status" "$s_label"
;;
*) status_row "$key" "$val" ;;
esac
done
sep_thin
step "Historia zużycia baterii (ostatnie 24h)"
adb_get "dumpsys batterystats 2>/dev/null" | grep -E "Discharge|charge|plugged|screen" | head -10 | while IFS= read -r line; do
detail "$line"
done
sep_thin
step "Rekomendacje"
local level
level=$(adb_get "dumpsys battery 2>/dev/null | grep level | awk -F: '{print \$2}' | tr -d ' \r'")
if [[ "$level" =~ ^[0-9]+$ ]]; then
(( level < 20 )) && warn "Niski poziom baterii — podłącz ładowarkę przed dalszą optymalizacją."
(( level >= 20 )) && ok "Poziom baterii wystarczający do optymalizacji."
fi
pause
}
diag_ui_performance() {
header "ANALIZA WYDAJNOŚCI UI (JANK / FRAME DROPS)"
echo -e " ${YELLOW}Mierzę wydajność renderowania — dotknij ekranu zegarka podczas testu.${RESET}"
step "Reset statystyk Gfxinfo"
adb_cmd "dumpsys gfxinfo --reset" >/dev/null 2>&1
sleep 2
step "Czekam 5 sekund na zbieranie danych..."
sleep 5
step "Odczyt statystyk klatek (SurfaceFlinger)"
local gfx_out
gfx_out=$(adb_get "dumpsys gfxinfo 2>/dev/null" | head -60)
local total_frames janky_frames slow_frames
total_frames=$(echo "$gfx_out" | grep -i "total frames" | awk '{print $NF}' | head -1)
janky_frames=$(echo "$gfx_out" | grep -i "janky frames" | awk '{print $NF}' | head -1)
slow_frames=$(echo "$gfx_out" | grep -i ">16ms" | awk '{print $NF}' | head -1)
if [[ -n "$total_frames" && "$total_frames" -gt 0 ]] 2>/dev/null; then
status_row "Całkowita liczba klatek" "$total_frames"
# BUGFIX v3.1: gfxinfo zwraca float (np. "43.48%") — użyj awk zamiast $(( ))
local janky_clean
janky_clean=$(echo "${janky_frames:-0}" | grep -oE '[0-9]+' | head -1)
local jank_pct_raw
jank_pct_raw=$(awk "BEGIN {printf \"%.1f\", ${janky_clean:-0} * 100 / ${total_frames}}")
local jank_pct_int
jank_pct_int=$(awk "BEGIN {printf \"%d\", ${janky_clean:-0} * 100 / ${total_frames}}")
status_row "Klatki z jankiem (>16ms)" "${janky_clean:-?} (${jank_pct_raw}%)"
local color="$GREEN"
(( jank_pct_int > 5 )) && color="$YELLOW"
(( jank_pct_int > 15 )) && color="$RED"
status_row "Procent janku" "${jank_pct_raw}%" "$color"
(( jank_pct_int > 10 )) && warn "Wykryto znaczny jank (${jank_pct_raw}%) — zalecana optymalizacja animacji i ART."
(( jank_pct_int <= 5 )) && ok "Wydajność UI dobra (jank ${jank_pct_raw}%)."
else
info "Niewystarczające dane z gfxinfo. Sprawdź SurfaceFlinger:"
adb_get "dumpsys SurfaceFlinger --latency 2>/dev/null" | head -15 | while IFS= read -r line; do
detail "$line"
done
fi
sep_thin
step "Dispatching latency (Input)"
adb_get "dumpsys input 2>/dev/null" | grep -E "latency|delay|drop" | head -5 | while IFS= read -r line; do
detail "$line"
done
pause
}
diag_system_services() {
header "STATUS USŁUG SYSTEMOWYCH"
local critical_services=(
"SurfaceFlinger:Rendering/UI"
"WindowManagerService:Zarządzanie oknami"
"ActivityManagerService:Zarządzanie aplikacjami"
"PackageManagerService:Zarządzanie pakietami"
"PowerManagerService:Zarządzanie energią"
"ThermalManagerService:Zarządzanie cieplne"
"WifiService:Wi-Fi"
"BluetoothManagerService:Bluetooth"
)
sep_thin
printf " ${BOLD}%-28s %-20s %s${RESET}\n" "USŁUGA" "OPIS" "STATUS"
sep_thin
for entry in "${critical_services[@]}"; do
local svc="${entry%%:*}"
local desc="${entry##*:}"
local found
found=$(adb_get "service check ${svc} 2>/dev/null" | grep -ic "found" || echo "0")
if [[ "$found" -gt 0 ]] 2>/dev/null; then
printf " ${BOLD}%-28s${RESET} %-20s ${GREEN}● Aktywna${RESET}\n" "$svc" "$desc"
else
printf " ${BOLD}%-28s${RESET} %-20s ${RED}✗ Nieaktywna${RESET}\n" "$svc" "$desc"
fi
done
sep_thin
step "Procesy w stanie ZOMBIE lub DEAD"
adb_get "ps -A 2>/dev/null | grep -E 'Z|D' | grep -v grep | head -10" | while IFS= read -r line; do
warn "$line"
done || detail "Brak procesów zombie."
pause
}
diag_log_analysis() {
header "ANALIZA LOGÓW SYSTEMOWYCH"
step "ANR (Application Not Responding) — ostatnie zdarzenia"
adb_get "logcat -d -t 200 2>/dev/null" | grep -i "ANR\|anr" | tail -5 | while IFS= read -r line; do
printf " ${RED}%s${RESET}\n" "$line"
done || detail "Brak ANR w buforze logów."
sep_thin
step "Crash / Wyjątki (ostatnie 5)"
adb_get "logcat -d -t 200 2>/dev/null" | grep -iE "FATAL|crash|exception|NullPointer" | tail -5 | while IFS= read -r line; do
printf " ${BRED}%s${RESET}\n" "$line"
done || detail "Brak crashy w buforze."
sep_thin
step "OOM / Duszenie pamięci"
adb_get "logcat -d -t 200 2>/dev/null" | grep -iE "lowmem|oom|kill" | tail -5 | while IFS= read -r line; do
printf " ${YELLOW}%s${RESET}\n" "$line"
done || detail "Brak wpisów OOM."
sep_thin
step "Throttling termiczny"
adb_get "logcat -d -t 200 2>/dev/null" | grep -iE "thermal|throttl|overheat" | tail -5 | while IFS= read -r line; do
printf " ${YELLOW}%s${RESET}\n" "$line"
done || detail "Brak wpisów throttlingu."
sep_thin
step "Błędy SurfaceFlinger / HWUI"
adb_get "logcat -d -t 200 -s SurfaceFlinger:W HWUI:W 2>/dev/null" | tail -10 | while IFS= read -r line; do
printf " ${YELLOW}%s${RESET}\n" "$line"
done || detail "Brak błędów renderowania."
pause
}
diag_network_bt() {
header "SIEĆ I BLUETOOTH"
step "Status Wi-Fi"
adb_get "dumpsys wifi 2>/dev/null" | grep -E "SSID|BSSID|signal|state|freq|speed|IP" | head -10 | while IFS= read -r line; do
detail "$line"
done
sep_thin
step "Status Bluetooth"
adb_get "dumpsys bluetooth_manager 2>/dev/null" | grep -E "state|enabled|profile|address" | head -8 | while IFS= read -r line; do
detail "$line"
done
sep_thin
step "Połączone urządzenia BT"
adb_get "dumpsys bluetooth_manager 2>/dev/null" | grep -E "name|class|connected" | head -6 | while IFS= read -r line; do
detail "$line"
done
pause
}
diag_export_report() {
local report_file="${LOG_DIR}/diagnostic_report_$(date +%Y%m%d_%H%M%S).txt"
step "Generuję pełny raport diagnostyczny..."
{
echo "=== Watch4 Ultra Suite — Raport Diagnostyczny ==="
echo "Data: $(date)"
echo "Urządzenie: ${DEVICE_SERIAL}"
echo
echo "--- SYSTEM INFO ---"
adb_get "getprop" 2>/dev/null | grep -E "ro\.(product|build|hardware|system)" | head -30
echo
echo "--- MEMINFO ---"
adb_get "cat /proc/meminfo"
echo
echo "--- BATTERY ---"
adb_get "dumpsys battery"
echo
echo "--- GFXINFO ---"
adb_get "dumpsys gfxinfo" | head -60
echo
echo "--- TOP PROCESSES ---"
adb_get "ps -eo pid,rss,comm | sort -k2 -rn | head -20"
echo
echo "--- THERMAL ---"
adb_get "dumpsys thermalservice" 2>/dev/null | head -30 || echo "niedostępne"
echo
echo "--- LOGCAT ERRORS ---"
adb_get "logcat -d -t 100 *:E" 2>/dev/null | head -50
} > "$report_file" &
spinner $! "Zbieranie danych..."
ok "Raport zapisany: ${report_file}"
# Prześlij na zegarek (opcjonalnie)
if confirm "Skopiować raport na zegarek (/sdcard/watch4_report.txt)?"; then
adb push "$report_file" "/sdcard/watch4_report.txt" >/dev/null 2>&1 && ok "Raport na zegarku: /sdcard/watch4_report.txt"
fi
pause
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 5 — ZARZĄDZANIE AOD
# ═══════════════════════════════════════════════════════════════════
aod_menu() {
while true; do
header "ZARZĄDZANIE AOD (Always-On Display)"
# Status
local aod_val doze_wakeup ambient_peekoff
aod_val=$(adb_get "settings get secure doze_always_on")
doze_wakeup=$(adb_get "settings get secure doze_wake_display_on_gesture")
ambient_peekoff=$(adb_get "settings get secure doze_pick_up_gesture")
status_row "AOD aktywne (doze_always_on)" "${aod_val:-null}"
status_row "Wybudzenie gestem" "${doze_wakeup:-null}"
status_row "Podniesienie nadgarstka" "${ambient_peekoff:-null}"
sep_thin
echo " [1] Wyłącz AOD (zalecane — eliminuje CPU spike przy wybudzeniu)"
echo " [2] Włącz AOD"
echo " [3] Tryb SMART — AOD tylko przy podniesieniu nadgarstka"
echo " [4] Dezaktywuj komponenty Samsung AOD (agresywnie)"
echo " [5] Przywróć komponenty AOD (cofnij opcję 4)"
echo " [6] Zabij AmbientDreamProxy wakelock (NOWE — fix lagów wybudzenia)"
echo " [7] Zarządzanie GPS/GNSS (wakeup killer)"
echo " [8] Optymalizacja timeoutów ekranu"
echo " [0] Powrót"
sep
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1)
safe_setting "secure" "doze_always_on" "0" "AOD"
safe_setting "secure" "doze_wake_display_on_gesture" "0" "Wybudzenie gestem"
ok "AOD wyłączone. Eliminuje ~150-300ms opóźnienie wybudzenia Exynos W920."
;;
2)
safe_setting "secure" "doze_always_on" "1" "AOD"
ok "AOD włączone."
;;
3)
safe_setting "secure" "doze_always_on" "0" "AOD"
safe_setting "secure" "doze_wake_display_on_gesture" "1" "Wybudzenie gestem"
safe_setting "secure" "doze_pick_up_gesture" "1" "Podniesienie nadgarstka"
ok "Tryb SMART: AOD nieaktywne, ekran budzi się na gest/podniesienie."
;;
4) aod_disable_components ;;
5) aod_restore_components ;;
6) aod_kill_ambient_proxy ;;
7) aod_gps_control ;;
8) aod_screen_timeouts ;;
0) return ;;
*) warn "Nieprawidłowy wybór." ;;
esac
pause
done
}
# Pakiety Samsung AOD — bezpieczne do dezaktywacji (nie odinstalowania)
declare -a SAMSUNG_AOD_COMPONENTS=(
"com.samsung.android.app.aodservice"
"com.samsung.systemui.aod"
"com.samsung.android.app.watchface.aod"
)
aod_disable_components() {
header "DEZAKTYWACJA KOMPONENTÓW AOD"
warn "Ta opcja dezaktywuje systemowe serwisy AOD Samsung."
warn "System przełączy się na standardowy tryb doze WearOS."
echo
if ! confirm "Kontynuować?"; then
info "Anulowano."; return
fi
for pkg in "${SAMSUNG_AOD_COMPONENTS[@]}"; do
local pm_state
pm_state=$(adb_get "pm list packages -d 2>/dev/null | grep ${pkg}" || echo "")
if adb_cmd "pm disable-user --user 0 ${pkg}" >/dev/null 2>&1; then
ok "Dezaktywowano: ${pkg}"
else
# Może już wyłączony lub nieistnieje
warn "Pominięto (może nie istnieć): ${pkg}"
fi
done
# Wymuś AOD standard WearOS
safe_setting "secure" "doze_always_on" "0" "AOD (standard WearOS doze)"
safe_setting "global" "always_finish_activities" "0" "Finalizacja aktywności"
ok "Komponenty AOD Samsung dezaktywowane. Standardowy doze WearOS aktywny."
info "Przywróć opcją [5] jeśli pojawią się problemy."
}
aod_restore_components() {
header "PRZYWRACANIE KOMPONENTÓW AOD"
for pkg in "${SAMSUNG_AOD_COMPONENTS[@]}"; do
if adb_cmd "pm enable ${pkg}" >/dev/null 2>&1; then
ok "Przywrócono: ${pkg}"
else
warn "Nie można przywrócić (lub nie istnieje): ${pkg}"
fi
done
safe_setting "secure" "doze_always_on" "1" "AOD"
ok "Komponenty AOD przywrócone."
}
aod_kill_ambient_proxy() {
header "KILL AmbientDreamProxy WAKELOCK"
echo -e " ${BYELLOW}Diagnoza z Twoich logów (14:02–14:03):${RESET}"
echo -e " ${DIM}+wake_lock=u0a40:\"AmbientDreamProxy\" budzący urządzenie co ~10s${RESET}"
echo -e " ${DIM}mimo doze_always_on=0. Powoduje lagi przy wybudzeniu + drenaż baterii.${RESET}"
echo
step "Zatrzymuję serwisy AmbientDreamProxy..."
local proxy_pkgs=(
"com.samsung.android.app.aodservice"
"com.samsung.systemui.aod"
"com.samsung.android.app.watchface.aod"
)
for pkg in "${proxy_pkgs[@]}"; do
if adb_cmd "am force-stop ${pkg}" >/dev/null 2>&1; then
ok "force-stop: ${pkg}"
else
warn "Pominięto (może nie istnieć): ${pkg}"
fi
done
step "Dezaktywuję wakelock trigger dla TILT gesture..."
safe_setting "secure" "doze_wake_display_on_gesture" "0" "Wybudzenie gestem TILT"
safe_setting "secure" "doze_pick_up_gesture" "0" "Podniesienie nadgarstka (doze)"
safe_setting "secure" "doze_pulse_on_pick_up" "0" "Pulse on pick-up"
safe_setting "secure" "doze_pulse_on_double_tap" "0" "Pulse on double-tap"
step "Blokuję AmbientDreamProxy przez AppOps..."
adb_cmd "appops set com.samsung.android.app.aodservice WAKE_LOCK deny" >/dev/null 2>&1 && \
ok "AppOps WAKE_LOCK: denied dla aodservice" || \
warn "AppOps — pominięto (może wymagać uprawnień)."
step "Sprawdzam aktywne wakelocki po operacji..."
local remaining
remaining=$(adb_get "dumpsys power 2>/dev/null | grep -i 'AmbientDream'" || echo "")
if [[ -z "$remaining" ]]; then
ok "AmbientDreamProxy nie widoczny w aktywnych wakélockach."
else
warn "AmbientDreamProxy nadal obecny: ${remaining}"
warn "Rozważ opcję [4] Dezaktywuj komponenty AOD dla trwałego efektu."
fi
info "Efekt utrzymuje się do następnego restartu. Dla trwałego — użyj opcji [4]."
pause
}
aod_gps_control() {
header "ZARZĄDZANIE GPS/GNSS (wakeup killer)"
echo -e " ${BYELLOW}Diagnoza z Twoich logów:${RESET}"
echo -e " ${DIM}wake_reason: \"12990000.gnss_mailbox\" — GNSS budzi CPU co kilka minut${RESET}"
echo -e " ${DIM}nawet gdy żadna aplikacja nie używa GPS aktywnie.${RESET}"
echo
local gps_mode
gps_mode=$(adb_get "settings get secure location_mode" || echo "?")
local gps_label
case "$gps_mode" in
0) gps_label="Wyłączone" ;;
1) gps_label="Tylko sensory (bez sieci)" ;;
2) gps_label="Tylko sieć (bez GPS)" ;;
3) gps_label="Wysoka dokładność (GPS + sieć)" ;;
*) gps_label="Nieznany ($gps_mode)" ;;
esac
status_row "Obecny tryb lokalizacji" "$gps_label"
echo
echo " [1] Wyłącz GPS całkowicie (0) — eliminuje wakeup gnss_mailbox"
echo " [2] Tylko sieć (2) — lokalizacja przez Wi-Fi bez GNSS hardware"
echo " [3] Wysoka dokładność (3) — przywróć pełne GPS"
echo " [4] Zatrzymaj proces GPS (tymczasowo)"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1)
safe_setting "secure" "location_mode" "0" "GPS (location_mode)"
safe_setting "secure" "location_providers_allowed" "" "GPS providers"
ok "GPS wyłączony. GNSS wakeup wyeliminowany."
warn "Funkcje fitness wymagające GPS (np. trasy na świeżym powietrzu) będą niedostępne."
;;
2)
safe_setting "secure" "location_mode" "2" "GPS (location_mode)"
ok "Tryb sieciowy — lokalizacja bez budzenia GNSS hardware."
;;
3)
safe_setting "secure" "location_mode" "3" "GPS (location_mode)"
ok "Pełne GPS przywrócone."
;;
4)
adb_cmd "am force-stop com.google.android.gms.location" >/dev/null 2>&1 || true
adb_cmd "settings put secure location_providers_allowed -gps" >/dev/null 2>&1
ok "GPS tymczasowo zatrzymany — efekt do restartu urządzenia."
;;
0) return ;;
esac
pause
}
aod_screen_timeouts() {
header "OPTYMALIZACJA TIMEOUTÓW EKRANU"
local cur_timeout
cur_timeout=$(adb_get "settings get system screen_off_timeout")
status_row "Aktualny timeout" "${cur_timeout} ms ($(( ${cur_timeout:-15000} / 1000 ))s)"
echo
echo " [1] 5 sekund (agresywne oszczędzanie)"
echo " [2] 10 sekund (zalecane dla WearOS)"
echo " [3] 15 sekund (domyślne)"
echo " [4] 30 sekund"
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1) safe_setting "system" "screen_off_timeout" "5000" "Timeout ekranu" ;;
2) safe_setting "system" "screen_off_timeout" "10000" "Timeout ekranu" ;;
3) safe_setting "system" "screen_off_timeout" "15000" "Timeout ekranu" ;;
4) safe_setting "system" "screen_off_timeout" "30000" "Timeout ekranu" ;;
*) warn "Nieprawidłowy wybór." ;;
esac
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 6 — OPTYMALIZACJA WYDAJNOŚCI
# ═══════════════════════════════════════════════════════════════════
performance_menu() {
while true; do
header "OPTYMALIZACJA WYDAJNOŚCI"
echo " [1] Animacje systemowe"
echo " [2] Renderer GPU (Exynos W920 — Vulkan/OpenGL)"
echo " [3] Kompilacja ART / DEX (bg-dexopt, speed-profile)"
echo " [4] Czyszczenie pamięci podręcznej"
echo " [5] Zarządzanie CPU Governor"
echo " [6] Optymalizacja Virtual Machine (Dalvik/ART flags)"
echo " [7] Profil TURBO (wszystkie optymalizacje)"
echo " [8] Przywróć ustawienia domyślne wydajności"
echo " [0] Powrót"
sep
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1) manage_animations ;;
2) manage_gpu ;;
3) optimize_art ;;
4) clear_caches ;;
5) manage_cpu_governor ;;
6) optimize_vm_flags ;;
7) apply_turbo_profile ;;
8) restore_defaults_perf ;;
0) return ;;
*) warn "Nieprawidłowy wybór." ;;
esac
done
}
manage_animations() {
header "ANIMACJE SYSTEMOWE"
local wa ts ad
wa=$(adb_get "settings get global window_animation_scale")
ts=$(adb_get "settings get global transition_animation_scale")
ad=$(adb_get "settings get global animator_duration_scale")
status_row "window_animation_scale" "$wa"
status_row "transition_animation_scale" "$ts"
status_row "animator_duration_scale" "$ad"
sep_thin
echo " [1] Wyłączone (0.0) — max responsywność, brak płynnych przejść"
echo " [2] 0.3x — szybkie, prawie niezauważalne"
echo " [3] 0.5x — zalecane dla WearOS"
echo " [4] 1.0x — domyślne"
echo " [5] Niestandardowe"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
set_animations() {
local v="$1"
safe_setting "global" "window_animation_scale" "$v" "window_animation_scale"
safe_setting "global" "transition_animation_scale" "$v" "transition_animation_scale"
safe_setting "global" "animator_duration_scale" "$v" "animator_duration_scale"
}
case "$ch" in
1) set_animations "0.0" ;;
2) set_animations "0.3" ;;
3) set_animations "0.5" ;;
4) set_animations "1.0" ;;
5)
read -rp "$(printf " Podaj wartość: ")" cv
[[ "$cv" =~ ^[0-9]+(\.[0-9]+)?$ ]] && set_animations "$cv" || err "Nieprawidłowa wartość."
;;
0) return ;;
esac
pause
}
manage_gpu() {
header "RENDERER GPU (EXYNOS W920)"
local cur_renderer
cur_renderer=$(adb_get "getprop debug.hwui.renderer 2>/dev/null"; echo "")
local cur_pipeline
cur_pipeline=$(adb_get "getprop debug.hwui.use_vulkan 2>/dev/null"; echo "")
status_row "debug.hwui.renderer" "${cur_renderer:-domyślny}"
status_row "debug.hwui.use_vulkan" "${cur_pipeline:-domyślny}"
sep_thin
echo " [1] Skia Vulkan (skiavk) — zalecane Exynos W920 + Android 16"
echo " [2] Skia OpenGL (skiagl) — stabilniejszy fallback"
echo " [3] Wymuś Vulkan pipeline (hwui.use_vulkan=1)"
echo " [4] Wyłącz debug overdraw"
echo " [5] Przywróć domyślny renderer"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1)
adb_cmd "setprop debug.hwui.renderer skiavk" >/dev/null
ok "Renderer: Skia Vulkan — restart aplikacji wymagany dla efektu."
warn "Jeśli pojawią się artefakty graficzne → użyj opcji [5]."
;;
2)
adb_cmd "setprop debug.hwui.renderer skiagl" >/dev/null
ok "Renderer: Skia OpenGL."
;;
3)
adb_cmd "setprop debug.hwui.use_vulkan 1" >/dev/null
ok "Vulkan pipeline wymuszony."
;;
4)
adb_cmd "setprop debug.hwui.overdraw false" >/dev/null
adb_cmd "setprop debug.hwui.show_dirty_regions false" >/dev/null
ok "Debug overdraw wyłączony."
;;
5)
adb_cmd "setprop debug.hwui.renderer ''" >/dev/null
adb_cmd "setprop debug.hwui.use_vulkan 0" >/dev/null
ok "Renderer przywrócony do domyślnego."
;;
0) return ;;
esac
pause
}
optimize_art() {
header "OPTYMALIZACJA ART / DEX (Android 16)"
echo " [1] bg-dexopt-job (profile-guided — ZALECANE)"
echo " [2] Kompilacja speed-profile dla wszystkich aplikacji"
echo " [3] Kompilacja speed (pełna — długa, więcej RAM)"
echo " [4] Reset i rekompilacja baseline (po aktualizacji systemu)"
echo " [5] Wymuś GC (Garbage Collection) we wszystkich procesach"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1)
step "Uruchamiam bg-dexopt-job (profile-guided, może potrwać 3-8 min)..."
warn "Nie blokuj ekranu i pozostań w zasięgu Wi-Fi."
echo
if adb_long "cmd package bg-dexopt-job"; then
ok "bg-dexopt-job zakończony sukcesem."
else
warn "bg-dexopt-job zwrócił błąd — próbuję przez pm compile..."
adb_long "pm compile -m speed-profile -a" && ok "pm compile zakończony." || err "Kompilacja nieudana — sprawdź log."
fi
;;
2)
step "Kompiluję wszystkie pakiety (speed-profile)..."
adb_long "pm compile -m speed-profile -a" && ok "Zakończono." || err "Błąd kompilacji."
;;
3)
warn "Kompilacja speed zajmie więcej czasu i wygeneruje duże pliki odex."
confirm "Kontynuować?" || { info "Anulowano."; pause; return; }
step "Kompilacja speed (pełna)..."
adb_long "pm compile -m speed -a" && ok "Zakończono." || err "Błąd."
;;
4)
warn "Reset profilów ART — system rekompiluje aplikacje stopniowo po restarcie."
confirm "Kontynuować?" || { info "Anulowano."; pause; return; }
adb_long "pm compile --reset -a" && ok "Profile ART zresetowane." || err "Błąd resetu."
info "Zalecany restart zegarka dla efektu."
;;
5)
step "Wymuszam GC we wszystkich procesach..."
adb_cmd "am force-stop --user all && echo ok" >/dev/null 2>&1 || true
local pids
pids=$(adb_get "ps -A 2>/dev/null | grep -v root | awk '{print \$1}'" | head -30)
local count=0
while IFS= read -r pid; do
[[ "$pid" =~ ^[0-9]+$ ]] || continue
adb_cmd "kill -10 $pid" >/dev/null 2>&1 && (( count++ )) || true
done <<< "$pids"
ok "GC wysłany do ${count} procesów."
;;
0) return ;;
esac
pause
}
clear_caches() {
header "CZYSZCZENIE PAMIĘCI PODRĘCZNEJ"
echo " [1] Trim caches aplikacji (pm trim-caches)"
echo " [2] Wyczyść cache SurfaceFlinger"
echo " [3] Wyczyść cache thumbnail / media"
echo " [4] Wymuś trim /data/cache"
echo " [5] Wszystkie powyższe"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
_trim_app_caches() {
step "Przycinam cache aplikacji..."
adb_cmd "pm trim-caches 4G" >/dev/null && ok "Cache aplikacji wyczyszczony." || err "pm trim-caches nieudane."
}
_sf_cache() {
step "Restartuję SurfaceFlinger cache..."
adb_cmd "service call SurfaceFlinger 1004 i32 0" >/dev/null 2>&1 && ok "SurfaceFlinger: odświeżony." || warn "SurfaceFlinger cache — pominięto (brak dostępu)."
}
_media_cache() {
step "Czyszczę cache mediów..."
adb_cmd "rm -rf /data/data/com.android.providers.media/cache/* 2>/dev/null" >/dev/null && ok "Cache mediów wyczyszczony." || warn "Cache mediów — brak dostępu (normalne bez root)."
}
_data_cache() {
step "Wymuszam trim /data/cache..."
adb_cmd "pm trim-caches 0" >/dev/null
adb_cmd "sync" >/dev/null 2>&1 && ok "Sync i trim zakończony." || warn "Sync pominięty."
}
case "$ch" in
1) _trim_app_caches ;;
2) _sf_cache ;;
3) _media_cache ;;
4) _data_cache ;;
5) _trim_app_caches; _sf_cache; _media_cache; _data_cache ;;
0) return ;;
esac
pause
}
manage_cpu_governor() {
header "CPU GOVERNOR (EXYNOS W920)"
warn "Zmiana governor'a wymaga dostępu root lub odblokowanego jądra."
warn "Na standardowym WearOS 6 ta opcja ogranicza się do odczytu."
echo
step "Odczyt obecnych ustawień CPU"
local core=0
for governor_path in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
local gov
gov=$(adb_get "cat ${governor_path} 2>/dev/null" || echo "niedostępny")
local freq_cur
freq_cur=$(adb_get "cat $(dirname "${governor_path}")/scaling_cur_freq 2>/dev/null || echo '?'")
local freq_max
freq_max=$(adb_get "cat $(dirname "${governor_path}")/scaling_max_freq 2>/dev/null || echo '?'")
printf " ${CYAN}CPU%d${RESET}: Governor=${BOLD}%s${RESET} | Curr=%s kHz | Max=%s kHz\n" \
"$core" "$gov" "$freq_cur" "$freq_max"
(( core++ ))
(( core > 4 )) && break
done
sep_thin
echo " [1] Ustaw governor 'performance' (próba bez root — może się nie udać)"
echo " [2] Ustaw governor 'schedutil' (zalecany balans)"
echo " [3] Odśwież odczyt stanu CPU"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1)
for cpu_path in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
adb_cmd "echo performance > ${cpu_path} 2>/dev/null" >/dev/null || true
done
ok "Próba ustawienia 'performance' — sprawdź odczyt opcją [3]."
;;
2)
for cpu_path in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
adb_cmd "echo schedutil > ${cpu_path} 2>/dev/null" >/dev/null || true
done
ok "Próba ustawienia 'schedutil'."
;;
3) manage_cpu_governor; return ;;
0) return ;;
esac
pause
}
optimize_vm_flags() {
header "OPTYMALIZACJA VM (DALVIK/ART FLAGS)"
local current_heapsize
current_heapsize=$(adb_get "getprop dalvik.vm.heapsize")
status_row "dalvik.vm.heapsize" "${current_heapsize:-domyślny}"
sep_thin
echo " [1] Optymalne flagi VM dla WearOS (lepsza GC, mniejszy heap pressure)"
echo " [2] Wymuś mały heap (agresywna GC — więcej wolnego RAM)"
echo " [3] Przywróć domyślne flagi VM"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1)
# Flagi sprawdzone dla Android 14-16 WearOS
adb_cmd "setprop dalvik.vm.heapgrowthlimit 48m" >/dev/null
adb_cmd "setprop dalvik.vm.heapminfree 512k" >/dev/null
adb_cmd "setprop dalvik.vm.heaptargetutilization 0.75" >/dev/null
adb_cmd "setprop dalvik.vm.dex2oat-filter speed-profile" >/dev/null
adb_cmd "setprop dalvik.vm.dex2oat-threads 2" >/dev/null
ok "Flagi VM zoptymalizowane dla WearOS."
;;
2)
adb_cmd "setprop dalvik.vm.heapgrowthlimit 32m" >/dev/null
adb_cmd "setprop dalvik.vm.heapmaxfree 4m" >/dev/null
adb_cmd "setprop dalvik.vm.heaptargetutilization 0.6" >/dev/null
ok "Mały heap — więcej wolnego RAM, częstszy GC."
;;
3)
adb_cmd "setprop dalvik.vm.heapgrowthlimit ''" >/dev/null
adb_cmd "setprop dalvik.vm.heapminfree ''" >/dev/null
adb_cmd "setprop dalvik.vm.heaptargetutilization ''" >/dev/null
ok "Flagi VM przywrócone do domyślnych."
;;
0) return ;;
esac
pause
}
apply_turbo_profile() {
header "PROFIL TURBO — KOMPLEKSOWA OPTYMALIZACJA"
echo -e " ${BYELLOW}Wykona kolejno WSZYSTKIE bezpieczne optymalizacje:${RESET}"
echo " → AOD wyłączone"
echo " → AmbientDreamProxy wakelock zatrzymany"
echo " → GPS tryb sieciowy (eliminuje gnss_mailbox wakeup)"
echo " → WSZYSTKIE 3 animacje 0.5x (w tym window_animation_scale)"
echo " → Renderer Skia Vulkan"
echo " → Optymalne flagi VM"
echo " → bg-dexopt-job (ART recompile)"
echo " → Trim caches"
echo
confirm "Zastosować profil TURBO?" || { info "Anulowano."; pause; return; }
sep
step "1/8 — AOD..."
safe_setting "secure" "doze_always_on" "0" "AOD"
safe_setting "secure" "doze_wake_display_on_gesture" "0" "Wybudzenie gestem"
safe_setting "secure" "doze_pick_up_gesture" "0" "Pulse on pick-up"
safe_setting "secure" "doze_pulse_on_double_tap" "0" "Pulse on double-tap"
step "2/8 — AmbientDreamProxy kill (fix lagów wybudzenia)..."
for pkg in com.samsung.android.app.aodservice com.samsung.systemui.aod; do
adb_cmd "am force-stop ${pkg}" >/dev/null 2>&1 && ok "force-stop: ${pkg}" || true
done
step "3/8 — GPS tryb sieciowy (eliminuje gnss_mailbox wakeup)..."
safe_setting "secure" "location_mode" "2" "GPS location_mode (sieciowy)"
step "4/8 — WSZYSTKIE animacje 0.5x..."
# BUGFIX v3.1: ustawiamy wszystkie 3, łącznie z window (które było 1.0 w logach)
safe_setting "global" "window_animation_scale" "0.5" "window_animation_scale"
safe_setting "global" "transition_animation_scale" "0.5" "transition_animation_scale"
safe_setting "global" "animator_duration_scale" "0.5" "animator_duration_scale"
step "5/8 — Renderer GPU..."
adb_cmd "setprop debug.hwui.renderer skiavk" >/dev/null && ok "Renderer: Skia Vulkan (Exynos W920)"
step "6/8 — VM flags..."
adb_cmd "setprop dalvik.vm.dex2oat-filter speed-profile" >/dev/null && ok "VM: speed-profile dex2oat"
adb_cmd "setprop dalvik.vm.dex2oat-threads 2" >/dev/null && ok "VM: 2 dex2oat threads"
step "7/8 — Cache trim..."
adb_cmd "pm trim-caches 4G" >/dev/null && ok "Cache: wyczyszczony"
step "8/8 — ART bg-dexopt-job (to zajmie chwilę)..."
if adb_long "cmd package bg-dexopt-job" | tail -3; then
ok "ART: bg-dexopt-job zakończony."
else
warn "bg-dexopt-job — próba pm compile..."
adb_long "pm compile -m speed-profile -a" | tail -3 && ok "ART: pm compile OK." || err "ART: kompilacja nieudana."
fi
sep
ok "Profil TURBO zastosowany!"
info "Zalecany restart zegarka: opcja 'Naprawy → Restart'"
pause
}
restore_defaults_perf() {
header "PRZYWRACANIE DOMYŚLNYCH USTAWIEŃ WYDAJNOŚCI"
confirm "Przywrócić domyślne ustawienia animacji, GPU, AOD?" || { info "Anulowano."; pause; return; }
safe_setting "global" "window_animation_scale" "1.0" "window_animation_scale"
safe_setting "global" "transition_animation_scale" "1.0" "transition_animation_scale"
safe_setting "global" "animator_duration_scale" "1.0" "animator_duration_scale"
safe_setting "secure" "doze_always_on" "1" "AOD"
adb_cmd "setprop debug.hwui.renderer ''" >/dev/null && ok "Renderer: domyślny"
adb_cmd "setprop debug.hwui.use_vulkan 0" >/dev/null && ok "Vulkan flag: wyłączony"
ok "Ustawienia domyślne przywrócone."
pause
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 7 — DEBLOAT
# ═══════════════════════════════════════════════════════════════════
# Katalog debloat — TYLKO aplikacje bezpieczne do wyłączenia (nie usunięcia)
# Podzielone na kategorie z poziomem ryzyka
declare -A DEBLOAT_PKGS_LOW=(
# RYZYKO NISKIE — można bezpiecznie wyłączyć
["com.samsung.android.app.tips"]="Wskazówki Samsung"
["com.samsung.android.forest"]="Digital Wellbeing (ekran wellness)"
["com.samsung.android.game.gos"]="Game Optimizing Service"
["com.samsung.android.app.social"]="Samsung Social apps"
["com.sec.android.app.chromecustomtabs"]="Chrome Custom Tabs"
["com.samsung.systemui.bixby.wearable"]="Bixby Watch"
["com.samsung.android.bixby.agent"]="Bixby Agent"
["com.samsung.android.app.spage"]="Bixby Home"
["com.samsung.android.beaconmanager"]="Beacon Manager"
["com.samsung.android.dynamiclock"]="Dynamic Lock Screen"
# Nowe — zidentyfikowane w logach 23.02.2026 jako hogi 40-50 MB
["com.samsung.android.easyMover"]="Easy Mover (~50 MB — transfer danych, zbędny na zegarku)"
["com.samsung.android.diagmonagent"]="DiagMonAgent (~41 MB — diagnostyka fabryczna)"
["com.samsung.android.app.reminder"]="Samsung Reminder (~42 MB)"
)
declare -A DEBLOAT_PKGS_MEDIUM=(
# RYZYKO ŚREDNIE — wyłącz ostrożnie
["com.samsung.android.app.reminder"]="Samsung Reminder"
["com.samsung.android.app.notes"]="Samsung Notes (watch)"
["com.samsung.android.app.samsungpay.wear"]="Samsung Pay Wear"
["com.samsung.android.app.watchmanager"]="Watch Manager (companion)"
["com.samsung.android.gearoplugin"]="Gear O Plugin"
["com.samsung.android.app.galaxyfind"]="Find My Watch (Podziel jeśli nieużywany)"
["com.samsung.android.mobileservice"]="Samsung Mobile Service"
)
debloat_menu() {
while true; do
header "DEBLOAT — BEZPIECZNE ZARZĄDZANIE APLIKACJAMI"
echo -e " ${GREEN}ZASADA: Tylko disable-user — żadnej aplikacji nie usuwamy!${RESET}"
echo -e " ${GREEN}Wszystkie zmiany są w pełni odwracalne przez opcję [4].${RESET}"
sep_thin
echo " [1] Przejrzyj i wyłącz aplikacje NISKIE RYZYKO (zalecane)"
echo " [2] Przejrzyj i wyłącz aplikacje ŚREDNIE RYZYKO (ostrożnie)"
echo " [3] Pokaż wszystkie aktualnie wyłączone aplikacje"
echo " [4] Przywróć wyłączone aplikacje Watch4 Suite"
echo " [5] Skanuj zasoby pożerające aplikacje (top hog scan)"
echo " [0] Powrót"
sep
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1) debloat_process_list "LOW" ;;
2) debloat_process_list "MEDIUM" ;;
3) debloat_show_disabled ;;
4) debloat_restore_all ;;
5) debloat_hog_scan ;;
0) return ;;
*) warn "Nieprawidłowy wybór." ;;
esac
done
}
debloat_process_list() {
local risk_level="$1"
header "DEBLOAT — RYZYKO: ${risk_level}"
# Wybierz odpowiedni słownik
local -n pkg_map
if [[ "$risk_level" == "LOW" ]]; then
pkg_map=DEBLOAT_PKGS_LOW
echo -e " ${GREEN}Aplikacje w tej kategorii są bezpieczne do wyłączenia.${RESET}"
else
pkg_map=DEBLOAT_PKGS_MEDIUM
echo -e " ${YELLOW}Aplikacje w tej kategorii — wyłącz tylko jeśli NIE używasz ich funkcji.${RESET}"
fi
echo
local disabled_log="${BACKUP_DIR}/debloat_${risk_level,,}.sh"
echo "#!/usr/bin/env bash" > "$disabled_log"
echo "# Przywracanie debloat ${risk_level}" >> "$disabled_log"
local i=1 pkgs_arr=()
for pkg in "${!pkg_map[@]}"; do
pkgs_arr+=("$pkg")
done
for pkg in "${pkgs_arr[@]}"; do
local desc="${pkg_map[$pkg]}"
# Sprawdź czy zainstalowany
local installed
installed=$(adb_get "pm list packages 2>/dev/null | grep -c ${pkg}" || echo "0")
local status_str
local is_disabled
is_disabled=$(adb_get "pm list packages -d 2>/dev/null | grep -c ${pkg}" || echo "0")
if [[ "$installed" -lt 1 ]] 2>/dev/null; then
status_str="${DIM}(nie zainstalowany)${RESET}"
elif [[ "$is_disabled" -gt 0 ]] 2>/dev/null; then
status_str="${YELLOW}(już wyłączony)${RESET}"
else
status_str="${GREEN}(aktywny)${RESET}"
fi
printf "\n [%2d] ${BOLD}%s${RESET}\n ${DIM}%s${RESET} %s\n" \
"$i" "$desc" "$pkg" "$status_str"
(( i++ ))
done
echo
sep_thin
echo " Wpisz numery aplikacji do wyłączenia (np: 1 3 5) lub [A] dla wszystkich aktywnych,"
read -rp " lub [0] aby anulować: " selection
[[ "$selection" == "0" ]] && return
local selected_pkgs=()
if [[ "${selection,,}" == "a" ]]; then
selected_pkgs=("${pkgs_arr[@]}")
else
for num in $selection; do
if [[ "$num" =~ ^[0-9]+$ ]] && (( num >= 1 && num <= ${#pkgs_arr[@]} )); then
selected_pkgs+=("${pkgs_arr[$((num-1))]}")
fi
done
fi
if [[ ${#selected_pkgs[@]} -eq 0 ]]; then
warn "Nie wybrano żadnych aplikacji."; pause; return
fi
echo
warn "Zamierzam wyłączyć ${#selected_pkgs[@]} aplikację/aplikacje:"
for pkg in "${selected_pkgs[@]}"; do
printf " ${CYAN}%s${RESET} — %s\n" "$pkg" "${pkg_map[$pkg]}"
done
echo
confirm "Potwierdzasz wyłączenie?" || { info "Anulowano."; pause; return; }
echo
for pkg in "${selected_pkgs[@]}"; do
echo "pm enable ${pkg}" >> "$disabled_log"
if adb_cmd "pm disable-user --user 0 ${pkg}" >/dev/null 2>&1; then
ok "Wyłączono: ${pkg_map[$pkg]}"
else
warn "Pominięto (może nie istnieć na tym urządzeniu): ${pkg}"
fi
done
echo
ok "Gotowe. Skrypt przywracania: ${disabled_log}"
info "Użyj opcji [4] w menu debloat aby przywrócić wszystko jednym kliknięciem."
pause
}
debloat_show_disabled() {
header "WYŁĄCZONE APLIKACJE (wszystkie)"
local disabled
disabled=$(adb_get "pm list packages -d 2>/dev/null" | sed 's/package://' | sort)
if [[ -z "$disabled" ]]; then
info "Brak wyłączonych aplikacji."; pause; return
fi
echo "$disabled" | while IFS= read -r pkg; do
printf " ${YELLOW}●${RESET} %s\n" "$pkg"
done
echo
info "Łącznie wyłączonych: $(echo "$disabled" | wc -l | tr -d ' ')"
pause
}
debloat_restore_all() {
header "PRZYWRACANIE APLIKACJI"
info "Przywracam wszystkie aplikacje wyłączone przez Watch4 Suite..."
local all_pkgs=("${!DEBLOAT_PKGS_LOW[@]}" "${!DEBLOAT_PKGS_MEDIUM[@]}")
local restored=0 skipped=0
for pkg in "${all_pkgs[@]}"; do
if adb_cmd "pm enable ${pkg}" >/dev/null 2>&1; then
ok "Przywrócono: ${pkg}"
(( restored++ ))
else
(( skipped++ ))
fi
done
ok "Przywrócono: ${restored} | Pominięto (nie było wyłączone): ${skipped}"
pause
}
debloat_hog_scan() {
header "SKAN POŻERACZY ZASOBÓW"
step "Analizuję zużycie CPU i RAM przez aplikacje (10 sekund)..."
echo
# CPU hogs
printf " ${BOLD}TOP 10 PROCESÓW — RAM${RESET}\n"
sep_thin
printf " ${DIM}%-8s %-8s %s${RESET}\n" "PID" "RSS(MB)" "APLIKACJA"
adb_get "ps -eo pid,rss,args 2>/dev/null | sort -k2 -rn | head -10" | while IFS= read -r line; do
local pid rss app
read -r pid rss app <<< "$line"
if [[ "$rss" =~ ^[0-9]+$ ]]; then
local rss_mb=$(( rss / 1024 ))
local color="$WHITE"
(( rss_mb > 80 )) && color="$YELLOW"
(( rss_mb > 150 )) && color="$RED"
printf " ${color}%-8s %-8s %s${RESET}\n" "$pid" "${rss_mb}MB" "${app:0:45}"
fi
done
sep_thin
step "Wakelock analysis (aplikacje budzące CPU)"
adb_get "dumpsys power 2>/dev/null" | grep -E "PARTIAL_WAKE_LOCK|acquired|held" | head -10 | while IFS= read -r line; do
printf " ${YELLOW}%s${RESET}\n" "$line"
done || detail "Brak dostępnych wakelock."
sep_thin
step "Battery drain — wina aplikacji (BatteryStats)"
adb_get "dumpsys batterystats --charged 2>/dev/null" | grep -E "Uid|wake|cpu" | head -15 | while IFS= read -r line; do
detail "$line"
done
pause
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 8 — NAPRAWA SYSTEMU
# ═══════════════════════════════════════════════════════════════════
repair_menu() {
while true; do
header "NAPRAWA SYSTEMU"
echo " [1] Reset UI (SystemUI, Launcher — bez restartu urządzenia)"
echo " [2] Reset stack Activity Manager (napraw zamrożone aplikacje)"
echo " [3] Naprawa sieci Wi-Fi (reset stosu sieciowego)"
echo " [4] Naprawa Bluetooth (reset stosu BT)"
echo " [5] Wymuszenie synchonizacji zegara systemowego"
echo " [6] Naprawa bazy danych PackageManager"
echo " [7] Restart usług systemowych (bezpieczny)"
echo " [8] Reset sensorów i health tracking"
echo " [9] Pełny bezpieczny restart zegarka"
echo " [10] Tryb odzyskiwania — eksport logów PRZED restartem"
echo " [0] Powrót"
sep
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1) repair_ui_reset ;;
2) repair_activity_stack ;;
3) repair_wifi ;;
4) repair_bluetooth ;;
5) repair_time_sync ;;
6) repair_package_manager ;;
7) repair_services ;;
8) repair_sensors ;;
9) repair_safe_reboot ;;
10) repair_export_before_reboot ;;
0) return ;;
*) warn "Nieprawidłowy wybór." ;;
esac
done
}
repair_ui_reset() {
header "RESET UI SYSTEMU"
warn "Ekran zegarka może migotać przez chwilę — to normalne."
echo
step "Restartuję SystemUI..."
adb_cmd "am force-stop com.android.systemui" >/dev/null && ok "SystemUI zatrzymany." || warn "SystemUI — problem."
sleep 2
# SystemUI restartuje się automatycznie; jeśli nie — poniżej
adb_cmd "am startservice --user 0 -n com.android.systemui/.SystemUIService" >/dev/null 2>&1 || true
sleep 2
step "Restartuję Launcher Samsung..."
local launcher_pkg
launcher_pkg=$(adb_get "pm list packages 2>/dev/null | grep -i 'launcher\|homescreen\|wlauncher'" | head -1 | sed 's/package://')
if [[ -n "$launcher_pkg" ]]; then
adb_cmd "am force-stop ${launcher_pkg}" >/dev/null && ok "Launcher zatrzymany: ${launcher_pkg}"
else
warn "Launcher nie zidentyfikowany."
fi
step "Restartuję usługę watchface..."
adb_cmd "am force-stop com.samsung.android.app.watchface" >/dev/null 2>&1 && ok "Watchface service zrestartowany." || warn "Watchface service — pominięto."
ok "Reset UI zakończony. Zegarek powinien odświeżyć interfejs."
pause
}
repair_activity_stack() {
header "RESET ACTIVITY MANAGER STACK"
step "Czyszczę stos zadań Activity Managera..."
adb_cmd "am clear-recent-tasks" >/dev/null 2>&1 && ok "Recent tasks wyczyszczone." || warn "Pominięto."
step "Reset animacji przejść..."
adb_cmd "wm dismiss-keyguard" >/dev/null 2>&1 || true
sleep 1
adb_cmd "input keyevent KEYCODE_WAKEUP" >/dev/null 2>&1 || true
step "Sprawdzam zakleszczone procesy..."
adb_get "dumpsys activity processes 2>/dev/null" | grep -i "ANR\|LOCK\|WAIT" | head -5 | while IFS= read -r line; do
warn "$line"
done || ok "Brak zakleszczonych procesów."
pause
}
repair_wifi() {
header "NAPRAWA WI-FI"
warn "Ta operacja zresetuje stos Wi-Fi — połączenie ADB chwilowo zerwane!"
confirm "Kontynuować? (Skrypt automatycznie ponownie połączy)" || { info "Anulowano."; pause; return; }
step "Zapisuję aktualny IP..."
local saved_serial="$DEVICE_SERIAL"
step "Wyłączam Wi-Fi..."
adb_cmd "svc wifi disable" >/dev/null 2>&1 || true
sleep 3
step "Włączam Wi-Fi..."
adb_cmd "svc wifi enable" >/dev/null 2>&1 || true
info "Czekam 10 sekund na reconnect..."
sleep 10
step "Próba ponownego połączenia ADB..."
local retries=5
while (( retries > 0 )); do
if adb connect "$saved_serial" >/dev/null 2>&1 && ping_device; then
DEVICE_SERIAL="$saved_serial"
ok "Ponownie połączono z ${DEVICE_SERIAL}"
break
fi
(( retries-- ))
warn "Próba połączenia... pozostało ${retries}"
sleep 3
done
if (( retries == 0 )); then
err "Nie udało się połączyć automatycznie."
err "Uruchom skrypt ponownie po chwili."
fi
pause
}
repair_bluetooth() {
header "NAPRAWA BLUETOOTH"
step "Wyłączam Bluetooth..."
adb_cmd "svc bluetooth disable" >/dev/null 2>&1 && ok "BT wyłączony." || warn "BT disable — pominięto."
sleep 3
step "Włączam Bluetooth..."
adb_cmd "svc bluetooth enable" >/dev/null 2>&1 && ok "BT włączony." || warn "BT enable — pominięto."
sleep 2
step "Sprawdzam status BT..."
local bt_state
bt_state=$(adb_get "settings get global bluetooth_on 2>/dev/null")
status_row "bluetooth_on" "${bt_state:-?}"
ok "Reset Bluetooth zakończony."
pause
}
repair_time_sync() {
header "SYNCHRONIZACJA ZEGARA SYSTEMOWEGO"
step "Obecny czas systemowy..."
adb_get "date" | while IFS= read -r line; do detail "$line"; done
step "Synchronizuję czas z NTP..."
adb_cmd "settings put global ntp_server pool.ntp.org" >/dev/null && ok "NTP server: pool.ntp.org"
adb_cmd "settings put global auto_time 1" >/dev/null && ok "Auto-time włączony"
adb_cmd "settings put global auto_time_zone 1" >/dev/null && ok "Auto-timezone włączony"
# Wymuś sync przez restart serwisu czasu
adb_cmd "am broadcast -a android.intent.action.TIME_SET" >/dev/null 2>&1 && ok "TIME_SET broadcast wysłany." || warn "Broadcast — pominięto."
step "Czas po synchronizacji:"
sleep 2
adb_get "date" | while IFS= read -r line; do ok "$line"; done
pause
}
repair_package_manager() {
header "NAPRAWA BAZY DANYCH PACKAGEMANAGER"
warn "Ta operacja wyczyści pamięć podręczną PackageManagera i zreoptymalizuje bazę."
step "Sprawdzam integralność PackageManager..."
local pm_err
pm_err=$(adb_get "pm dump com.android.providers.settings 2>/dev/null | grep -i error | head -5" || echo "")
[[ -n "$pm_err" ]] && warn "Wykryte błędy PM: $pm_err" || ok "PM integrity: brak widocznych błędów."
step "Czyszczę cache PackageManager..."
adb_cmd "pm clear com.android.providers.settings" >/dev/null 2>&1 && ok "Settings provider cache wyczyszczony." || warn "Pominięto."
step "Rekompilacja zoptymalizowanego kodu PackageManager..."
adb_cmd "pm compile -m speed-profile com.android.settings" >/dev/null 2>&1 && ok "Settings recompiled." || warn "Pominięto."
step "Trim storage..."
adb_cmd "pm trim-caches 4G" >/dev/null && ok "Storage trimmed."
ok "Naprawa PM zakończona."
pause
}
repair_services() {
header "RESTART USŁUG SYSTEMOWYCH (BEZPIECZNY)"
echo " [1] Restart SurfaceFlinger (napraw rendering)"
echo " [2] Restart MediaServer (napraw audio/media)"
echo " [3] Restart InputDispatcher (napraw dotyk)"
echo " [4] Wyczyść cache i zrestartuj wszystkie kluczowe usługi"
echo " [0] Powrót"
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1)
warn "Ekran może migać przez 2-5 sekund."
adb_cmd "kill \$(pidof surfaceflinger)" >/dev/null 2>&1
sleep 3 && ok "SurfaceFlinger zrestartowany (automatycznie przez init)."
;;
2)
adb_cmd "kill \$(pidof mediaserver)" >/dev/null 2>&1
sleep 2 && ok "MediaServer zrestartowany."
;;
3)
adb_cmd "kill \$(pidof inputdispatcher)" >/dev/null 2>&1
sleep 1 && ok "InputDispatcher zrestartowany."
;;
4)
warn "Restartuję kluczowe usługi — chwilowe zakłócenie UI."
confirm "Kontynuować?" || { info "Anulowano."; return; }
for svc_proc in surfaceflinger mediaserver; do
adb_cmd "kill \$(pidof ${svc_proc} 2>/dev/null)" >/dev/null 2>&1 && ok "${svc_proc}: restarted" || warn "${svc_proc}: pominięto"
sleep 1
done
;;
0) return ;;
esac
pause
}
repair_sensors() {
header "RESET SENSORÓW I HEALTH TRACKING"
step "Resetuję kalibrację sensorów..."
adb_cmd "am broadcast -a android.intent.action.SENSOR_RECALIBRATION" >/dev/null 2>&1 || true
adb_cmd "am force-stop com.samsung.android.wear.shealth" >/dev/null 2>&1 && ok "Samsung Health Watch zrestartowany." || warn "Samsung Health Watch — pominięto."
adb_cmd "am force-stop com.samsung.android.service.health" >/dev/null 2>&1 && ok "Health Service zrestartowany." || warn "Health Service — pominięto."
step "Sprawdzam sensory..."
adb_get "dumpsys sensorservice 2>/dev/null | head -20" | while IFS= read -r line; do
detail "$line"
done
ok "Reset sensorów zakończony. Pomiary zdrowia zostaną skalibrowane podczas kolejnego noszenia."
pause
}
repair_safe_reboot() {
header "BEZPIECZNY RESTART ZEGARKA"
# Przed restartem — wykonaj backup
if [[ "$BACKUP_DONE" == "false" ]]; then
step "Tworzę backup ustawień przed restartem..."
adb_get "settings list global" > "${BACKUP_DIR}/global_settings.txt" 2>/dev/null
adb_get "settings list secure" > "${BACKUP_DIR}/secure_settings.txt" 2>/dev/null
adb_get "settings list system" > "${BACKUP_DIR}/system_settings.txt" 2>/dev/null
ok "Backup zapisany: ${BACKUP_DIR}/"
BACKUP_DONE=true
fi
warn "Zegarek uruchomi się ponownie. Połączenie ADB zostanie zerwane."
confirm "Uruchomić ponownie zegarek?" || { info "Anulowano."; pause; return; }
info "Restartuję zegarek..."
adb -s "$DEVICE_SERIAL" reboot
ok "Restart zlecony."
info "Zegarek będzie dostępny za ~60-90 sekund."
info "Uruchom skrypt ponownie po restarcie."
exit 0
}
repair_export_before_reboot() {
header "EKSPORT LOGÓW PRZED RESTARTEM"
local export_dir="${LOG_DIR}/pre_reboot_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$export_dir"
step "Eksportuje pełną diagnostykę..."
{
echo "=== PRE-REBOOT DUMP ==="
echo "Date: $(date)"
echo "Device: $DEVICE_SERIAL"
adb_get "dumpsys" 2>/dev/null
} > "${export_dir}/dumpsys_full.txt" &
spinner $! "Zbieranie dumpsys (może potrwać 30s)..."
adb_get "logcat -d 2>/dev/null" > "${export_dir}/logcat.txt" &
spinner $! "Zbieranie logcat..."
adb_get "getprop 2>/dev/null" > "${export_dir}/getprop.txt"
ok "Eksport zakończony: ${export_dir}"
info "Możesz teraz bezpiecznie wykonać restart zegarka."
pause
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 9 — BACKUP / RESTORE PEŁNY
# ═══════════════════════════════════════════════════════════════════
backup_menu() {
while true; do
header "BACKUP I PRZYWRACANIE"
status_row "Katalog backup" "$BACKUP_DIR"
sep_thin
echo " [1] Backup wszystkich ustawień systemowych"
echo " [2] Przywróć ustawienia z backupu tej sesji"
echo " [3] Pokaż istniejące backupy"
echo " [4] Eksportuj backup na zegarek (/sdcard/watch4_backup/)"
echo " [0] Powrót"
sep
read -rp "$(printf " Wybór: ")" ch
case "$ch" in
1) backup_settings ;;
2) restore_from_backup ;;
3) list_backups ;;
4) export_backup_to_watch ;;
0) return ;;
*) warn "Nieprawidłowy wybór." ;;
esac
done
}
backup_settings() {
step "Tworzę pełny backup ustawień systemowych..."
adb_get "settings list global 2>/dev/null" | while IFS='=' read -r key val; do
echo "settings put global '${key}' '${val}'"
done > "${BACKUP_DIR}/restore_global.sh"
adb_get "settings list secure 2>/dev/null" | while IFS='=' read -r key val; do
echo "settings put secure '${key}' '${val}'"
done > "${BACKUP_DIR}/restore_secure.sh"
adb_get "settings list system 2>/dev/null" | while IFS='=' read -r key val; do
echo "settings put system '${key}' '${val}'"
done > "${BACKUP_DIR}/restore_system.sh"
BACKUP_DONE=true
ok "Backup zakończony: ${BACKUP_DIR}/"
detail "restore_global.sh | restore_secure.sh | restore_system.sh"
pause
}
restore_from_backup() {
if [[ "$BACKUP_DONE" == "false" ]]; then
warn "Nie wykonano backupu w tej sesji. Wykonaj najpierw opcję [1]."; pause; return
fi
step "Przywracam ustawienia z backupu..."
for restore_script in "${BACKUP_DIR}"/restore_*.sh "${BACKUP_DIR}"/debloat_*.sh; do
[[ -f "$restore_script" ]] || continue
info "Przetwarzam: $(basename "$restore_script")"
while IFS= read -r cmd; do
[[ "$cmd" =~ ^# ]] && continue
[[ -z "$cmd" ]] && continue
adb_cmd "$cmd" >/dev/null 2>&1 || true
done < "$restore_script"
done
ok "Przywracanie zakończone."
pause
}
list_backups() {
header "ISTNIEJĄCE BACKUPY"
find "$LOG_DIR" -name "*.sh" -o -name "*.txt" 2>/dev/null | while IFS= read -r f; do
printf " ${CYAN}%s${RESET} (%.1f KB)\n" "$f" "$(du -k "$f" | cut -f1)"
done || info "Brak backupów."
pause
}
export_backup_to_watch() {
step "Eksportuje backup na zegarek..."
adb_cmd "mkdir -p /sdcard/watch4_backup/" >/dev/null 2>&1
for f in "${BACKUP_DIR}"/*.sh "${BACKUP_DIR}"/*.txt; do
[[ -f "$f" ]] || continue
adb push "$f" "/sdcard/watch4_backup/$(basename "$f")" >/dev/null 2>&1 && ok "$(basename "$f")" || warn "Nie można przesłać: $f"
done
ok "Backup dostępny na zegarku: /sdcard/watch4_backup/"
pause
}
# ═══════════════════════════════════════════════════════════════════
# SEKCJA 10 — MENU GŁÓWNE
# ═══════════════════════════════════════════════════════════════════
main_menu() {
while true; do
print_banner
printf " ${BOLD}Urządzenie: ${CYAN}%s${RESET} | ${BOLD}Model: ${CYAN}%s${RESET} | ${BOLD}Android: ${CYAN}%s${RESET}\n\n" \
"$DEVICE_SERIAL" "$DEVICE_MODEL" "$DEVICE_ANDROID"
echo -e " ${BOLD}${WHITE}[ DIAGNOSTYKA ]${RESET}"
echo " [1] Diagnostyka proaktywna (monitoring, logi, analiza)"
echo
echo -e " ${BOLD}${WHITE}[ OPTYMALIZACJA ]${RESET}"
echo " [2] Zarządzanie AOD (Always-On Display)"
echo " [3] Wydajność systemu (animacje, GPU, ART, CPU)"
echo
echo -e " ${BOLD}${WHITE}[ ZARZĄDZANIE SYSTEMEM ]${RESET}"
echo " [4] Debloat — bezpieczne zarządzanie aplikacjami"
echo " [5] Naprawa systemu (UI, sieć, sensory, restart)"
echo
echo -e " ${BOLD}${WHITE}[ DANE ]${RESET}"
echo " [6] Backup i przywracanie ustawień"
echo
echo -e " ${BOLD}${WHITE}[ SZYBKIE AKCJE ]${RESET}"
echo " [T] ⚡ Profil TURBO — pełna optymalizacja"
echo " [R] ↩ Przywróć domyślne ustawienia wydajności"
echo " [Q] Rozłącz i zakończ"
sep
read -rp "$(printf " Wybór: ")" choice
case "${choice,,}" in
1) diagnostics_menu ;;
2) aod_menu ;;
3) performance_menu ;;
4) debloat_menu ;;
5) repair_menu ;;
6) backup_menu ;;
t) apply_turbo_profile ;;
r) restore_defaults_perf ;;
q)
info "Rozłączam ${DEVICE_SERIAL}..."
adb disconnect "$DEVICE_SERIAL" &>/dev/null || true
ok "Sesja zakończona."
info "Log sesji: ${LOG_FILE}"
if [[ "$BACKUP_DONE" == "true" ]]; then
info "Backup ustawień: ${BACKUP_DIR}/"
fi
exit 0
;;
*) warn "Nieprawidłowy wybór." ; sleep 1 ;;
esac
done
}
# ═══════════════════════════════════════════════════════════════════
# PUNKT WEJŚCIA
# ═══════════════════════════════════════════════════════════════════
main() {
print_banner
log "=== ${SCRIPT_NAME} v${VERSION} — Sesja rozpoczęta ==="
log "System: $(uname -a)"
check_adb_installed
connect_device
main_menu
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment