s''
This commit is contained in:
324
run_redroid.py
Normal file
324
run_redroid.py
Normal file
@@ -0,0 +1,324 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
from tools.helper import bcolors, print_color
|
||||
|
||||
|
||||
COMMON_BRIDGE_PROPS = [
|
||||
"ro.product.cpu.abilist=x86_64,arm64-v8a,x86,armeabi-v7a,armeabi",
|
||||
"ro.product.cpu.abilist64=x86_64,arm64-v8a",
|
||||
"ro.product.cpu.abilist32=x86,armeabi-v7a,armeabi",
|
||||
"ro.dalvik.vm.isa.arm=x86",
|
||||
"ro.dalvik.vm.isa.arm64=x86_64",
|
||||
"ro.enable.native.bridge.exec=1",
|
||||
"ro.enable.native.bridge.exec64=1",
|
||||
"ro.vendor.enable.native.bridge.exec=1",
|
||||
"ro.vendor.enable.native.bridge.exec64=1",
|
||||
]
|
||||
|
||||
DEVICE_PROFILES = {
|
||||
"pixel-3-xl": [
|
||||
"ro.product.model=Pixel 3 XL",
|
||||
"ro.product.brand=google",
|
||||
"ro.product.name=crosshatch",
|
||||
"ro.product.device=crosshatch",
|
||||
"ro.product.manufacturer=Google",
|
||||
"ro.product.system.model=Pixel 3 XL",
|
||||
"ro.product.system.brand=google",
|
||||
"ro.product.system.name=crosshatch",
|
||||
"ro.product.system.device=crosshatch",
|
||||
"ro.product.system.manufacturer=Google",
|
||||
"ro.product.vendor.model=Pixel 3 XL",
|
||||
"ro.product.vendor.brand=google",
|
||||
"ro.product.vendor.name=crosshatch",
|
||||
"ro.product.vendor.device=crosshatch",
|
||||
"ro.product.vendor.manufacturer=Google",
|
||||
"ro.product.product.model=Pixel 3 XL",
|
||||
"ro.product.product.brand=google",
|
||||
"ro.product.product.name=crosshatch",
|
||||
"ro.product.product.device=crosshatch",
|
||||
"ro.product.product.manufacturer=Google",
|
||||
"ro.build.fingerprint=google/crosshatch/crosshatch:11/RQ3A.211001.001/7641976:user/release-keys",
|
||||
"ro.system.build.fingerprint=google/crosshatch/crosshatch:11/RQ3A.211001.001/7641976:user/release-keys",
|
||||
"ro.vendor.build.fingerprint=google/crosshatch/crosshatch:11/RQ3A.211001.001/7641976:user/release-keys",
|
||||
"ro.product.build.fingerprint=google/crosshatch/crosshatch:11/RQ3A.211001.001/7641976:user/release-keys",
|
||||
"ro.build.type=user",
|
||||
"ro.build.tags=release-keys",
|
||||
"ro.secure=1",
|
||||
"ro.debuggable=0",
|
||||
"ro.boot.verifiedbootstate=green",
|
||||
"ro.boot.vbmeta.device_state=locked",
|
||||
"ro.boot.flash.locked=1",
|
||||
"ro.boot.veritymode=enforcing",
|
||||
],
|
||||
"pixel-7-pro": [
|
||||
"ro.product.model=Pixel 7 Pro",
|
||||
"ro.product.brand=google",
|
||||
"ro.product.name=cheetah",
|
||||
"ro.product.device=cheetah",
|
||||
"ro.product.manufacturer=Google",
|
||||
"ro.product.system.model=Pixel 7 Pro",
|
||||
"ro.product.system.brand=google",
|
||||
"ro.product.system.name=cheetah",
|
||||
"ro.product.system.device=cheetah",
|
||||
"ro.product.system.manufacturer=Google",
|
||||
"ro.product.vendor.model=Pixel 7 Pro",
|
||||
"ro.product.vendor.brand=google",
|
||||
"ro.product.vendor.name=cheetah",
|
||||
"ro.product.vendor.device=cheetah",
|
||||
"ro.product.vendor.manufacturer=Google",
|
||||
"ro.product.product.model=Pixel 7 Pro",
|
||||
"ro.product.product.brand=google",
|
||||
"ro.product.product.name=cheetah",
|
||||
"ro.product.product.device=cheetah",
|
||||
"ro.product.product.manufacturer=Google",
|
||||
"ro.build.fingerprint=google/cheetah/cheetah:13/TQ3A.230805.001/2023080800:user/release-keys",
|
||||
"ro.system.build.fingerprint=google/cheetah/cheetah:13/TQ3A.230805.001/2023080800:user/release-keys",
|
||||
"ro.vendor.build.fingerprint=google/cheetah/cheetah:13/TQ3A.230805.001/2023080800:user/release-keys",
|
||||
"ro.product.build.fingerprint=google/cheetah/cheetah:13/TQ3A.230805.001/2023080800:user/release-keys",
|
||||
"ro.build.type=user",
|
||||
"ro.build.tags=release-keys",
|
||||
"ro.secure=1",
|
||||
"ro.debuggable=0",
|
||||
"ro.boot.verifiedbootstate=green",
|
||||
"ro.boot.vbmeta.device_state=locked",
|
||||
"ro.boot.flash.locked=1",
|
||||
"ro.boot.veritymode=enforcing",
|
||||
]
|
||||
}
|
||||
|
||||
LAUNCH_PRESETS = {
|
||||
"redroid-pro": {
|
||||
"props": [
|
||||
"androidboot.redroid_width=720",
|
||||
"androidboot.redroid_height=1280",
|
||||
"androidboot.redroid_dpi=320",
|
||||
"androidboot.redroid_fps=30",
|
||||
"androidboot.redroid_vm_heap=256m",
|
||||
"ro.config.low_ram=true",
|
||||
"config.disable_consumerir=true",
|
||||
],
|
||||
"device_profile": "pixel-3-xl",
|
||||
"memory": "4g",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def infer_bridge(image, requested):
|
||||
if requested != "auto":
|
||||
return requested
|
||||
if "houdini" in image:
|
||||
return "libhoudini"
|
||||
if "ndk" in image:
|
||||
return "libndk"
|
||||
return "none"
|
||||
|
||||
|
||||
def bridge_props(mode):
|
||||
if mode == "none":
|
||||
return []
|
||||
props = list(COMMON_BRIDGE_PROPS)
|
||||
if mode == "libhoudini":
|
||||
props.append("ro.dalvik.vm.native.bridge=libhoudini.so")
|
||||
elif mode == "libnb":
|
||||
props.append("ro.dalvik.vm.native.bridge=libnb.so")
|
||||
elif mode == "libndk":
|
||||
props.append("ro.dalvik.vm.native.bridge=libndk_translation.so")
|
||||
props.append("ro.ndk_translation.version=0.2.3")
|
||||
else:
|
||||
raise ValueError("Unsupported bridge mode: {}".format(mode))
|
||||
return props
|
||||
|
||||
|
||||
def device_profile_props(profile):
|
||||
if profile == "none":
|
||||
return []
|
||||
try:
|
||||
return list(DEVICE_PROFILES[profile])
|
||||
except KeyError as exc:
|
||||
raise ValueError("Unsupported device profile: {}".format(profile)) from exc
|
||||
|
||||
|
||||
def preset_props(preset):
|
||||
if preset == "none":
|
||||
return []
|
||||
try:
|
||||
return list(LAUNCH_PRESETS[preset]["props"])
|
||||
except KeyError as exc:
|
||||
raise ValueError("Unsupported preset: {}".format(preset)) from exc
|
||||
|
||||
|
||||
def resolve_device_profile(preset, requested):
|
||||
if requested != "none":
|
||||
return requested
|
||||
if preset == "none":
|
||||
return "none"
|
||||
return LAUNCH_PRESETS[preset].get("device_profile", "none")
|
||||
|
||||
|
||||
def resolve_memory(preset, requested):
|
||||
if requested:
|
||||
return requested
|
||||
if preset == "none":
|
||||
return None
|
||||
return LAUNCH_PRESETS[preset].get("memory")
|
||||
|
||||
|
||||
def default_name(image):
|
||||
name = image.split("/")[-1].replace(":", "_")
|
||||
name = re.sub(r"[^a-zA-Z0-9_.-]+", "-", name).strip("-")
|
||||
return name or "redroid"
|
||||
|
||||
|
||||
def quote_cmd(args):
|
||||
return " ".join(shlex.quote(part) for part in args)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Launch a redroid container with a tested native bridge configuration."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--image",
|
||||
required=True,
|
||||
help="Image name, for example redroid/redroid:13.0.0_mindthegapps_houdini_magisk",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--container",
|
||||
default="docker",
|
||||
choices=["docker", "podman"],
|
||||
help="Container runtime",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--name",
|
||||
help="Container name. Defaults to a slug derived from the image tag.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--data-dir",
|
||||
default="~/data-redroid",
|
||||
help="Host directory mapped to /data",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=5555,
|
||||
help="Host TCP port mapped to guest ADB 5555",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--bridge",
|
||||
choices=["auto", "none", "libhoudini", "libnb", "libndk"],
|
||||
default="auto",
|
||||
help="Native bridge runtime property to inject",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--preset",
|
||||
choices=["none"] + sorted(LAUNCH_PRESETS.keys()),
|
||||
default="none",
|
||||
help="Inject a tested launch preset",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--gpu-mode",
|
||||
default="guest",
|
||||
help="Value for androidboot.redroid_gpu_mode",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--device-profile",
|
||||
choices=["none"] + sorted(DEVICE_PROFILES.keys()),
|
||||
default="none",
|
||||
help="Inject a tested device identity profile",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--memory",
|
||||
help="Optional container memory limit, for example 4g",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--replace",
|
||||
action="store_true",
|
||||
help="Remove an existing container with the same name before running",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--keep-container",
|
||||
action="store_true",
|
||||
help="Do not pass --rm to the runtime",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Print the generated command without executing it",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--extra-prop",
|
||||
action="append",
|
||||
default=[],
|
||||
help="Additional redroid property, repeatable",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
image = args.image
|
||||
name = args.name or default_name(image)
|
||||
data_dir = os.path.abspath(os.path.expanduser(args.data_dir))
|
||||
bridge = infer_bridge(image, args.bridge)
|
||||
preset = args.preset
|
||||
device_profile = resolve_device_profile(preset, args.device_profile)
|
||||
memory = resolve_memory(preset, args.memory)
|
||||
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
cmd = [
|
||||
args.container,
|
||||
"run",
|
||||
"-d",
|
||||
"--privileged",
|
||||
"--name",
|
||||
name,
|
||||
"-v",
|
||||
"{}:/data".format(data_dir),
|
||||
"-p",
|
||||
"{}:5555".format(args.port),
|
||||
]
|
||||
if memory:
|
||||
cmd.extend(["--memory", memory])
|
||||
if not args.keep_container:
|
||||
cmd.append("--rm")
|
||||
cmd.extend(
|
||||
[
|
||||
image,
|
||||
"androidboot.redroid_gpu_mode={}".format(args.gpu_mode),
|
||||
]
|
||||
)
|
||||
cmd.extend(bridge_props(bridge))
|
||||
cmd.extend(preset_props(preset))
|
||||
cmd.extend(device_profile_props(device_profile))
|
||||
cmd.extend(args.extra_prop)
|
||||
|
||||
if args.replace and not args.dry_run:
|
||||
subprocess.run(
|
||||
[args.container, "rm", "-f", name],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=False,
|
||||
)
|
||||
|
||||
print_color("Selected native bridge: {}".format(bridge), bcolors.GREEN)
|
||||
if preset != "none":
|
||||
print_color("Selected launch preset: {}".format(preset), bcolors.GREEN)
|
||||
if device_profile != "none":
|
||||
print_color("Selected device profile: {}".format(device_profile), bcolors.GREEN)
|
||||
print("Command:\n{}\n".format(quote_cmd(cmd)))
|
||||
|
||||
if args.dry_run:
|
||||
return
|
||||
|
||||
subprocess.run(cmd, check=True)
|
||||
print_color("Container started as {}".format(name), bcolors.GREEN)
|
||||
print("ADB: adb connect 127.0.0.1:{}".format(args.port))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user