205 lines
5.9 KiB
Python
205 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from stuff.houdini import Houdini
|
|
from stuff.houdini_hack import Houdini_Hack
|
|
from stuff.magisk import Magisk
|
|
from stuff.mindthegapps import MindTheGapps
|
|
import tools.compat as compat
|
|
import tools.helper as helper
|
|
|
|
|
|
SUPPORTED_ANDROID_VERSIONS = ["13.0.0"]
|
|
|
|
|
|
def ensure_base_image(container_runtime, android_version):
|
|
base_image = "redroid/redroid:{}-latest".format(android_version)
|
|
inspect = subprocess.run(
|
|
[container_runtime, "image", "inspect", base_image],
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
check=False,
|
|
)
|
|
local_present = inspect.returncode == 0
|
|
|
|
tar_name = "redroid-redroid-{}-latest.tar".format(android_version)
|
|
tar_path = os.path.join(helper.get_image_dir(), tar_name)
|
|
tar_exists = os.path.isfile(tar_path)
|
|
offline_only = helper.is_offline_only()
|
|
|
|
if local_present:
|
|
helper.print_color(
|
|
"Using existing local base image {} ...".format(base_image),
|
|
helper.bcolors.GREEN,
|
|
)
|
|
return "present"
|
|
|
|
if tar_exists:
|
|
helper.print_color(
|
|
"Loading base image from offline archive {} ...".format(tar_path),
|
|
helper.bcolors.GREEN,
|
|
)
|
|
subprocess.run([container_runtime, "load", "-i", tar_path], check=True)
|
|
return tar_path
|
|
|
|
if offline_only:
|
|
raise FileNotFoundError(
|
|
"REDROID_OFFLINE is set but {} is not in local storage and {} was not found".format(
|
|
base_image,
|
|
tar_path,
|
|
)
|
|
)
|
|
|
|
helper.print_color(
|
|
"No local base image or offline .tar; pulling {} ...".format(base_image),
|
|
helper.bcolors.YELLOW,
|
|
)
|
|
pull = subprocess.run([container_runtime, "pull", base_image], check=False)
|
|
if pull.returncode == 0:
|
|
return "pulled"
|
|
|
|
raise FileNotFoundError(
|
|
"Pull failed for {} and offline archive {} was not found".format(
|
|
base_image,
|
|
tar_path,
|
|
)
|
|
)
|
|
|
|
|
|
def build_layers(args):
|
|
dockerfile = "FROM redroid/redroid:{}-latest\n".format(args.android)
|
|
tags = [args.android]
|
|
|
|
if args.mindthegapps:
|
|
MindTheGapps(args.android).install()
|
|
dockerfile += "COPY mindthegapps /\n"
|
|
tags.append("mindthegapps")
|
|
|
|
if args.houdini:
|
|
arch = helper.host()[0]
|
|
if arch not in {"x86", "x86_64"}:
|
|
raise ValueError("Houdini only makes sense on x86/x86_64 hosts")
|
|
Houdini(args.android).install()
|
|
Houdini_Hack(args.android).install()
|
|
dockerfile += "COPY houdini /\n"
|
|
tags.append("houdini")
|
|
|
|
if args.magisk:
|
|
os.environ.setdefault("REDROID_MAGISK_BOOT_COMPLETE", "1")
|
|
Magisk().install()
|
|
dockerfile += "COPY magisk /\n"
|
|
tags.append("magisk")
|
|
|
|
return dockerfile, tags
|
|
|
|
|
|
def print_recommended_flow(image_name):
|
|
print("\nRecommended 5570 launch (headless: always pass --adb-insecure)")
|
|
print(
|
|
"python run_redroid.py "
|
|
"--image {} "
|
|
"--bridge libhoudini "
|
|
"--device-profile pixel-7-pro "
|
|
"--data-dir ~/data-redroid13 "
|
|
"--port 5570 "
|
|
"--replace "
|
|
"--adb-insecure\n".format(image_name)
|
|
)
|
|
print("Recommended post-boot hardening")
|
|
print(
|
|
"python bootstrap_redroid.py "
|
|
"--serial 127.0.0.1:5570 "
|
|
"--device-profile pixel-7-pro "
|
|
"--proxy-host auto "
|
|
"--install-extreme-script\n"
|
|
)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Build the minimal Android 13 redroid image used for the optimized 5570 setup."
|
|
)
|
|
parser.add_argument(
|
|
"-a",
|
|
"--android-version",
|
|
dest="android",
|
|
default="13.0.0",
|
|
choices=SUPPORTED_ANDROID_VERSIONS,
|
|
help="Android base image to build from",
|
|
)
|
|
parser.add_argument(
|
|
"-mtg",
|
|
"--install-mindthegapps",
|
|
dest="mindthegapps",
|
|
action="store_true",
|
|
help="Install MindTheGapps into the image",
|
|
)
|
|
parser.add_argument(
|
|
"-i",
|
|
"--install-houdini",
|
|
dest="houdini",
|
|
action="store_true",
|
|
help="Install libhoudini and the Android 13 compatibility hack",
|
|
)
|
|
parser.add_argument(
|
|
"-m",
|
|
"--install-magisk",
|
|
dest="magisk",
|
|
action="store_true",
|
|
help="Install Kitsune Mask / Magisk Delta bootless payload",
|
|
)
|
|
parser.add_argument(
|
|
"-c",
|
|
"--container",
|
|
dest="container",
|
|
default="docker",
|
|
choices=["docker", "podman"],
|
|
help="Container runtime",
|
|
)
|
|
parser.add_argument(
|
|
"--offline",
|
|
dest="offline",
|
|
action="store_true",
|
|
help="Do not pull images or download archives; require offline/downloads and offline/images",
|
|
)
|
|
parser.add_argument(
|
|
"--no-compat-check",
|
|
dest="no_compat_check",
|
|
action="store_true",
|
|
help="Skip container-runtime / OS compatibility checks before build",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
if args.offline:
|
|
os.environ["REDROID_OFFLINE"] = "1"
|
|
if not args.no_compat_check:
|
|
build_report = compat.analyze_for_build(args.container)
|
|
compat.emit_compat_report(build_report)
|
|
if build_report.errors:
|
|
sys.exit(1)
|
|
base_image_source = ensure_base_image(args.container, args.android)
|
|
dockerfile, tags = build_layers(args)
|
|
|
|
print("\nDockerfile\n{}".format(dockerfile))
|
|
with open("./Dockerfile", "w", encoding="utf-8") as handle:
|
|
handle.write(dockerfile)
|
|
|
|
image_name = "redroid/redroid:" + "_".join(tags)
|
|
subprocess.run([args.container, "build", "-t", image_name, "."], check=True)
|
|
helper.print_color(
|
|
"Successfully built {}".format(image_name),
|
|
helper.bcolors.GREEN,
|
|
)
|
|
print("Base image source: {}".format(base_image_source))
|
|
|
|
if args.houdini:
|
|
print_recommended_flow(image_name)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|