init: Lawnchair build bridge — prebuilt and AOSP-source build modes

This commit is contained in:
oxmc
2026-07-15 01:59:00 -07:00
commit fc8a0a1729
7 changed files with 575 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
* text=auto
*.sh text eol=lf
+116
View File
@@ -0,0 +1,116 @@
# lawnchair-build — PawletOS Lawnchair build bridge
Builds Lawnchair (16-dev) either the current known-good way (vendored
prebuilt stubs) or against PawletOS's actual AOSP `android-16.0.0_r4`
checkout, to eliminate the framework version-skew crash in
`TouchInteractionService` (`NoSuchMethodError` at startup →
`OverviewProxyService` never binds → no nav pill/gestures).
Kept separate from the `lawnchair` repo on purpose: the bridge mutates the
Lawnchair tree reversibly, and this way a failed experiment can't dirty the
launcher history.
## Three-repo layout
| Repo | Role | Where |
|---|---|---|
| `PawletOS/prebuilt_lawnchair` | pre-built APK shipped in the ROM | `vendor/Lawnchair/LawnchairLauncher` (Soong build) |
| `PawletOS/Lawnchair` (16-dev) | launcher source | `external/build-tools/lawnchair/source` (in-tree) |
| `PawletOS/lawnchair-build` | this repo — build scripts | `external/build-tools/lawnchair/build` (in-tree) |
The in-tree paths are wired in `android_local_manifest/common/pawletos.xml`
and synced by `environ.py --forceResync`. Neither source nor build repo is
part of the Soong build — the output APK is committed to
`prebuilt_lawnchair`, which is what the ROM actually packages.
The scripts find the Lawnchair checkout as a sibling automatically, in
either layout:
```
AOSP tree (build server) PawletOS working copy (Windows)
external/build-tools/lawnchair/ PawletOS/
source/ <- Lawnchair 16-dev lawnchair/ <- Lawnchair 16-dev
build/ <- this repo lawnchair-build/ <- this repo
```
In-tree, `build.sh aosp` also derives `AOSP_ROOT` from its own location
(4 levels up), so no env vars are needed on the server.
## Usage
```bash
./build.sh prebuilt # plain Gradle, vendored stubs — works anywhere
./build.sh aosp # both swaps + Gradle — needs an AOSP env on THIS machine
./build.sh aosp --skip-jars # AIDL swap only (try this first)
./build.sh aosp --wmshell # additionally swap WindowManager-Shell-16.jar
./build.sh restore # undo all bridge changes in the lawnchair tree
./build.sh clone # clone Lawnchair next to this folder if missing
```
`aosp` mode auto-detects the AOSP tree (`$AOSP_ROOT`,
`~/PawletOS-Build/AOSP-Source`, `/mnt/ssd/AOSP-Source`) and errors out if
none exists — so it effectively only runs on ubuntu-server-01, while
`prebuilt` works on any machine with a JDK/Android SDK.
## What the bridge actually swaps (verified against the real tree, 2026-07)
The original plan guessed at Lawnchair's layout; the real wiring is:
| Plan assumed | Reality |
|---|---|
| `quickstep/build.gradle.kts` with its own aidl sourceSet | One Groovy root `build.gradle`; quickstep is the `withQuickstep` sourceSet |
| Hidden-API jar at `quickstep/libs/`, needs Gradle edit | `addFrameworkJar('framework-16.jar')` resolves `prebuilts/libs/framework-16.jar` by name into ~25 modules — drop-in file replacement, zero Gradle edits |
| Symlink IPip/ISplitScreen/IRecentsAnimation* .aidl | Those files under `wmshell/src` are **dead source** — the compiled wm.shell stubs ship in `prebuilts/libs/WindowManager-Shell-16.jar` (an `implementation` dep, bundled into the APK). Swapping the jar (`--wmshell`) is the real lever |
| `assembleLawnWithQuickstepRelease` | Three flavor dimensions → `assembleLawnWithQuickstepGithubRelease` |
So the two swaps are:
1. **AIDL sources** (`aosp-bridge/gen-aidl-sourceset.sh`) — every `.aidl`
under `systemUI/shared/src` that has a same-path counterpart in
`frameworks/base/packages/SystemUI/shared/src` (or `core/java`) is
replaced by the AOSP copy. Copies, not symlinks; originals kept as
`.orig` + manifest.
2. **Prebuilt jars** (`aosp-bridge/gen-framework-jars.sh`) —
`prebuilts/libs/framework-16.jar``framework-minus-apex.jar` from
`out/soong/.intermediates`. `--wmshell` additionally swaps
`WindowManager-Shell-16.jar`.
### Known skew already found
Lawnchair vendors **both** `IOverviewProxy.aidl` and `ILauncherProxy.aidl`
in `systemUI/shared/src/com/android/systemui/shared/recents/`; the r4 tree
has only `ILauncherProxy` + `ISystemUiProxy` (`IOverviewProxy` is the
pre-rename QPR name). If Lawnchair's `TouchInteractionService` still hands
SystemUI an `IOverviewProxy` binder, that alone explains the bind failure —
the AIDL swap script flags this case but can't fix it; it needs a source
look in Lawnchair's quickstep code.
## Suggested order of operations
1. Fix the current AOSP build blocker first (last build died in Soong
generation: TWRP theme selection — `TW_THEME` unset, likely from the new
`recovery_toolkit` in `android_vendor_pawlet`), then at minimum
`m framework-minus-apex`.
2. `DRY_RUN=1 ./aosp-bridge/gen-aidl-sourceset.sh <AOSP_ROOT> <LAWNCHAIR_ROOT>`
— read what differs before anything is touched.
3. `./build.sh aosp --skip-jars` — test whether the AIDL swap alone fixes
the crash.
4. Full `./build.sh aosp`, then `--wmshell` on top, escalating only as
needed — each step pulls in more of the diverged class graph, and compile
errors from the jar swaps are the skew surfacing at build time (fix in
Lawnchair source, don't paper over).
5. If it balloons: `./build.sh prebuilt` still works (it auto-restores any
bridge leftovers), and pinning to Lawnchair 15 stable remains the
fallback plan.
## Verifying the fix on device
```bash
adb connect 10.0.0.236:5555
adb logcat -c
# restart Lawnchair / reboot
adb logcat | grep -iE "TouchInteractionService|app.lawnchair|FATAL EXCEPTION|OverviewProxyService"
```
Success: no `NoSuchMethodError`/`NoSuchFieldError`, an OverviewProxy bind
log line, and the nav pill/gesture affordances actually rendering.
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env bash
#
# gen-aidl-sourceset.sh — overwrites Lawnchair's vendored launcher<->SystemUI
# AIDL sources with the copies from PawletOS's local frameworks/base, so the
# binder surface Lawnchair compiles against matches what the device's
# SystemUI actually exposes.
#
# VERIFIED LAYOUT (Lawnchair 16-dev, checked 2026-07):
# The AIDLs that are compiled FROM SOURCE live in systemUI/shared/src
# (module ':shared' -> systemUI/shared, aidl.srcDirs includes its src dir).
# That includes the TouchInteractionService handshake interfaces:
# ISystemUiProxy, ILauncherProxy (and the vendored-only IOverviewProxy).
#
# The wm.shell interfaces (IPip, ISplitScreen, IRecentsAnimation*, ...)
# under wmshell/src are NOT compiled — wmshell's sourceSet only includes
# wmshell/shared/src; the real wm.shell classes ship precompiled in
# prebuilts/libs/WindowManager-Shell-16.jar. Touching wmshell/src does
# nothing; that jar is handled by gen-framework-jars.sh --wmshell instead.
#
# Usage:
# gen-aidl-sourceset.sh <AOSP_ROOT> <LAWNCHAIR_ROOT>
# DRY_RUN=1 gen-aidl-sourceset.sh <AOSP_ROOT> <LAWNCHAIR_ROOT> # report only
# gen-aidl-sourceset.sh --restore # undo via manifest
#
# Files are COPIED (not symlinked) so the result works regardless of where
# the Lawnchair checkout lives; originals are kept as <file>.orig and listed
# in the manifest for --restore.
set -euo pipefail
log() { printf '\033[1;33m[gen-aidl]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[gen-aidl]\033[0m %s\n' "$*" >&2; }
MANIFEST_NAME=".aosp-bridge-aidl-backup.tsv"
DRY_RUN="${DRY_RUN:-0}"
# --- restore mode ------------------------------------------------------
if [ "${1:-}" = "--restore" ]; then
ROOT="${LAWNCHAIR_ROOT:-.}"
MANIFEST="$ROOT/$MANIFEST_NAME"
[ -f "$MANIFEST" ] || { log "no AIDL backup manifest at $MANIFEST — nothing to restore"; exit 0; }
while IFS=$'\t' read -r target backup; do
[ -z "$target" ] && continue
if [ -e "$backup" ]; then
mv -f "$backup" "$target"
log "restored: $target"
fi
done < "$MANIFEST"
rm -f "$MANIFEST"
exit 0
fi
AOSP_ROOT="${1:?usage: gen-aidl-sourceset.sh <AOSP_ROOT> <LAWNCHAIR_ROOT>}"
LAWNCHAIR_ROOT="${2:?usage: gen-aidl-sourceset.sh <AOSP_ROOT> <LAWNCHAIR_ROOT>}"
MANIFEST="$LAWNCHAIR_ROOT/$MANIFEST_NAME"
# Lawnchair source-compiled AIDL root -> candidate AOSP roots for the same
# package-relative path. core/java catches android.os / com.android.internal
# files that SystemUI/shared borrows from framework core.
LAWN_AIDL_ROOT="$LAWNCHAIR_ROOT/systemUI/shared/src"
AOSP_CANDIDATE_ROOTS=(
"$AOSP_ROOT/frameworks/base/packages/SystemUI/shared/src"
"$AOSP_ROOT/frameworks/base/core/java"
)
[ -d "$LAWN_AIDL_ROOT" ] || { err "expected $LAWN_AIDL_ROOT to exist — Lawnchair layout changed, re-verify before using this script"; exit 1; }
[ "$DRY_RUN" = "1" ] || : > "$MANIFEST"
swapped=0
identical=0
vendored_only=()
while IFS= read -r lawn_file; do
rel="${lawn_file#"$LAWN_AIDL_ROOT/"}"
aosp_file=""
for root in "${AOSP_CANDIDATE_ROOTS[@]}"; do
[ -f "$root/$rel" ] && { aosp_file="$root/$rel"; break; }
done
if [ -z "$aosp_file" ]; then
vendored_only+=("$rel")
continue
fi
if cmp -s "$lawn_file" "$aosp_file"; then
identical=$((identical + 1))
continue
fi
log "DIFFERS: $rel"
log " <- $aosp_file"
if [ "$DRY_RUN" != "1" ]; then
cp -a "$lawn_file" "${lawn_file}.orig"
printf '%s\t%s\n' "$lawn_file" "${lawn_file}.orig" >> "$MANIFEST"
cp "$aosp_file" "$lawn_file"
fi
swapped=$((swapped + 1))
done < <(find "$LAWN_AIDL_ROOT" -name '*.aidl' | sort)
log "----------------------------------------------------------------"
log "swapped: $swapped identical (no action): $identical"
if [ "${#vendored_only[@]}" -gt 0 ]; then
err "Vendored-only AIDLs with NO counterpart in this AOSP tag (left untouched):"
for v in "${vendored_only[@]}"; do err " - $v"; done
err "If Lawnchair code implements one of these but the device SystemUI binds its"
err "renamed successor (e.g. IOverviewProxy vs ILauncherProxy in android-16),"
err "that's a likely source of the bind failure — needs a source-level look."
fi
if [ "$DRY_RUN" = "1" ]; then
log "DRY_RUN=1 — nothing was modified."
elif [ "$swapped" -gt 0 ]; then
log "Backup manifest: $MANIFEST (undo with --restore)"
else
rm -f "$MANIFEST"
log "No differing files — vendored AIDL already matches this AOSP tree."
fi
+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/env bash
#
# gen-framework-jars.sh — replaces Lawnchair's vendored prebuilt jars with
# the ones compiled from PawletOS's local AOSP tree. (Successor to the
# planned gen-hidden-api-jar.sh — the destination wiring turned out to be
# much simpler than the plan assumed.)
#
# VERIFIED WIRING (Lawnchair 16-dev root build.gradle, checked 2026-07):
# addFrameworkJar('framework-16.jar') prepends
# prebuilts/libs/framework-16.jar to the compile classpath of the root
# module and ~25 submodules, and it is resolved BY FILE NAME in
# prebuilts/libs. So the hidden-API swap is a drop-in replacement of that
# one file — no Gradle edits needed, and no quickstep/libs/ dir exists.
#
# WindowManager-Shell-16.jar is wired as `implementation` (bundled into
# the APK!) and carries the compiled wm.shell binder stubs (IPip,
# ISplitScreen, IRecentsAnimation*, ...). Swapping it aligns those
# transaction surfaces too, but drags in more of the diverged class graph
# — opt in with --wmshell only if the framework jar swap alone isn't enough.
#
# Usage:
# gen-framework-jars.sh [--wmshell] <AOSP_ROOT> <LAWNCHAIR_ROOT>
# gen-framework-jars.sh --restore
#
# Originals are kept as <jar>.orig and recorded in a manifest for --restore.
set -euo pipefail
log() { printf '\033[1;33m[gen-jars]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[gen-jars]\033[0m %s\n' "$*" >&2; }
MANIFEST_NAME=".aosp-bridge-jars-backup.tsv"
# --- restore mode ------------------------------------------------------
if [ "${1:-}" = "--restore" ]; then
ROOT="${LAWNCHAIR_ROOT:-.}"
MANIFEST="$ROOT/$MANIFEST_NAME"
[ -f "$MANIFEST" ] || { log "no jar backup manifest at $MANIFEST — nothing to restore"; exit 0; }
while IFS=$'\t' read -r target backup; do
[ -z "$target" ] && continue
if [ -e "$backup" ]; then
mv -f "$backup" "$target"
log "restored: $target"
fi
done < "$MANIFEST"
rm -f "$MANIFEST"
exit 0
fi
WMSHELL=0
if [ "${1:-}" = "--wmshell" ]; then WMSHELL=1; shift; fi
AOSP_ROOT="${1:?usage: gen-framework-jars.sh [--wmshell] <AOSP_ROOT> <LAWNCHAIR_ROOT>}"
LAWNCHAIR_ROOT="${2:?usage: gen-framework-jars.sh [--wmshell] <AOSP_ROOT> <LAWNCHAIR_ROOT>}"
PREBUILTS_DIR="$LAWNCHAIR_ROOT/prebuilts/libs"
MANIFEST="$LAWNCHAIR_ROOT/$MANIFEST_NAME"
INTERMEDIATES="$AOSP_ROOT/out/soong/.intermediates/frameworks/base"
[ -d "$PREBUILTS_DIR" ] || { err "$PREBUILTS_DIR not found — Lawnchair layout changed, re-verify"; exit 1; }
# Locate a module's compiled jar in Soong output. Exact intermediate layout
# varies between AOSP versions, so prefer known paths then fall back to find.
find_module_jar() {
local module="$1" search_root="$2"
local candidates=(
"$search_root/$module/android_common/combined/$module.jar"
"$search_root/$module/android_common/javac/$module.jar"
)
for c in "${candidates[@]}"; do
[ -f "$c" ] && { echo "$c"; return 0; }
done
find "$INTERMEDIATES" -maxdepth 6 -path "*/$module/android_common*" -name "$module.jar" 2>/dev/null | head -1
}
swap_jar() {
local src="$1" dest_name="$2"
local dest="$PREBUILTS_DIR/$dest_name"
[ -f "$dest" ] || { err "expected vendored jar $dest to exist — aborting this swap"; return 1; }
if [ ! -f "${dest}.orig" ]; then
cp -a "$dest" "${dest}.orig"
printf '%s\t%s\n' "$dest" "${dest}.orig" >> "$MANIFEST"
fi
cp "$src" "$dest"
log "swapped $dest_name <- $src ($(du -h "$src" | cut -f1))"
}
touch "$MANIFEST"
# --- framework-16.jar (the hidden-API classpath jar) --------------------
# framework-minus-apex is the right module: the full app-facing framework
# including @hide APIs, minus mainline-module classes Lawnchair can't see
# anyway. Plain 'framework' is a thin wrapper around it in android-16.
src_jar="$(find_module_jar framework-minus-apex "$INTERMEDIATES")"
if [ -z "$src_jar" ]; then
src_jar="$(find_module_jar framework "$INTERMEDIATES")"
fi
if [ -z "$src_jar" ]; then
err "No compiled framework jar found under $INTERMEDIATES"
err "Run a framework build first: lunch <target>-bp4a-userdebug && m framework-minus-apex"
err "Then locate it manually if this still fails:"
err " find \"$AOSP_ROOT/out/soong/.intermediates\" -name 'framework-minus-apex.jar'"
exit 1
fi
swap_jar "$src_jar" "framework-16.jar"
# --- WindowManager-Shell-16.jar (opt-in) --------------------------------
if [ "$WMSHELL" -eq 1 ]; then
wm_jar="$(find_module_jar WindowManager-Shell "$INTERMEDIATES/libs/WindowManager/Shell")"
[ -z "$wm_jar" ] && wm_jar="$(find_module_jar WindowManager-Shell "$INTERMEDIATES")"
if [ -z "$wm_jar" ]; then
err "WindowManager-Shell jar not found — build it with 'm WindowManager-Shell' and re-run"
exit 1
fi
swap_jar "$wm_jar" "WindowManager-Shell-16.jar"
fi
log "Done. Undo with --restore (manifest: $MANIFEST)"
Executable
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
#
# build-aosp.sh — builds Lawnchair against the local PawletOS AOSP checkout
# instead of the vendored AIDL/stub jars. Fixes NoSuchMethodError-style
# crashes in TouchInteractionService caused by Lawnchair's upstream stub
# surface (QPR1-derived) drifting from PawletOS's actual frameworks/base
# (android-16.0.0_r4).
#
# Two swaps, both reversible via 'build.sh restore':
# 1. AIDL: systemUI/shared/src AIDL files <- frameworks/base copies
# 2. Jars: prebuilts/libs/framework-16.jar <- compiled framework jar from out/
# (+ optionally WindowManager-Shell-16.jar with --wmshell)
#
# Called via: build.sh aosp [--clean] [--skip-aidl] [--skip-jars] [--wmshell]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
AOSP_ROOT="${AOSP_ROOT:?AOSP_ROOT not set}"
LAWNCHAIR_ROOT="${LAWNCHAIR_ROOT:?LAWNCHAIR_ROOT not set}"
GRADLE_TASK="${GRADLE_TASK:-assembleLawnWithQuickstepGithubRelease}"
SKIP_AIDL=0
SKIP_JARS=0
WMSHELL=0
CLEAN=0
for arg in "$@"; do
case "$arg" in
--skip-aidl) SKIP_AIDL=1 ;;
--skip-jars|--skip-hidden-api) SKIP_JARS=1 ;;
--wmshell) WMSHELL=1 ;;
--clean) CLEAN=1 ;;
*) echo "unknown flag: $arg" >&2; exit 1 ;;
esac
done
log() { printf '\033[1;36m[build-aosp.sh]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[build-aosp.sh]\033[0m %s\n' "$*" >&2; exit 1; }
# Fail fast if the AOSP tree has never produced framework artifacts —
# the jar swap needs a compiled framework, and a half-applied bridge is
# worse than no bridge.
if [ "$SKIP_JARS" -eq 0 ]; then
if ! find "$AOSP_ROOT/out/soong/.intermediates/frameworks/base" \
-maxdepth 4 -name 'framework-minus-apex.jar' -print -quit 2>/dev/null | grep -q .; then
die "No compiled framework jar under \$AOSP_ROOT/out — run a framework build first
(e.g. 'lunch <target>-bp4a-userdebug && m framework-minus-apex'), or pass
--skip-jars to apply only the AIDL swap."
fi
fi
cd "$LAWNCHAIR_ROOT"
if [ "$CLEAN" -eq 1 ]; then
log "Cleaning previous AOSP-bridge artifacts"
"$SCRIPT_DIR/aosp-bridge/gen-aidl-sourceset.sh" --restore || true
"$SCRIPT_DIR/aosp-bridge/gen-framework-jars.sh" --restore || true
rm -f ./aosp-bridge.state
fi
if [ "$SKIP_AIDL" -eq 0 ]; then
log "Step 1/2: syncing AIDL sources from local AOSP tree"
"$SCRIPT_DIR/aosp-bridge/gen-aidl-sourceset.sh" "$AOSP_ROOT" "$LAWNCHAIR_ROOT"
else
log "Step 1/2: skipped (--skip-aidl)"
fi
if [ "$SKIP_JARS" -eq 0 ]; then
log "Step 2/2: swapping prebuilt framework jar(s) from local AOSP build output"
jar_flags=()
[ "$WMSHELL" -eq 1 ] && jar_flags+=(--wmshell)
"$SCRIPT_DIR/aosp-bridge/gen-framework-jars.sh" ${jar_flags[@]+"${jar_flags[@]}"} "$AOSP_ROOT" "$LAWNCHAIR_ROOT"
else
log "Step 2/2: skipped (--skip-jars)"
fi
echo "aosp" > ./aosp-bridge.state
log "Running ./gradlew $GRADLE_TASK"
if ! ./gradlew "$GRADLE_TASK"; then
log "Build failed. Triage guide:"
log " - Wall of missing-class/missing-method COMPILE errors: that IS the version skew,"
log " now surfacing at build time instead of crashing at runtime. Each one needs a"
log " source fix in Lawnchair (or the call removed) to match PawletOS's framework."
log " - If it's unmanageable, retry with --skip-jars to isolate the AIDL swap alone,"
log " or fall back to './build.sh prebuilt'."
exit 1
fi
log "Done. APK(s):"
find . -path '*/outputs/apk/*' -name '*.apk' -newer ./gradlew 2>/dev/null | head -5
log "NOTE: the swapped AIDL files and jars persist in the Lawnchair tree until you run"
log "'./build.sh restore' — do that before committing anything in the lawnchair repo."
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
#
# build-prebuilt.sh — plain Gradle build using the AIDL/hidden-API stubs
# vendored in the Lawnchair repo (prebuilts/libs/framework-16.jar etc.).
# This is the path PawletOS has used up to now: build the APK standalone,
# drop it into vendor/pawlet prebuilts. Kept as the known-good fallback and
# the only mode that works on machines without an AOSP checkout.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LAWNCHAIR_ROOT="${LAWNCHAIR_ROOT:?LAWNCHAIR_ROOT not set}"
GRADLE_TASK="${GRADLE_TASK:-assembleLawnWithQuickstepGithubRelease}"
log() { printf '\033[1;36m[build-prebuilt.sh]\033[0m %s\n' "$*"; }
cd "$LAWNCHAIR_ROOT"
if [ -f ./aosp-bridge.state ]; then
log "Leftover AOSP-bridge artifacts detected — restoring vendored originals first"
"$SCRIPT_DIR/aosp-bridge/gen-aidl-sourceset.sh" --restore || true
"$SCRIPT_DIR/aosp-bridge/gen-framework-jars.sh" --restore || true
rm -f ./aosp-bridge.state
fi
log "Running ./gradlew $GRADLE_TASK"
./gradlew "$GRADLE_TASK"
log "Done. APK(s):"
find . -path '*/outputs/apk/*' -name '*.apk' -newer ./gradlew 2>/dev/null | head -5
Executable
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
#
# build.sh — PawletOS Lawnchair build dispatcher
#
# Usage:
# ./build.sh prebuilt # known-good flow: plain Gradle, vendored AIDL + stub jars
# ./build.sh aosp # build against a local AOSP checkout (requires one on THIS machine)
# ./build.sh aosp --skip-jars # AIDL swap only, keep Lawnchair's vendored framework-16.jar
# ./build.sh aosp --wmshell # also swap WindowManager-Shell-16.jar (heavier, see README)
# ./build.sh aosp --clean # restore originals first, then re-apply swaps and build
# ./build.sh restore # undo all AOSP-bridge changes, back to pristine prebuilt state
# ./build.sh clone # clone the Lawnchair repo next to this folder if missing
#
# Env vars:
# AOSP_ROOT AOSP checkout root. If unset, auto-detected (including the
# case where this repo is checked out inside the AOSP tree at
# external/build-tools/lawnchair/build).
# LAWNCHAIR_ROOT Lawnchair checkout. If unset, first existing of
# ../source (in-tree manifest layout) or ../lawnchair
# (PawletOS Windows working-copy layout).
# GRADLE_TASK Gradle task (default: assembleLawnWithQuickstepGithubRelease)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MODE="${1:-}"
shift || true
if [ -z "${LAWNCHAIR_ROOT:-}" ]; then
if [ -d "$SCRIPT_DIR/../source" ]; then
LAWNCHAIR_ROOT="$SCRIPT_DIR/../source"
else
LAWNCHAIR_ROOT="$SCRIPT_DIR/../lawnchair"
fi
fi
export LAWNCHAIR_ROOT
export GRADLE_TASK="${GRADLE_TASK:-assembleLawnWithQuickstepGithubRelease}"
LAWNCHAIR_REMOTE="https://git.oxmc.me/PawletOS/Lawnchair"
LAWNCHAIR_BRANCH="16-dev"
log() { printf '\033[1;36m[build.sh]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[build.sh]\033[0m %s\n' "$*" >&2; exit 1; }
# Find an AOSP build environment on this machine. AOSP mode only works where
# the tree (and ideally its build output) actually lives — on any other
# machine we error out rather than half-work. When this repo is checked out
# in-tree (external/build-tools/lawnchair/build), the tree root is 4 levels up.
detect_aosp_root() {
local candidates=(
"${AOSP_ROOT:-}"
"$SCRIPT_DIR/../../../.."
"$HOME/PawletOS-Build/AOSP-Source"
"/mnt/ssd/AOSP-Source"
)
for c in "${candidates[@]}"; do
[ -n "$c" ] && [ -f "$c/build/envsetup.sh" ] && { cd "$c" && pwd; return 0; }
done
return 1
}
case "$MODE" in
aosp)
AOSP_ROOT="$(detect_aosp_root)" || die \
"No AOSP build environment found on this machine.
Checked: \$AOSP_ROOT, 4 dirs above this script (in-tree checkout),
~/PawletOS-Build/AOSP-Source, /mnt/ssd/AOSP-Source.
AOSP mode must run where the PawletOS AOSP tree lives (ubuntu-server-01);
use './build.sh prebuilt' for a purely local build."
export AOSP_ROOT
[ -d "$LAWNCHAIR_ROOT" ] || die "Lawnchair checkout not found at $LAWNCHAIR_ROOT — run './build.sh clone' or set LAWNCHAIR_ROOT"
log "AOSP env: $AOSP_ROOT"
exec "$SCRIPT_DIR/build-aosp.sh" "$@"
;;
prebuilt)
[ -d "$LAWNCHAIR_ROOT" ] || die "Lawnchair checkout not found at $LAWNCHAIR_ROOT — run './build.sh clone' or set LAWNCHAIR_ROOT"
log "Prebuilt mode: vendored AIDL + stub jars (no AOSP checkout needed)"
exec "$SCRIPT_DIR/build-prebuilt.sh" "$@"
;;
restore)
[ -d "$LAWNCHAIR_ROOT" ] || die "Lawnchair checkout not found at $LAWNCHAIR_ROOT"
"$SCRIPT_DIR/aosp-bridge/gen-aidl-sourceset.sh" --restore
"$SCRIPT_DIR/aosp-bridge/gen-framework-jars.sh" --restore
rm -f "$LAWNCHAIR_ROOT/aosp-bridge.state"
log "All AOSP-bridge changes restored."
;;
clone)
[ -d "$LAWNCHAIR_ROOT" ] && die "Lawnchair already exists at $LAWNCHAIR_ROOT"
log "Cloning $LAWNCHAIR_REMOTE ($LAWNCHAIR_BRANCH) -> $LAWNCHAIR_ROOT"
git clone --branch "$LAWNCHAIR_BRANCH" "$LAWNCHAIR_REMOTE" "$LAWNCHAIR_ROOT"
;;
*)
die "usage: $0 [aosp|prebuilt|restore|clone] [flags]"
;;
esac