Release-keys/AVB, CVE clean+hi batches, Yama/slabrand, Pro branding, bundled apps, and AXP-class product surface docs/scripts.
150 lines
5.3 KiB
Python
Executable File
150 lines
5.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Idempotent Magisk preroot hook into releasetools common.py (LOS 23.2 / A16).
|
|
|
|
Gate (either is enough):
|
|
- ``out/.magisk/READY`` present (preferred — survives ninja/soong env scrubbing)
|
|
- ``SUNFISH_A16_MAGISK_PREROOT=1``
|
|
|
|
Matches sfX extendrom inject (always-on once staged), adapted for A16 + our
|
|
vendor path. ``RunAndCheckOutput`` env is merged with ``os.environ`` so PATH /
|
|
ANDROID_BUILD_TOP survive (extendrom only passed ``system_root_image``; that
|
|
works via shebang but is fragile under sandboxes).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import pathlib
|
|
import re
|
|
import sys
|
|
|
|
MARKER = "SUNFISH_A16: Magisk preroot hook"
|
|
MARKER_VER = "SUNFISH_A16: Magisk preroot hook v2"
|
|
|
|
BUILD_HOOK = '''
|
|
# SUNFISH_A16: Magisk preroot hook v2 (before AVB)
|
|
# Gate: staged out/.magisk/READY and/or SUNFISH_A16_MAGISK_PREROOT=1
|
|
_sf_top = os.getenv("ANDROID_BUILD_TOP") or os.environ.get("PWD") or os.getcwd()
|
|
_sf_ready = os.path.isfile(os.path.join(_sf_top, "out", ".magisk", "READY"))
|
|
_sf_env = os.environ.get("SUNFISH_A16_MAGISK_PREROOT") == "1"
|
|
if _sf_ready or _sf_env:
|
|
if ((partition_name == "boot" and info_dict.get("init_boot") != "true")
|
|
or partition_name == "init_boot"):
|
|
mpatcher = [
|
|
os.path.join(_sf_top, "vendor/sunfish-a16/magisk/patch.sh"),
|
|
img.name,
|
|
_sf_top,
|
|
]
|
|
logger.info("SUNFISH_A16 Magisk patching (build): %s", img.name)
|
|
_sf_penv = os.environ.copy()
|
|
_sf_penv["system_root_image"] = info_dict.get("system_root_image", "false")
|
|
_sf_penv.setdefault("ANDROID_BUILD_TOP", _sf_top)
|
|
RunAndCheckOutput(mpatcher, verbose=True, env=_sf_penv)
|
|
'''
|
|
|
|
PREBUILT_HOOK = '''
|
|
# SUNFISH_A16: Magisk preroot hook v2 (prebuilt)
|
|
_sf_top = os.getenv("ANDROID_BUILD_TOP") or os.environ.get("PWD") or os.getcwd()
|
|
_sf_ready = os.path.isfile(os.path.join(_sf_top, "out", ".magisk", "READY"))
|
|
_sf_env = os.environ.get("SUNFISH_A16_MAGISK_PREROOT") == "1"
|
|
if _sf_ready or _sf_env:
|
|
if ((prebuilt_name == "boot.img" or prebuilt_name == "init_boot.img")
|
|
and os.path.exists(prebuilt_path)):
|
|
if info_dict is None:
|
|
info_dict = OPTIONS.info_dict
|
|
bimg = os.path.join(_sf_top, prebuilt_path)
|
|
logger.info("SUNFISH_A16 Magisk patching (prebuilt): %s", bimg)
|
|
mpatcher = [
|
|
os.path.join(_sf_top, "vendor/sunfish-a16/magisk/patch.sh"),
|
|
bimg,
|
|
_sf_top,
|
|
]
|
|
_sf_penv = os.environ.copy()
|
|
_sf_penv["system_root_image"] = info_dict.get("system_root_image", "false")
|
|
_sf_penv.setdefault("ANDROID_BUILD_TOP", _sf_top)
|
|
RunAndCheckOutput(mpatcher, verbose=True, env=_sf_penv)
|
|
'''
|
|
|
|
|
|
def _strip_old_hooks(text: str) -> str:
|
|
"""Remove prior SUNFISH Magisk hook blocks (v1 gated or v2)."""
|
|
# Build hook: from our comment through just before AVB block
|
|
text = re.sub(
|
|
r"\n # SUNFISH_A16: Magisk preroot hook(?: v2)? \(before AVB\).*?"
|
|
r"(?=\n # AVB: if enabled)",
|
|
"\n",
|
|
text,
|
|
count=1,
|
|
flags=re.S,
|
|
)
|
|
# Prebuilt hook: after BOOTABLE_IMAGES assign, before "if os.path.exists(prebuilt_path)"
|
|
text = re.sub(
|
|
r"( prebuilt_path = os\.path\.join\(unpack_dir, \"BOOTABLE_IMAGES\", prebuilt_name\)\n)"
|
|
r"\n # SUNFISH_A16: Magisk preroot hook(?: v2)? \(prebuilt\).*?"
|
|
r"(?=\n if os\.path\.exists\(prebuilt_path\):)",
|
|
r"\1",
|
|
text,
|
|
count=1,
|
|
flags=re.S,
|
|
)
|
|
return text
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--top", default=os.environ.get("ANDROID_BUILD_TOP", ""))
|
|
ap.add_argument("--dry-run", action="store_true")
|
|
ap.add_argument(
|
|
"--force",
|
|
action="store_true",
|
|
help="Replace an existing SUNFISH Magisk hook with v2",
|
|
)
|
|
args = ap.parse_args()
|
|
top = pathlib.Path(args.top or ".")
|
|
target = top / "build/make/tools/releasetools/common.py"
|
|
if not target.is_file():
|
|
print(f"ERROR: missing {target}", file=sys.stderr)
|
|
return 2
|
|
text = target.read_text()
|
|
|
|
if MARKER_VER in text and not args.force:
|
|
print(f"already applied (v2): {target}")
|
|
return 0
|
|
|
|
if MARKER in text or MARKER_VER in text:
|
|
if not args.force and MARKER_VER not in text:
|
|
# old v1 present — upgrade
|
|
pass
|
|
text = _strip_old_hooks(text)
|
|
|
|
needle_avb = (
|
|
' # AVB: if enabled, calculate and add hash to boot.img or recovery.img.\n'
|
|
' if info_dict.get("avb_enable") == "true":\n'
|
|
' avbtool = info_dict["avb_avbtool"]\n'
|
|
' if partition_name == "recovery":'
|
|
)
|
|
idx = text.find(needle_avb)
|
|
if idx < 0:
|
|
print("ERROR: AVB anchor not found", file=sys.stderr)
|
|
return 3
|
|
text = text[:idx] + BUILD_HOOK + "\n" + text[idx:]
|
|
|
|
assign = ' prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name)\n'
|
|
idx2 = text.find(assign)
|
|
if idx2 < 0:
|
|
print("ERROR: prebuilt assign not found", file=sys.stderr)
|
|
return 4
|
|
insert_at = idx2 + len(assign)
|
|
text = text[:insert_at] + PREBUILT_HOOK + "\n" + text[insert_at:]
|
|
|
|
if args.dry_run:
|
|
print("dry-run OK (v2)")
|
|
return 0
|
|
target.write_text(text)
|
|
print(f"applied v2 -> {target}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|