009: Polish bacon fixes, OTA host scripts, and migration docs.

Restore disable_configstore, EuiccDisabler and thermal CDEV guards, branding
and rebuild/sync helpers; document device roles, laptop migration, and Gitea.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
sunfish-adminandCursor committed 2026-10-16 21:06:45 +02:00
1 parent 3f941e8451
commit 2d145c2878
3193 files changed
+21264 -371

No files matched your search

@@ -49,7 +49,10 @@ export PRODUCT_DEFAULT_DEV_CERTIFICATE="$CERT_DIR/releasekey"
echo "OK: PRODUCT_DEFAULT_DEV_CERTIFICATE=$PRODUCT_DEFAULT_DEV_CERTIFICATE"
LIVE=kernel/google/msm-4.14
BASE=28f9290ae067
# Use the kernel revision selected by the pinned LOS manifest. Repeated bacons
# are safe because all project patches are uncommitted and HEAD stays at the
# upstream commit. AXP_KERNEL_BASE is only for an explicit historical bisect.
BASE=${AXP_KERNEL_BASE:-$(git -C "$LIVE" rev-parse HEAD)}
KH=vendor/sunfish-a16/patches/009-kernel-hardening
LIST_CLEAN="$KH/cve-clean-offset.list"
LIST_HI1="$KH/cve-high-offset-batch1.list"
@@ -61,6 +64,29 @@ test -f "$LIST_HI2"
test -f "$LIST_HI3"
test -d "$LIVE"
# Re-run ship gates + artifact publish from existing out/ (after a post-mka FAIL).
if [[ "${AXP_POSTFLIGHT_ONLY:-0}" == 1 ]]; then
echo "=== AXP_POSTFLIGHT_ONLY: ship gates + artifacts only $(date -Is) ==="
AXP_DEBLOB_WAVE4="${AXP_DEBLOB_WAVE4:-1}"
PROD=out/target/product/sunfish
shopt -s nullglob
_ota_zip=( "$PROD"/lineage-*-PRO-sunfish.zip )
shopt -u nullglob
if [[ ${#_ota_zip[@]} -lt 1 ]]; then
echo "FAIL: missing $PROD/lineage-*-PRO-sunfish.zip (run full bacon first)" >&2
exit 1
fi
_self="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
_start=$(grep -n '^# Post-ship gates:' "$_self" | head -1 | cut -d: -f1)
[[ -n "$_start" ]] || { echo "FAIL: postflight marker missing in $_self" >&2; exit 1; }
_pf=$(mktemp /tmp/axp-postflight-XXXX.sh)
sed -n "${_start},\$p" "$_self" > "$_pf"
bash "$_pf"
ec_pf=$?
rm -f "$_pf"
exit "$ec_pf"
fi
echo "=== reset kernel @ $BASE ==="
git -C "$LIVE" reset --hard "$BASE"
git -C "$LIVE" clean -fdq
@@ -86,7 +112,7 @@ do
echo "applied $(basename "$PORT")"
done
# US-S5-1 — Yama + SLAB_FREELIST_RANDOM (Graphene/AXP defconfig gaps)
# US-S5-1 — SLAB_FREELIST_RANDOM; keep Yama unset like GOLDEN/AXP.
chmod +x "$KH/apply_uss5_1_defconfig.sh" 2>/dev/null || true
bash "$KH/apply_uss5_1_defconfig.sh" "$LIVE"
@@ -118,9 +144,11 @@ if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
fi
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED \
SECURITY_YAMA SLAB_FREELIST_RANDOM; do
SLAB_FREELIST_RANDOM; do
grep -q "^CONFIG_${k}=y" "$DEF" || { echo "FAIL missing $k" >&2; exit 1; }
done
grep -q '^# CONFIG_SECURITY_YAMA is not set$' "$DEF" \
|| { echo "FAIL: SECURITY_YAMA still enabled (GOLDEN leaves it unset)" >&2; exit 1; }
grep -q '^# CONFIG_USERFAULTFD is not set$' "$DEF" \
|| { echo "FAIL: USERFAULTFD still enabled (GOLDEN leaves it unset)" >&2; exit 1; }
if grep -q '^CONFIG_USERFAULTFD=y$' "$DEF"; then
@@ -147,7 +175,15 @@ python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_app
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_supl_privacy.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_product_includes.py
grep -q 'sunfish-a16-009-product-includes' device/google/sunfish/lineage_sunfish.mk
grep -q 'sunfish-a16-009-board-config' device/google/sunfish/BoardConfigLineage.mk
export ANDROID_CERTS_DIR="${ANDROID_CERTS_DIR:-/srv/rom/secrets/android-certs}"
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_axp_identity.py
test -f vendor/sunfish-a16/certs/avb.pem
test -f vendor/sunfish-a16/certs/avb_pkmd.bin
test -f vendor/lineage-priv/keys/releasekey.pk8
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_axp_branding.py
grep -q '^VENDOR_SECURITY_PATCH = 2023-09-05$' device/google/sunfish/device-common.mk
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_yama_ptrace.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_cmdline_mode.py
@@ -181,16 +217,18 @@ if grep -q 'sdk_version: "37"' prebuilts/openeuicc-deps/Android.bp; then
fi
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_openssh_packages.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_euicc_google.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_euicc_disabler_guard.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_thermal_cdev_log.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_carrier_google.py
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_lineage_tools.py
# Wave 4 (diag/bpftool/imsrcsd): only when AXP_DEBLOB_WAVE4=1 (see 009-bacon-wave4-deblob.sh).
# Wave 4 (diag/bpftool/imsrcsd) is mandatory for OTAs.
# scripts/009-rebuild-from-los.sh and 009-bacon-hardened-malloc.sh set
# AXP_DEBLOB_WAVE4=1. Default 0 only for a debug bacon that is not an OTA.
AXP_DEBLOB_WAVE4="${AXP_DEBLOB_WAVE4:-0}"
if [[ "$AXP_DEBLOB_WAVE4" == 1 ]]; then
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_lab_only_commands.py
fi
# Jelly stays (owner 2026-10-07). Gallery is FossifyGallery. Do not re-add
# Gallery2. The product gate requires Jelly.apk and FossifyGallery, and
# fails if Gallery2.apk is present.
# Jelly stays (owner ship gate). Gallery: LOS Gallery2 and/or Fossify — not gated.
# Host prebuilts → vendor/sunfish-a16/prebuilt (rsync --delete must not wipe these).
mkdir -p vendor/sunfish-a16/prebuilt
@@ -206,6 +244,15 @@ link_prebuilt GsfProxy.apk /srv/rom/prebuilts/microg/GsfProxy.apk
link_prebuilt AuroraStore.apk /srv/rom/prebuilts/axp-apps/AuroraStore.apk
link_prebuilt Droidify.apk /srv/rom/prebuilts/axp-apps/Droidify.apk
link_prebuilt FossifyGallery.apk /srv/rom/prebuilts/axp-apps/FossifyGallery.apk
# GmsCore JNI is deflated with extractNativeLibs=true. Without these files in
# /system_ext/app/GmsCore/lib/arm64, Conscrypt/Cronet fail and Google Maps stays brown.
GMS_JNI=vendor/sunfish-a16/prebuilt/GmsCore-jni/arm64
rm -rf "$GMS_JNI"
mkdir -p "$GMS_JNI"
unzip -q -j -o vendor/sunfish-a16/prebuilt/GmsCore.apk 'lib/arm64-v8a/*.so' -d "$GMS_JNI"
test -s "$GMS_JNI/libconscrypt_gmscore_jni.so" || {
echo "FAIL: GmsCore arm64 JNI not extracted into $GMS_JNI" >&2; exit 1; }
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
"$AAPT" dump permissions vendor/sunfish-a16/prebuilt/Phonesky.apk 2>/dev/null | grep -q USE_EXACT_ALARM
@@ -263,6 +310,21 @@ case "$AVB_KEY" in
esac
[[ "$AVB_ALG" == "SHA256_RSA4096" ]] || { echo "FAIL: AVB alg=$AVB_ALG" >&2; exit 1; }
PRODUCT_PKGS=$(get_build_var PRODUCT_PACKAGES)
for _gms in GmsCore GsfProxy Phonesky; do
case " $PRODUCT_PKGS " in
*" $_gms "*) ;;
*) echo "FAIL: PRODUCT_PACKAGES missing $_gms (gms.mk not inherited?)" >&2; exit 1 ;;
esac
done
for _app in AuroraStore Droidify FossifyGallery OpenEUICC; do
case " $PRODUCT_PKGS " in
*" $_app "*) ;;
*) echo "FAIL: PRODUCT_PACKAGES missing $_app (apps.mk not inherited?)" >&2; exit 1 ;;
esac
done
echo "OK: bundled apps in PRODUCT_PACKAGES (AuroraStore Droidify FossifyGallery OpenEUICC)"
echo "=== mka bacon $(date -Is) signing=$PRODUCT_DEFAULT_DEV_CERTIFICATE ==="
set -o pipefail
mka bacon -j8
@@ -489,18 +551,42 @@ if ! debugfs -R "stat /bin/vim" "$SYSEXT_RAW" 2>&1 | grep -q 'Inode:'; then
echo "FAIL: expected system_ext/bin/vim present" >&2
exit 1
fi
if ! debugfs -R "stat /app/GmsCore/lib/arm64/libconscrypt_gmscore_jni.so" "$SYSEXT_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW" "$SYS_RAW" "$SYSEXT_RAW"
echo "FAIL: expected system_ext/app/GmsCore/lib/arm64 JNI (GOLDEN layout)" >&2
exit 1
fi
rm -f "$SYS_RAW" "$SYSEXT_RAW"
echo "lineage tools surface OK (no bash/htop/nano/unrar/addon.d; curl+vim kept)"
if [[ "$AXP_DEBLOB_WAVE4" == 1 ]]; then
VENDOR_RAW=$(mktemp /tmp/axp-vendor-XXXX.img)
"$SIMG" "$DEST/vendor.img" "$VENDOR_RAW"
for p in /bin/cnss_diag /bin/diag_klog /bin/diag_mdlog /bin/diag_socket_log /bin/diag_uart_log /bin/ssr_diag /bin/test_diag /bin/imsrcsd /bin/disable_configstore /etc/init/imsrcsd.rc; do
# target_files can ship vendor.img as raw ext4; simg2img rejects non-sparse input.
if [[ "$(od -An -tx4 -N4 "$DEST/vendor.img" | tr -d ' ')" == ed26ff3a ]]; then
"$SIMG" "$DEST/vendor.img" "$VENDOR_RAW"
else
cp "$DEST/vendor.img" "$VENDOR_RAW"
fi
for p in /bin/cnss_diag /bin/diag_klog /bin/diag_mdlog /bin/diag_socket_log /bin/diag_uart_log /bin/ssr_diag /bin/test_diag /bin/imsrcsd /etc/init/imsrcsd.rc; do
if debugfs -R "stat $p" "$VENDOR_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW" "$VENDOR_RAW"
echo "FAIL: expected vendor$p absent" >&2
exit 1
fi
done
# disable_configstore must override HIDL configstore HAL (A16 VINTF has no
# ISurfaceFlingerConfigs). Expect stub present; real HAL + init rc absent.
for p in /bin/hw/android.hardware.configstore@1.1-service /etc/init/android.hardware.configstore@1.1-service.rc; do
if debugfs -R "stat $p" "$VENDOR_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW" "$VENDOR_RAW"
echo "FAIL: expected vendor$p absent (use disable_configstore override)" >&2
exit 1
fi
done
if ! debugfs -R "stat /bin/disable_configstore" "$VENDOR_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW" "$VENDOR_RAW"
echo "FAIL: expected vendor/bin/disable_configstore present (HAL override)" >&2
exit 1
fi
for p in /bin/loc_launcher /bin/lowi-server /bin/xtra-daemon; do
if ! debugfs -R "stat $p" "$VENDOR_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW" "$VENDOR_RAW"
@@ -509,39 +595,41 @@ if [[ "$AXP_DEBLOB_WAVE4" == 1 ]]; then
fi
done
rm -f "$VENDOR_RAW"
echo "lab-only commands surface OK (diag/imsrcsd/debug tools gone; GPS daemons kept)"
echo "lab-only commands surface OK (diag/imsrcsd gone; configstore HAL overridden; GPS kept)"
fi
# US-S4-2 — Jelly stays. FossifyGallery stays; Gallery2 does not.
# Stale JNI symlink dirs under product/app/Gallery2/lib can remain from
# older out/ — gate Gallery2 on the APK.
# US-S4-2 — ship gate: Jelly browser on product (owner requirement). Gallery app
# (LOS Gallery2 vs Fossify) is not gated; either is fine.
if ! debugfs -R "stat /app/Jelly/Jelly.apk" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW"
echo "FAIL: US-S4-2 expected Jelly.apk on product.img" >&2
exit 1
fi
if debugfs -R "stat /app/Gallery2/Gallery2.apk" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW"
echo "FAIL: US-S4-2 expected Gallery2.apk absent on product.img" >&2
exit 1
fi
if debugfs -R "stat /app/Gallery2" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
echo "WARN: US-S4-2 /app/Gallery2 dir still present (likely stale jni symlinks; no APK)"
fi
if ! debugfs -R "stat /app/FossifyGallery" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW"
echo "FAIL: US-S4-2 expected FossifyGallery present" >&2
exit 1
fi
rm -f "$PROD_RAW"
echo "US-S4-2 product surface OK (Jelly + FossifyGallery; no Gallery2 APK)"
for _bundled in AuroraStore Droidify FossifyGallery; do
if debugfs -R "stat /app/${_bundled}/${_bundled}.apk" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW"
echo "FAIL: US-S4-3 AXP parity: ${_bundled} must not be on product.img" >&2
exit 1
fi
done
SYSEXT_RAW=$(mktemp /tmp/axp-systemext-XXXX.img)
"$SIMG" "$DEST/system_ext.img" "$SYSEXT_RAW"
for _bundled in AuroraStore Droidify FossifyGallery; do
if ! debugfs -R "stat /app/${_bundled}/${_bundled}.apk" "$SYSEXT_RAW" 2>&1 | grep -q 'Inode:'; then
rm -f "$PROD_RAW" "$SYSEXT_RAW"
echo "FAIL: US-S4-3 expected system_ext/app/${_bundled}/${_bundled}.apk" >&2
exit 1
fi
done
rm -f "$PROD_RAW" "$SYSEXT_RAW"
echo "US-S4-2/3 surface OK (Jelly product + Aurora/Droidify/FossifyGallery system_ext)"
{
echo "artifact=$DEST"
echo "list_clean=$LIST_CLEAN (429)"
echo "list_hi=batch1+2+3"
echo "kernel_stage1=30 (misc/0021 omitted; base KSYM_NAME_LEN=192 retained)"
echo "hardening=Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2+3 + US-S4-1-no-openssh + US-S4-2-jelly-fossify + US-S5-1-yama-slabrand + CVE-2022-49980-lock-scope"
echo "hardening=Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2+3 + US-S4-1-no-openssh + US-S4-2-jelly + US-S5-1-slabrand-no-yama + CVE-2022-49980-lock-scope"
echo "vendor_security_patch=2023-09-05"
echo "branding=AXP-Resurection-Pro"
echo "signing=$PRODUCT_DEFAULT_DEV_CERTIFICATE"
+8 -4
View File
@@ -1,8 +1,11 @@
#!/bin/bash
# 012 bacon: current ship pack plus Graphene hardened_malloc.
# Compiles libc first. The full bacon runs only if that link succeeds.
# Does not change AVB flags or run the userspace deblob.
# Final ship candidate: closure pack + wave 4 deblob + hardened_malloc (2 GiB regions).
# Compiles libc first; full bacon runs only if that link succeeds.
# AVB flags 0 (Magisk track). Queue after any in-flight ninja on the same out/.
set -e
export AXP_AVB_FLAGS=0
export WITH_AVB=true
export AXP_DEBLOB_WAVE4=1
cd /srv/rom/src/lineage
export HOME=/home/android-build
export CCACHE_DIR=/srv/rom/ccache
@@ -26,4 +29,5 @@ breakfast sunfish user
echo "=== m libc $(date -Is) ==="
m libc -j8
echo "=== libc ok, starting bacon $(date -Is) ==="
exec /srv/rom/artifacts/bin/009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh
# Same tree as this file (do not depend on a stale copy under artifacts/bin).
exec bash "$(cd "$(dirname "$0")" && pwd)/009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh"
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Read-only Yuh / banking surface diff: GOLDEN oracle vs LAB.
# Requires: adb, both devices authorized, root shell (Magisk su).
set -euo pipefail
GOLDEN=11071JEC203839
LAB=11231JEC207477
PKG=com.yuh
USER_ISLAND=10
section() { echo; echo "======== $1 ========"; }
dump_device() {
local tag=$1 serial=$2
section "$tag ($serial)"
adb -s "$serial" shell true >/dev/null 2>&1 || {
echo "adb not ready for $serial"
return 1
}
adb -s "$serial" shell "su -c '
echo --- build ---
getprop ro.build.display.id
getprop ro.build.version.release
getprop ro.build.version.sdk
echo --- magisk ---
magisk -v 2>/dev/null || true
magisk --sqlite \"SELECT key,value FROM settings\" 2>/dev/null | sort
echo --- modules (no disable) ---
for d in /data/adb/modules/*; do
[ -d \"\$d\" ] || continue
name=\$(basename \"\$d\")
[ -f \"\$d/disable\" ] && state=DISABLED || state=active
id=
[ -f \"\$d/module.prop\" ] && id=\$(grep -E ^id= \"\$d/module.prop\" | cut -d= -f2)
echo \"\$state \$name id=\$id\"
done
echo --- tricky_store targets ---
if [ -f /data/adb/tricky_store/target.txt ]; then
cat /data/adb/tricky_store/target.txt
else
echo missing target.txt
fi
echo --- denylist (yuh / swissquote) ---
magisk --denylist ls 2>/dev/null | grep -E \"yuh|swissquote\" || true
echo --- boot props (app-visible) ---
getprop ro.boot.verifiedbootstate
getprop ro.boot.flash.locked
getprop ro.boot.vbmeta.device_state
getprop ro.boot.veritymode
getprop sys.oem_unlock_allowed
echo --- cmdline mode ---
ls -l /proc/cmdline
echo --- yuh packages ---
pm list packages --user 0 \"$PKG\" 2>/dev/null || true
pm list packages --user $USER_ISLAND \"$PKG\" 2>/dev/null || true
dumpsys package \"$PKG\" 2>/dev/null | grep -E \"versionName|versionCode|firstInstallTime|installerPackage\" | head -20
echo --- island ---
pm list packages --user $USER_ISLAND com.oasisfeng.island.fdroid 2>/dev/null | head -1
dumpsys package com.oasisfeng.island.fdroid 2>/dev/null | grep versionName | head -1
echo --- vector props log (tail) ---
if [ -f /data/adb/lspd/log/props.txt ]; then
tail -30 /data/adb/lspd/log/props.txt
else
echo no props.txt
fi
'" 2>&1 | sed 's/\r$//'
}
dump_device GOLDEN "$GOLDEN" || true
dump_device LAB "$LAB" || true
section "Next: Yuh open in Island user $USER_ISLAND on LAB only"
echo " adb -s $LAB logcat -c"
echo " # open Yuh in Island, reproduce fail"
echo " adb -s $LAB logcat -d | grep -iE 'yuh|talsec|keystore2|KeyMint|integrity|DroidGuard|vectord|teesim' | tail -80"
+158
View File
@@ -0,0 +1,158 @@
#!/bin/bash
# Rebuild AXP Resurection from a LineageOS 23.2 sunfish tree on rom-dev01.
#
# This is the OTA entry point. It always ships:
# - Magisk 30.7 preroot + release-keys (009 bacon)
# - wave 4 deblob (AXP_DEBLOB_WAVE4=1)
# - hardened_malloc 2 GiB (012), after a libc link check
# - AVB flags 0 (WITH_AVB=true)
#
# It does not download the signed nightly zip. The source is the repo tree
# at LINEAGE_TREE (default /srv/rom/src/lineage), branch lineage-23.2.
#
# Usage (host only, detached):
# LOS_SYNC=1 /srv/rom/artifacts/bin/rom-detach bacon009ota -- \
# bash /path/to/AXP_Resurection/scripts/009-rebuild-from-los.sh
#
# LOS_SYNC=1
# Clean project worktrees, repo sync -c -j8 --force-sync, then check out every project
# revision from LOS_MANIFEST. LOS_MANIFEST is mandatory in this mode.
# LOS_MANIFEST=/path/to/build-manifest.xml
# Exact official nightly build-manifest.xml. After pinning, write repo
# manifest -r and fail if any common project revision differs.
# LOS_DATE=YYYYMMDD
# Nightly date used as LINEAGE_BUILD_DATE, so the zip is named
# AXP-Resurection-Pro-23.2-<LOS_DATE>-sunfish.zip.
#
# Current tree (2026-10-10) was synced 2026-09-13 (vanilla bacon 2026-09-14),
# kernel reset each bacon to 28f9290ae067. That is NOT
# lineage-23.2-20261008-nightly-sunfish. Set LOS_SYNC=1 to move the tree
# forward, then compare manifests before trusting the zip.
set -euo pipefail
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
TREE=${LINEAGE_TREE:-/srv/rom/src/lineage}
ART=/srv/rom/artifacts/009-axp-los23-port
PROJECT_SOURCE=${AXP_PROJECT_SOURCE:-}
if [[ ! -d "$TREE/.repo" ]]; then
echo "FAIL: $TREE is not a repo checkout" >&2
exit 1
fi
cd "$TREE"
# rom-dev01: if bacon is started as root, git refuses android-build-owned trees.
export HOME="${HOME:-/home/android-build}"
mkdir -p "$ART"
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
if [[ "${LOS_SYNC:-0}" == 1 ]]; then
if [[ -z "${LOS_MANIFEST:-}" || ! -f "$LOS_MANIFEST" ]]; then
echo "FAIL: LOS_SYNC=1 requires an existing LOS_MANIFEST" >&2
exit 1
fi
echo "=== clean existing project worktrees $(date -Is) ==="
repo forall -c 'git reset --hard -q HEAD; git clean -fdq'
echo "=== repo sync -c -j8 --force-sync $(date -Is) ==="
# force-sync is needed when upstream changed a project's object-store
# association. Project worktrees were reset above; our patch source is
# staged outside the repo tree.
repo sync -c -j8 --force-sync
echo "=== pin projects to $(basename "$LOS_MANIFEST") $(date -Is) ==="
python3 - "$LOS_MANIFEST" <<'PY'
import pathlib
import subprocess
import sys
import xml.etree.ElementTree as ET
root = ET.parse(sys.argv[1]).getroot()
missing = []
count = 0
for el in root.iter("project"):
path = pathlib.Path(el.get("path") or el.get("name") or "")
rev = el.get("revision")
if not path or not rev:
continue
if not (path / ".git").exists():
missing.append(str(path))
continue
probe = subprocess.run(
["git", "-C", str(path), "cat-file", "-e", f"{rev}^{{commit}}"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
if probe.returncode:
sys.exit(f"FAIL: nightly revision unavailable in {path}: {rev}")
subprocess.run(
["git", "-C", str(path), "checkout", "--detach", "-q", rev],
check=True,
)
subprocess.run(["git", "-C", str(path), "clean", "-fdq"], check=True)
count += 1
print(f"OK: pinned {count} projects; {len(missing)} nightly-only paths absent locally")
for path in missing[:20]:
print(f"MISSING_LOCAL {path}")
if len(missing) > 20:
print(f"... {len(missing) - 20} more missing paths")
PY
fi
MANIFEST_OUT="$ART/manifest-${STAMP}.xml"
repo manifest -r -o "$MANIFEST_OUT"
echo "OK: wrote $MANIFEST_OUT"
if [[ -n "${LOS_MANIFEST:-}" ]]; then
if [[ ! -f "$LOS_MANIFEST" ]]; then
echo "FAIL: LOS_MANIFEST not a file: $LOS_MANIFEST" >&2
exit 1
fi
echo "=== manifest diff vs $LOS_MANIFEST ==="
python3 - "$MANIFEST_OUT" "$LOS_MANIFEST" <<'PY'
import sys
import xml.etree.ElementTree as ET
def revs(path):
root = ET.parse(path).getroot()
out = {}
for el in root.iter("project"):
name = el.get("name") or el.get("path")
rev = el.get("revision")
if name and rev:
out[name] = rev
return out
local, nightly = revs(sys.argv[1]), revs(sys.argv[2])
only_l = sorted(set(local) - set(nightly))
only_n = sorted(set(nightly) - set(local))
differ = sorted(n for n in local.keys() & nightly.keys() if local[n] != nightly[n])
print(f"projects local={len(local)} nightly={len(nightly)} differ={len(differ)} only_local={len(only_l)} only_nightly={len(only_n)}")
for n in differ[:40]:
print(f"DIFF {n}\n local {local[n]}\n nightly {nightly[n]}")
if len(differ) > 40:
print(f"... {len(differ) - 40} more diffs")
if differ:
sys.exit("FAIL: local source revisions do not match the pinned nightly")
PY
fi
if [[ -n "${LOS_DATE:-}" ]]; then
[[ "$LOS_DATE" =~ ^[0-9]{8}$ ]] || { echo "FAIL: LOS_DATE must be YYYYMMDD" >&2; exit 1; }
echo "$LOS_DATE" > "$TREE/.axp-los-date"
echo "OK: build name date = LOS nightly $LOS_DATE"
fi
if [[ -n "$PROJECT_SOURCE" ]]; then
if [[ ! -d "$PROJECT_SOURCE/vendor/sunfish-a16" ]]; then
echo "FAIL: AXP_PROJECT_SOURCE lacks vendor/sunfish-a16: $PROJECT_SOURCE" >&2
exit 1
fi
echo "=== install current AXP working tree into source tree ==="
rsync -a --delete --exclude .git \
"$PROJECT_SOURCE/vendor/sunfish-a16/" "$TREE/vendor/sunfish-a16/"
fi
echo "=== mandatory ship: wave4 + hardened_malloc + release-keys bacon ==="
export AXP_DEBLOB_WAVE4=1
export AXP_AVB_FLAGS=0
export WITH_AVB=true
exec bash "$SCRIPT_DIR/009-bacon-hardened-malloc.sh"
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# After fixing the laptop tree: re-stage and relaunch polish bacon on rom-dev01.
set -euo pipefail
ROOT=$(cd "$(dirname "$0")/.." && pwd)
STAGE="${1:-/srv/rom/artifacts/009-axp-los23-port/worktree-20261016-polish}"
SESSION="${BACON_SESSION:-bacon009polish20261016}"
SSH=(ssh -F "$ROOT/docs/ssh/config" a16-build)
"$ROOT/scripts/009-sync-ota-stage-to-host.sh" "$STAGE"
"${SSH[@]}" "AXP_PROJECT_SOURCE=$STAGE LOS_SYNC=0 LOS_DATE=20261016 \
/srv/rom/artifacts/bin/rom-detach $SESSION -- \
bash $STAGE/scripts/009-rebuild-from-los.sh"
echo "OK: bacon relaunched ($SESSION). Check:"
echo " ssh -F docs/ssh/config a16-build cat /srv/rom/artifacts/detach-${SESSION}.status"
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# Push OTA rebuild inputs from laptop checkout to rom-dev01 stage dir.
# Does NOT change the phone. Apps/bootanim ship only after rom-dev01 bacon + sideload.
# Usage: scripts/009-sync-ota-stage-to-host.sh [stage-dir-on-host]
set -euo pipefail
ROOT=$(cd "$(dirname "$0")/.." && pwd)
STAGE=${1:-/srv/rom/artifacts/009-axp-los23-port/worktree-20261010-ota}
SSH=(ssh -F "$ROOT/docs/ssh/config" a16-build)
RSYNC_RSH="ssh -F $ROOT/docs/ssh/config"
"${SSH[@]}" "mkdir -p '$STAGE/scripts' '$STAGE/vendor/sunfish-a16'"
rsync -a --delete --exclude .git/ "$ROOT/scripts/" "a16-build:$STAGE/scripts/" -e "$RSYNC_RSH"
rsync -a --delete --exclude .git/ "$ROOT/vendor/sunfish-a16/" "a16-build:$STAGE/vendor/sunfish-a16/" -e "$RSYNC_RSH"
bash -n "$ROOT/scripts/009-rebuild-from-los.sh" "$ROOT/scripts/009-bacon-hardened-malloc.sh" \
"$ROOT/scripts/009-bacon-hardened-malloc.sh" "$ROOT/scripts/009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh"
"${SSH[@]}" "bash -n '$STAGE/scripts/009-rebuild-from-los.sh'"
echo "OK: staged to $STAGE on rom-dev01"
+32
View File
@@ -0,0 +1,32 @@
# Build / host scripts
**OTA / rebuild from LOS (use this):**
`009-rebuild-from-los.sh`
Always includes wave 4 deblob + hardened_malloc + Magisk release-keys bacon.
Optional `LOS_SYNC=1` runs `repo sync` first. Run on `rom-dev01` via `rom-detach`.
**Laptop → host stage (OTA inputs only):**
- `009-sync-ota-stage-to-host.sh` — rsync project tree to
`/srv/rom/artifacts/009-axp-los23-port/worktree-*` on `rom-dev01`
- `009-relaunch-polish-bacon.sh` — sync + detached `009-rebuild-from-los.sh`
(default session `bacon009polish20261016`, `LOS_DATE=20261016`)
Low-level pieces (called by the rebuild script, not a full OTA by themselves):
- `009-bacon-hardened-malloc.sh` — malloc link check, then ship bacon with wave 4
- `009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh` — kernel pack + userspace applies + `mka bacon`
- `009-bacon-wave4-deblob.sh` — wave 4 only (no malloc; not an OTA)
Checklist: `docs/009-upstream-rebase-ota.md`
**Historical / bisect only** (do not use for routine ship):
`009-bacon-axp-stage1-combo4*.sh` without `releasekeys`, `009-wait-flash-*`,
`009-watch-then-cve-bacon.sh`, `009-build-fortify-*`, `009-bisect-*`,
`009-fortify-select-family.py`.
LAB helpers: `009-diff-yuh-golden-lab.sh`, `009-read-swissquote-rasp.py`,
`check-module-abi.py` (KernelSU module ABI).
All heavy builds run on `rom-dev01` via `rom-detach` — see `AGENTS.md`.
+52
View File
@@ -0,0 +1,52 @@
#!/bin/bash
# Build sunfish bootanimation.tar from two GIFs (loading + loaded finale).
# Lineage Android.mk prepends "W H FPS" and appends branding/bootanimation/desc.txt.
#
# Sequence (desc.txt):
# part0 loading — play once
# part1 loaded — play once (finale before bootanim waits on part2)
# part2 hold — loop last loaded frame until boot completes
#
# Output: vendor/sunfish-a16/branding/bootanimation/bootanimation.tar
set -euo pipefail
ROOT=$(cd "$(dirname "$0")/.." && pwd)
LOADING=${1:-/home/aventura/Downloads/AXP_OS_Resurrection_loading.gif}
LOADED=${2:-/home/aventura/Downloads/AXP_OS_Resurrection_loaded.gif}
OUT="$ROOT/artifacts/bootanimation-resurrection"
WORK="$OUT/work"
W=1080
H=2340
FPS=30
# Fill frame (no letterbox band); AXP_BOOTANIMATION_FULLSCREEN in branding.mk.
VF="scale=${W}:${H}:force_original_aspect_ratio=increase,crop=${W}:${H},format=rgb24"
rm -rf "$WORK"
mkdir -p "$WORK/part0" "$WORK/part1" "$WORK/part2"
ffmpeg -y -i "$LOADING" -vf "$VF" "$WORK/part0/%05d.png"
ffmpeg -y -i "$LOADED" -vf "$VF" "$WORK/part1/%05d.png"
LAST_LOADED=$(ls -1 "$WORK/part1"/*.png | sort | tail -1)
cp "$LAST_LOADED" "$WORK/part2/00001.png"
cat >"$ROOT/vendor/sunfish-a16/branding/bootanimation/desc.txt" <<'EOF'
c 1 0 part0
c 1 0 part1
c 0 0 part2
EOF
cp "$ROOT/vendor/sunfish-a16/branding/bootanimation/desc.txt" "$WORK/desc.txt"
rm -f "$OUT/bootanimation.zip"
(cd "$WORK" && zip -0 -q "$OUT/bootanimation.zip" desc.txt && zip -0 -q -r "$OUT/bootanimation.zip" part0 part1 part2)
unzip -t "$OUT/bootanimation.zip" >/dev/null
TAR="$ROOT/vendor/sunfish-a16/branding/bootanimation/bootanimation.tar"
(cd "$WORK" && tar cf "$TAR" part0 part1 part2)
n0=$(ls -1 "$WORK/part0" | wc -l)
n1=$(ls -1 "$WORK/part1" | wc -l)
identify "$WORK/part0/00001.png" "$WORK/part2/00001.png"
ls -lh "$OUT/bootanimation.zip" "$TAR"
echo "OK: rebacon (or mka bootanimation.zip) — sync branding to host first"
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
# Pull recent Bluetooth / pairing / PBAP lines from LAB log buffers (no repro needed).
set -euo pipefail
LAB="${LAB_SERIAL:-11231JEC207477}"
OUT_DIR="${1:-$(cd "$(dirname "$0")/.." && pwd)/.local-artifacts/lab-bt-logs}"
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
mkdir -p "$OUT_DIR"
adb -s "$LAB" shell true >/dev/null 2>&1 || {
echo "LAB $LAB not visible to adb (USB or wireless debugging)." >&2
exit 1
}
BASE="$OUT_DIR/${STAMP}-lab-bt"
echo "LAB identity:"
adb -s "$LAB" shell getprop ro.lineage.version ro.build.display.id 2>/dev/null | tr '\n' ' '
echo
adb -s "$LAB" shell settings get global bluetooth_off_timeout >"${BASE}-bt-timeout.txt"
adb -s "$LAB" logcat -d -v threadtime -t 80000 >"${BASE}-logcat-main.txt"
adb -s "$LAB" logcat -b events -d -v threadtime -t 50000 >"${BASE}-logcat-events.txt"
adb -s "$LAB" shell dumpsys bluetooth_manager >"${BASE}-dumpsys-bluetooth_manager.txt"
adb -s "$LAB" shell dumpsys package com.android.bluetooth >"${BASE}-dumpsys-pkg-bluetooth.txt"
grep -iE 'bluetooth|pbap|phonebook|pair|bond|BtAutoOff|PermissionController|READ_CONTACTS|READ_CALL_LOG' \
"${BASE}-logcat-main.txt" >"${BASE}-grep-main.txt" || true
grep -iE 'bt_|bond|pair' "${BASE}-logcat-events.txt" >"${BASE}-grep-events.txt" || true
echo "Wrote:"
ls -la "${BASE}"-*
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
# Wallapop runs in Island (user 10, uid 1010271). Plain adb logcat often shows nothing.
set -euo pipefail
UID_WALLAPOP=1010271
echo "Clear log, reproduce login error on Island Wallapop, wait 10s..."
adb logcat -c
sleep 10
adb logcat -d --uid="$UID_WALLAPOP" > "/tmp/wallapop-uid-${UID_WALLAPOP}.log"
grep -iE 'error|exception|fail|auth|openid|http|integrity|host|ssl|connect' "/tmp/wallapop-uid-${UID_WALLAPOP}.log" | tail -80
echo "--- full log: /tmp/wallapop-uid-${UID_WALLAPOP}.log"