70 lines
3.4 KiB
Python
70 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Run production APK media workers on a device without replacing the installed app."""
|
|
import argparse
|
|
import os
|
|
from pathlib import Path
|
|
import shlex
|
|
import subprocess
|
|
import tempfile
|
|
import zipfile
|
|
|
|
|
|
def main():
|
|
project = Path(__file__).resolve().parents[2]
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("serial", help="adb serial of the test device")
|
|
parser.add_argument("--sdk", type=Path, default=os.getenv("ANDROID_HOME") or os.getenv("ANDROID_SDK_ROOT"))
|
|
parser.add_argument("--apk", type=Path, default=project / "app/build/outputs/apk/debug/app-debug.apk")
|
|
args = parser.parse_args()
|
|
sdk = args.sdk
|
|
if sdk is None:
|
|
properties = project / "local.properties"
|
|
if properties.exists():
|
|
for line in properties.read_text().splitlines():
|
|
if line.startswith("sdk.dir="):
|
|
sdk = Path(line.split("=", 1)[1])
|
|
if sdk is None or not args.apk.is_file():
|
|
parser.error("Build assembleDebug first and specify --sdk or sdk.dir in local.properties")
|
|
android = sdk / "platforms/android-36/android.jar"
|
|
versions = sorted((sdk / "build-tools").glob("*/d8"), key=lambda p: tuple(int(n) for n in p.parent.name.split(".")))
|
|
if not android.is_file() or not versions:
|
|
parser.error("Android API 36 and build-tools with d8 are required")
|
|
adb = ["adb", "-s", args.serial]
|
|
remote = "/data/local/tmp/utun-stream-worker-smoke"
|
|
|
|
def run(*command):
|
|
subprocess.run([str(part) for part in command], check=True)
|
|
|
|
with tempfile.TemporaryDirectory(prefix="utun-stream-worker-smoke-") as directory:
|
|
work = Path(directory)
|
|
classes = work / "classes"
|
|
classes.mkdir()
|
|
run("javac", "-cp", android, "-d", classes, Path(__file__).with_name("StreamWorkerSmoke.java"))
|
|
jar = work / "smoke.jar"
|
|
run(versions[-1], "--lib", android, "--min-api", "26", "--output", jar, classes / "StreamWorkerSmoke.class")
|
|
frame = work / "key.h264"
|
|
run("ffmpeg", "-nostdin", "-loglevel", "error", "-f", "lavfi", "-i", "color=size=128x72:rate=30:color=blue",
|
|
"-frames:v", "1", "-c:v", "libx264", "-preset", "ultrafast", "-tune", "zerolatency",
|
|
"-x264-params", "repeat-headers=1", "-f", "h264", frame)
|
|
abi = subprocess.check_output(adb + ["shell", "getprop", "ro.product.cpu.abi"], text=True).strip()
|
|
libraries = []
|
|
with zipfile.ZipFile(args.apk) as apk:
|
|
for name in apk.namelist():
|
|
if name.startswith(f"lib/{abi}/") and name.endswith(".so"):
|
|
target = work / Path(name).name
|
|
target.write_bytes(apk.read(name))
|
|
libraries.append(target)
|
|
if not libraries:
|
|
parser.error(f"APK has no native libraries for {abi}")
|
|
run(*adb, "shell", "mkdir", "-p", remote)
|
|
run(*adb, "push", jar, frame, *libraries, remote + "/")
|
|
run(*adb, "push", args.apk, remote + "/app.apk")
|
|
command = [f"CLASSPATH={remote}/smoke.jar:{remote}/app.apk", "app_process",
|
|
f"-Djava.library.path={remote}", remote, "StreamWorkerSmoke", remote + "/key.h264"]
|
|
print("Testing real MediaCodec/Opus/AudioTrack: 500ms video stall, EOF and reset; audio content is silence", flush=True)
|
|
run(*adb, "shell", " ".join(shlex.quote(part) for part in command))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|