Private
Public Access
Minamp 1.3
- Fix NoSuchMethodError on Android 2.x: Dalvik before 4.0 can't link Object methods (toString/equals/...) called through an interface. Patch the bundled Bouncy Castle (tools/patch_bc_dalvik.py) and our own CertVerifier, and make build.sh fail if tools/scan_dalvik.py finds any such call - Treat a manually entered private address (10.x, 172.16-31.x, 192.168.x, .local) as home, so LAN servers that allow access without sign-in work - Send Plex client headers on media requests (files and transcodes) - Explain a 503 on a file as the server being unable to open it (drive or folder not available) - Connection log: home/away, token presence, Plex's file check and a direct file request in the streaming test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a4b875ef34
commit
58d21b6d68
14 files changed
+218
-13
No files matched your search
@@ -0,0 +1,46 @@
|
||||
# Find invokeinterface calls to java.lang.Object methods (toString/equals/hashCode/getClass) through an
|
||||
# interface that doesn't declare them itself: Dalvik before 4.0 can't resolve those (NoSuchMethodError).
|
||||
import os, re, subprocess, sys, zipfile
|
||||
classes = sys.argv[1]; android_jar = sys.argv[2]
|
||||
OBJ = {"toString:()Ljava/lang/String;", "equals:(Ljava/lang/Object;)Z", "hashCode:()I", "getClass:()Ljava/lang/Class;"}
|
||||
z = zipfile.ZipFile(android_jar)
|
||||
declared = {}
|
||||
def declares(iface, m):
|
||||
key = (iface, m)
|
||||
if key in declared: return declared[key]
|
||||
path = os.path.join(classes, iface + ".class")
|
||||
src = path if os.path.exists(path) else None
|
||||
args = ["javap", "-p", "-s", "-cp", classes if src else android_jar, iface.replace("/", ".")]
|
||||
out = subprocess.run(args, capture_output=True, text=True).stdout
|
||||
name, desc = m.split(":")
|
||||
found = False
|
||||
lines = out.splitlines()
|
||||
for i, l in enumerate(lines):
|
||||
if re.search(r"\b" + name + r"\(", l) and i + 1 < len(lines) and desc in lines[i + 1]:
|
||||
found = True
|
||||
# superinterfaces declaring it also count
|
||||
if not found:
|
||||
mm = re.search(r"interface \S+ extends (.+?) \{", out)
|
||||
if mm:
|
||||
for sup in mm.group(1).split(","):
|
||||
sup = sup.strip().split("<")[0].replace(".", "/")
|
||||
if sup and declares(sup, m): found = True
|
||||
declared[key] = found
|
||||
return found
|
||||
hits = {}
|
||||
files = [os.path.join(dp, f) for dp, _, fs in os.walk(classes) for f in fs if f.endswith(".class")]
|
||||
for i in range(0, len(files), 200):
|
||||
out = subprocess.run(["javap", "-c", "-p"] + files[i:i+200], capture_output=True, text=True).stdout
|
||||
cur = None
|
||||
for line in out.splitlines():
|
||||
m = re.match(r"^(?:public |final |abstract |class |interface )*.*?(?:class|interface) (\S+)", line)
|
||||
if m and not line.startswith(" "): cur = m.group(1)
|
||||
mi = re.search(r"invokeinterface\s+#\d+,\s*\d+\s*// InterfaceMethod (\S+)\.(\w+):(\S+)", line)
|
||||
if mi:
|
||||
iface, name, desc = mi.group(1), mi.group(2), mi.group(3)
|
||||
sig = name + ":" + desc
|
||||
if sig in OBJ and not declares(iface, sig):
|
||||
hits.setdefault((iface, sig), set()).add(cur)
|
||||
for (iface, sig), users in sorted(hits.items()):
|
||||
print(f"{iface}.{sig} <- {len(users)} class(es): " + ", ".join(sorted(users))[:300])
|
||||
print("total patterns:", len(hits))
|
||||
Reference in new issue
Block a user