From fc8a0a17297caed0a99ec4cf508b49da3da987d7 Mon Sep 17 00:00:00 2001 From: oxmc <67136658+oxmc@users.noreply.github.com> Date: Wed, 15 Jul 2026 01:59:00 -0700 Subject: [PATCH] =?UTF-8?q?init:=20Lawnchair=20build=20bridge=20=E2=80=94?= =?UTF-8?q?=20prebuilt=20and=20AOSP-source=20build=20modes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitattributes | 2 + README.md | 116 +++++++++++++++++++++++++++++ aosp-bridge/gen-aidl-sourceset.sh | 120 ++++++++++++++++++++++++++++++ aosp-bridge/gen-framework-jars.sh | 118 +++++++++++++++++++++++++++++ build-aosp.sh | 94 +++++++++++++++++++++++ build-prebuilt.sh | 30 ++++++++ build.sh | 95 +++++++++++++++++++++++ 7 files changed, 575 insertions(+) create mode 100644 .gitattributes create mode 100644 README.md create mode 100755 aosp-bridge/gen-aidl-sourceset.sh create mode 100755 aosp-bridge/gen-framework-jars.sh create mode 100755 build-aosp.sh create mode 100755 build-prebuilt.sh create mode 100755 build.sh diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..efdba87 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +*.sh text eol=lf diff --git a/README.md b/README.md new file mode 100644 index 0000000..c1ccbec --- /dev/null +++ b/README.md @@ -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 ` + — 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. diff --git a/aosp-bridge/gen-aidl-sourceset.sh b/aosp-bridge/gen-aidl-sourceset.sh new file mode 100755 index 0000000..ea277e7 --- /dev/null +++ b/aosp-bridge/gen-aidl-sourceset.sh @@ -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 +# DRY_RUN=1 gen-aidl-sourceset.sh # 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 .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 }" +LAWNCHAIR_ROOT="${2:?usage: gen-aidl-sourceset.sh }" +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 diff --git a/aosp-bridge/gen-framework-jars.sh b/aosp-bridge/gen-framework-jars.sh new file mode 100755 index 0000000..cd32b7a --- /dev/null +++ b/aosp-bridge/gen-framework-jars.sh @@ -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] +# gen-framework-jars.sh --restore +# +# Originals are kept as .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] }" +LAWNCHAIR_ROOT="${2:?usage: gen-framework-jars.sh [--wmshell] }" + +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 -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)" diff --git a/build-aosp.sh b/build-aosp.sh new file mode 100755 index 0000000..fc95f64 --- /dev/null +++ b/build-aosp.sh @@ -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 -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." diff --git a/build-prebuilt.sh b/build-prebuilt.sh new file mode 100755 index 0000000..a15a040 --- /dev/null +++ b/build-prebuilt.sh @@ -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 diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..e0b1422 --- /dev/null +++ b/build.sh @@ -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