Bootstrap Mentra Live firmware during ASG dev setup - #3737
Conversation
📋 PR Review Helper📱 Mobile App Build⏳ Waiting for build... 🕶️ ASG Client Build✅ Ready to test! (commit 🔀 Test Locallygh pr checkout 3737 |
| start_time="$(date +%s)" | ||
| sleep 2 | ||
| continue | ||
| fi |
There was a problem hiding this comment.
Reboot wait exits too early
High Severity
wait_for_boot_after_reboot treats any prior ADB disconnect as proof the device rebooted, then returns as soon as ADB is back—even when boot_id is unchanged. The explicit ADB reboot fallback only runs when saw_disconnect stays false, so the path meant for older firmware (first adb reboot failed because ADB already dropped) is skipped and MTK verification fails after a reconnect without a real reboot.
Triggered by project rule: Bugbot rules for MentraOS
Reviewed by Cursor Bugbot for commit 7090220. Configure here.
| # | ||
|
|
||
| set -e | ||
| set -euo pipefail |
There was a problem hiding this comment.
Restore aborts on grep miss
Medium Severity
Switching restore-stock.sh to set -euo pipefail makes existing grep pipelines fatal. If dumpsys lacks versionCode or the OTA JSON shape does not match the grep -o patterns, command substitution fails and the script exits after stock may already be partially re-enabled, instead of skipping the optional update path.
Additional Locations (1)
Triggered by project rule: Bugbot rules for MentraOS
Reviewed by Cursor Bugbot for commit 7090220. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7090220f25
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "${ADB[@]}" uninstall "$STOCK_PKG" >/dev/null \ | ||
| || fail "Could not remove the ASG 36 update layer" |
There was a problem hiding this comment.
Preserve legacy captures before uninstalling the bridge
On devices upgrading from older stock firmware, this uninstall can permanently delete unsynced photos and videos still under /storage/emulated/0/Android/data/com.mentra.asg_client/files before the staging build can migrate them. MediaStorage.java:11-21 documents that this app-owned tree is deleted during an uninstall and that older builds store media there; installing and starting the legacy ASG 36 bridge does not establish that migration has completed. Preserve package data (or explicitly migrate and verify legacy media) before removing the bridge.
AGENTS.md reference: asg_client/AGENTS.md:L5-L7
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
10 issues found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="asg_client/scripts/restore-stock.sh">
<violation number="1" location="asg_client/scripts/restore-stock.sh:27">
P2: When `ANDROID_SERIAL` selects a device and another ADB device is connected, `resolve_serial` ignores that selection and either aborts for multiple devices or can restore the other device. Map `ANDROID_SERIAL` to `ADB_SERIAL` before calling `resolve_serial`, as `update-stock-for-dev.sh` does.</violation>
</file>
<file name="asg_client/scripts/update-stock-for-dev.sh">
<violation number="1" location="asg_client/scripts/update-stock-for-dev.sh:149">
P2: If a stock restore command fails, `enable_stock_runtime` suppresses the error and cleanup still claims to have restored the launcher. Check the critical install, enable, home-selection, and launch operations so setup failures cannot leave the device without a usable home.</violation>
<violation number="2" location="asg_client/scripts/update-stock-for-dev.sh:187">
P1: When ADB disconnects and reconnects without changing `boot_id`, this branch treats the reconnect as a completed reboot and the next MTK check can read stale firmware. Require a changed `boot_id` before breaking, or resend `adb reboot` for this case.</violation>
<violation number="3" location="asg_client/scripts/update-stock-for-dev.sh:199">
P2: When ADB stays online and the boot ID never changes, this retry leaves the loop with no later timeout or failure path, so setup can hang forever. Add a bounded post-retry timeout that calls `fail` and lets cleanup restore stock.</violation>
<violation number="4" location="asg_client/scripts/update-stock-for-dev.sh:267">
P1: After `BES accepted apply`, the BES manager is still awaiting reboot and exact verification, but this function proceeds after a fixed sleep and a `version_info_3` match without requiring the BES-specific reconnect and terminal success. Wait for the durable terminal-success edge plus the BES disconnect/reconnect before replacing the bridge or continuing.</violation>
</file>
<file name="asg_client/scripts/test-bes-ota.sh">
<violation number="1" location="asg_client/scripts/test-bes-ota.sh:16">
P3: When a caller supplies `--no-follow` plus an extra argument, this parser silently accepts the typo and runs the OTA. Reject any nonempty fourth argument instead of ignoring it.</violation>
<violation number="2" location="asg_client/scripts/test-bes-ota.sh:88">
P1: When a phone BES OTA is active, this copy overwrites its shared `bes_firmware.bin` before `DebugBesOtaReceiver` can acquire admission, and a later refusal cannot restore it. Reserve OTA admission before staging the compatibility copy, or use a bridge-specific path that cannot touch phone-owned artifacts.
(Based on your team's feedback about preserving unrelated BES artifacts.)</violation>
</file>
<file name="asg_client/scripts/dev-setup.sh">
<violation number="1" location="asg_client/scripts/dev-setup.sh:20">
P2: When the optional version or OTA JSON `grep` finds no match, `set -o pipefail` propagates that status and `set -e` aborts restoration after stock may already be partially re-enabled. Guard these probes or handle their status explicitly so a missing optional field skips the update path.</violation>
<violation number="2" location="asg_client/scripts/dev-setup.sh:77">
P2: If setup fails after the recovery-agent step, the failure handler leaves `LEGACY_UPDATER_PKG` disabled while restoring stock. Re-enable the legacy updater alongside `RECOVERY_PKG` so stock recovery remains complete.</violation>
<violation number="3" location="asg_client/scripts/dev-setup.sh:117">
P2: When the firmware updater fails after mutating the device while ADB is offline, this flag is still false, so the parent trap skips its restore/reconnect guidance. Mark setup as mutable before invoking the updater, or propagate the child’s mutation state.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| while [ "$SECONDS" -lt "$deadline" ]; do | ||
| adb_online || fail "ADB disconnected during the BES transfer" | ||
| logs="$("${ADB[@]}" logcat -d 2>/dev/null | tail -n 500 || true)" | ||
| if printf '%s\n' "$logs" | grep -Eq 'BES firmware update SUCCESS|BES accepted apply'; then |
There was a problem hiding this comment.
P1: After BES accepted apply, the BES manager is still awaiting reboot and exact verification, but this function proceeds after a fixed sleep and a version_info_3 match without requiring the BES-specific reconnect and terminal success. Wait for the durable terminal-success edge plus the BES disconnect/reconnect before replacing the bridge or continuing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/update-stock-for-dev.sh, line 267:
<comment>After `BES accepted apply`, the BES manager is still awaiting reboot and exact verification, but this function proceeds after a fixed sleep and a `version_info_3` match without requiring the BES-specific reconnect and terminal success. Wait for the durable terminal-success edge plus the BES disconnect/reconnect before replacing the bridge or continuing.</comment>
<file context>
@@ -0,0 +1,478 @@
+ while [ "$SECONDS" -lt "$deadline" ]; do
+ adb_online || fail "ADB disconnected during the BES transfer"
+ logs="$("${ADB[@]}" logcat -d 2>/dev/null | tail -n 500 || true)"
+ if printf '%s\n' "$logs" | grep -Eq 'BES firmware update SUCCESS|BES accepted apply'; then
+ echo "BES accepted the firmware and is rebooting."
+ break
</file context>
|
|
||
| # ASG 36 predates target/hash extras and always reads this fixed path. Keep both | ||
| # copies so this one broadcast works with the bootstrap client and current ASG. | ||
| "${ADB[@]}" shell cp "$REMOTE_PATH" "$LEGACY_REMOTE_PATH" |
There was a problem hiding this comment.
P1: When a phone BES OTA is active, this copy overwrites its shared bes_firmware.bin before DebugBesOtaReceiver can acquire admission, and a later refusal cannot restore it. Reserve OTA admission before staging the compatibility copy, or use a bridge-specific path that cannot touch phone-owned artifacts.
(Based on your team's feedback about preserving unrelated BES artifacts.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/test-bes-ota.sh, line 88:
<comment>When a phone BES OTA is active, this copy overwrites its shared `bes_firmware.bin` before `DebugBesOtaReceiver` can acquire admission, and a later refusal cannot restore it. Reserve OTA admission before staging the compatibility copy, or use a bridge-specific path that cannot touch phone-owned artifacts.
(Based on your team's feedback about preserving unrelated BES artifacts.) </comment>
<file context>
@@ -72,6 +83,16 @@ if [ "$REMOTE_SHA256" != "$FIRMWARE_SHA256" ]; then
+# ASG 36 predates target/hash extras and always reads this fixed path. Keep both
+# copies so this one broadcast works with the bootstrap client and current ASG.
+"${ADB[@]}" shell cp "$REMOTE_PATH" "$LEGACY_REMOTE_PATH"
+LEGACY_REMOTE_SHA256="$("${ADB[@]}" shell sha256sum "$LEGACY_REMOTE_PATH" | awk '{print $1}' | tr -d '\r')"
+if [ "$LEGACY_REMOTE_SHA256" != "$FIRMWARE_SHA256" ]; then
</file context>
| if [ -n "$previous_boot_id" ] && [ -n "$current_boot_id" ] && [ "$current_boot_id" != "$previous_boot_id" ]; then | ||
| break | ||
| fi | ||
| if [ "$saw_disconnect" = true ]; then |
There was a problem hiding this comment.
P1: When ADB disconnects and reconnects without changing boot_id, this branch treats the reconnect as a completed reboot and the next MTK check can read stale firmware. Require a changed boot_id before breaking, or resend adb reboot for this case.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/update-stock-for-dev.sh, line 187:
<comment>When ADB disconnects and reconnects without changing `boot_id`, this branch treats the reconnect as a completed reboot and the next MTK check can read stale firmware. Require a changed `boot_id` before breaking, or resend `adb reboot` for this case.</comment>
<file context>
@@ -0,0 +1,478 @@
+ if [ -n "$previous_boot_id" ] && [ -n "$current_boot_id" ] && [ "$current_boot_id" != "$previous_boot_id" ]; then
+ break
+ fi
+ if [ "$saw_disconnect" = true ]; then
+ break
+ fi
</file context>
|
|
||
| echo "Connected device:" | ||
| adb devices | grep "device$" | ||
| resolve_serial |
There was a problem hiding this comment.
P2: When ANDROID_SERIAL selects a device and another ADB device is connected, resolve_serial ignores that selection and either aborts for multiple devices or can restore the other device. Map ANDROID_SERIAL to ADB_SERIAL before calling resolve_serial, as update-stock-for-dev.sh does.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/restore-stock.sh, line 27:
<comment>When `ANDROID_SERIAL` selects a device and another ADB device is connected, `resolve_serial` ignores that selection and either aborts for multiple devices or can restore the other device. Map `ANDROID_SERIAL` to `ADB_SERIAL` before calling `resolve_serial`, as `update-stock-for-dev.sh` does.</comment>
<file context>
@@ -9,25 +9,23 @@
-
-echo "Connected device:"
-adb devices | grep "device$"
+resolve_serial
+export ANDROID_SERIAL="$SERIAL"
echo ""
</file context>
| resolve_serial | |
| if [ -n "${ANDROID_SERIAL:-}" ] && [ -z "${ADB_SERIAL:-}" ]; then | |
| ADB_SERIAL="$ANDROID_SERIAL" | |
| export ADB_SERIAL | |
| fi | |
| resolve_serial |
| "${ADB[@]}" shell cmd package install-existing "$STOCK_PKG" >/dev/null 2>&1 || true | ||
| "${ADB[@]}" shell pm enable "$STOCK_PKG" >/dev/null 2>&1 || true | ||
| "${ADB[@]}" shell pm clear-package-preferred-activities "$STOCK_PKG" >/dev/null 2>&1 || true | ||
| "${ADB[@]}" shell cmd package set-home-activity --user 0 "$STOCK_COMPONENT" >/dev/null 2>&1 || true |
There was a problem hiding this comment.
P2: If a stock restore command fails, enable_stock_runtime suppresses the error and cleanup still claims to have restored the launcher. Check the critical install, enable, home-selection, and launch operations so setup failures cannot leave the device without a usable home.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/update-stock-for-dev.sh, line 149:
<comment>If a stock restore command fails, `enable_stock_runtime` suppresses the error and cleanup still claims to have restored the launcher. Check the critical install, enable, home-selection, and launch operations so setup failures cannot leave the device without a usable home.</comment>
<file context>
@@ -0,0 +1,478 @@
+ "${ADB[@]}" shell cmd package install-existing "$STOCK_PKG" >/dev/null 2>&1 || true
+ "${ADB[@]}" shell pm enable "$STOCK_PKG" >/dev/null 2>&1 || true
+ "${ADB[@]}" shell pm clear-package-preferred-activities "$STOCK_PKG" >/dev/null 2>&1 || true
+ "${ADB[@]}" shell cmd package set-home-activity --user 0 "$STOCK_COMPONENT" >/dev/null 2>&1 || true
+ "${ADB[@]}" shell am start -n "$STOCK_COMPONENT" >/dev/null 2>&1 || true
+}
</file context>
| if [ "$elapsed" -ge 45 ] && [ "$saw_disconnect" = false ] && [ "$resent_reboot" = false ]; then | ||
| echo "The first reboot was not observed; sending one explicit ADB reboot." | ||
| "${ADB[@]}" reboot >/dev/null 2>&1 || true | ||
| resent_reboot=true |
There was a problem hiding this comment.
P2: When ADB stays online and the boot ID never changes, this retry leaves the loop with no later timeout or failure path, so setup can hang forever. Add a bounded post-retry timeout that calls fail and lets cleanup restore stock.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/update-stock-for-dev.sh, line 199:
<comment>When ADB stays online and the boot ID never changes, this retry leaves the loop with no later timeout or failure path, so setup can hang forever. Add a bounded post-retry timeout that calls `fail` and lets cleanup restore stock.</comment>
<file context>
@@ -0,0 +1,478 @@
+ if [ "$elapsed" -ge 45 ] && [ "$saw_disconnect" = false ] && [ "$resent_reboot" = false ]; then
+ echo "The first reboot was not observed; sending one explicit ADB reboot."
+ "${ADB[@]}" reboot >/dev/null 2>&1 || true
+ resent_reboot=true
+ start_time="$(date +%s)"
+ sleep 2
</file context>
| echo "Setup failed; restoring the stock launcher..." >&2 | ||
| "${ADB[@]}" shell cmd package install-existing "$STOCK_PKG" >/dev/null 2>&1 || true | ||
| "${ADB[@]}" shell pm enable "$STOCK_PKG" >/dev/null 2>&1 || true | ||
| "${ADB[@]}" shell pm enable "$RECOVERY_PKG" >/dev/null 2>&1 || true |
There was a problem hiding this comment.
P2: If setup fails after the recovery-agent step, the failure handler leaves LEGACY_UPDATER_PKG disabled while restoring stock. Re-enable the legacy updater alongside RECOVERY_PKG so stock recovery remains complete.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/dev-setup.sh, line 77:
<comment>If setup fails after the recovery-agent step, the failure handler leaves `LEGACY_UPDATER_PKG` disabled while restoring stock. Re-enable the legacy updater alongside `RECOVERY_PKG` so stock recovery remains complete.</comment>
<file context>
@@ -52,24 +61,38 @@ echo ""
+ echo "Setup failed; restoring the stock launcher..." >&2
+ "${ADB[@]}" shell cmd package install-existing "$STOCK_PKG" >/dev/null 2>&1 || true
+ "${ADB[@]}" shell pm enable "$STOCK_PKG" >/dev/null 2>&1 || true
+ "${ADB[@]}" shell pm enable "$RECOVERY_PKG" >/dev/null 2>&1 || true
+ "${ADB[@]}" shell cmd package set-home-activity --user 0 \
+ "$STOCK_PKG/com.mentra.asg_client.MainActivity" >/dev/null 2>&1 || true
</file context>
| "${ADB[@]}" shell pm enable "$RECOVERY_PKG" >/dev/null 2>&1 || true | |
| "${ADB[@]}" shell pm enable "$RECOVERY_PKG" >/dev/null 2>&1 || true | |
| "${ADB[@]}" shell pm enable "$LEGACY_UPDATER_PKG" >/dev/null 2>&1 || true |
| ADB_SERIAL="$SERIAL" "$SCRIPT_DIR/update-stock-for-dev.sh" | ||
| SETUP_MUTATED=true |
There was a problem hiding this comment.
P2: When the firmware updater fails after mutating the device while ADB is offline, this flag is still false, so the parent trap skips its restore/reconnect guidance. Mark setup as mutable before invoking the updater, or propagate the child’s mutation state.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/dev-setup.sh, line 117:
<comment>When the firmware updater fails after mutating the device while ADB is offline, this flag is still false, so the parent trap skips its restore/reconnect guidance. Mark setup as mutable before invoking the updater, or propagate the child’s mutation state.</comment>
<file context>
@@ -88,25 +111,36 @@ fi
+# Step 2: Put the stock firmware on a known-compatible staging baseline.
+echo "=== Updating Mentra Live Firmware ==="
+echo ""
+ADB_SERIAL="$SERIAL" "$SCRIPT_DIR/update-stock-for-dev.sh"
+SETUP_MUTATED=true
+
</file context>
| ADB_SERIAL="$SERIAL" "$SCRIPT_DIR/update-stock-for-dev.sh" | |
| SETUP_MUTATED=true | |
| SETUP_MUTATED=true | |
| ADB_SERIAL="$SERIAL" "$SCRIPT_DIR/update-stock-for-dev.sh" |
| # | ||
|
|
||
| set -e | ||
| set -euo pipefail |
There was a problem hiding this comment.
P2: When the optional version or OTA JSON grep finds no match, set -o pipefail propagates that status and set -e aborts restoration after stock may already be partially re-enabled. Guard these probes or handle their status explicitly so a missing optional field skips the update path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/dev-setup.sh, line 20:
<comment>When the optional version or OTA JSON `grep` finds no match, `set -o pipefail` propagates that status and `set -e` aborts restoration after stock may already be partially re-enabled. Guard these probes or handle their status explicitly so a missing optional field skips the update path.</comment>
<file context>
@@ -16,17 +17,25 @@
#
-set -e
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
</file context>
| if [ "${3:-}" = "--no-follow" ]; then | ||
| FOLLOW_LOGS=false | ||
| elif [ -n "${3:-}" ]; then | ||
| echo "Unknown option: $3" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
P3: When a caller supplies --no-follow plus an extra argument, this parser silently accepts the typo and runs the OTA. Reject any nonempty fourth argument instead of ignoring it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At asg_client/scripts/test-bes-ota.sh, line 16:
<comment>When a caller supplies `--no-follow` plus an extra argument, this parser silently accepts the typo and runs the OTA. Reject any nonempty fourth argument instead of ignoring it.</comment>
<file context>
@@ -11,9 +11,17 @@ set -euo pipefail
TARGET_VERSION="${2:-}"
+FOLLOW_LOGS=true
+
+if [ "${3:-}" = "--no-follow" ]; then
+ FOLLOW_LOGS=false
+elif [ -n "${3:-}" ]; then
</file context>
| if [ "${3:-}" = "--no-follow" ]; then | |
| FOLLOW_LOGS=false | |
| elif [ -n "${3:-}" ]; then | |
| echo "Unknown option: $3" | |
| exit 1 | |
| fi | |
| if [ -n "${4:-}" ]; then | |
| echo "Unknown option: $4" | |
| exit 1 | |
| elif [ "${3:-}" = "--no-follow" ]; then | |
| FOLLOW_LOGS=false | |
| elif [ -n "${3:-}" ]; then | |
| echo "Unknown option: $3" | |
| exit 1 | |
| fi |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 45507bf. Configure here.
| enable_thirdparty_runtime | ||
| echo "$DEV_PKG is active again; its APK and app data were preserved." | ||
| fi | ||
|
|
There was a problem hiding this comment.
Resume handoff undoes firmware success
Medium Severity
SUCCESS is set only after enable_thirdparty_runtime, so a failed am start or HOME resolve check during the resume handoff still runs restore_safe_stock_on_failure. That rolls a completed ASG/BES/MTK update back to stock and re-enables recovery, leaving the developer off their third-party launcher even though firmware already landed. Unlike enable_stock_runtime, the handoff treats am start as fatal, and the restore path never disables DEV_PKG after a partial switch.
Additional Locations (2)
Triggered by project rule: Bugbot rules for MentraOS
Reviewed by Cursor Bugbot for commit 45507bf. Configure here.


Summary
test-bes-ota.shstage both the ASG 36 fixed path and the current hash-addressed pathupdate-mentra-live.shfor devices already running thedev-setup.shcustom client; it preserves that APK and its data, services firmware through signed stock ASG, then verifies and restores the custom HOME activityValidation
bash -n asg_client/scripts/*.shgit diff --check origin/dev...HEADcom.mentra.asg_client, versionName36.0, versionCode99999999, and verified its pinned size/SHA-256Hardware test required
Not run locally because no Mentra Live is attached. Before merging, exercise:
com.mentra.asg_client.thirdparty; runupdate-mentra-live.shand confirm the same APK/data and custom HOME return after firmware verification.Note
High Risk
These scripts flash ASG, BES, and MTK firmware on physical glasses, including a signed bridge APK and reboot/recovery handling. A bug can brick or leave devices on the wrong launcher.
Overview
dev-setup.shnow brings Mentra Live to a pinned staging firmware baseline before installing the third-party client. It snapshots the rolling staging OTA manifest once, SHA-256-verifies ASG/BES/MTK artifacts, then applies them through a signed ASG 36 BES bridge, staging ASG, and the exact MTK patch chain (no downgrades).update-mentra-live.shreuses that flow with--resume-thirdparty: it temporarily enables stock ASG for BES/MTK updates, then restores the existing third-party APK and data after verifying transitions. Failures restore a stock launcher and recovery; recovery/legacy updater packages stay disabled while the custom client is HOME.OTA helpers now support the ASG 36 legacy BES path,
--no-follow,ADB_SERIAL, and reboot wait with a 45s Infinity Cable reconnect prompt. README documents the new setup and firmware-update paths.Reviewed by Cursor Bugbot for commit 45507bf. Bugbot is set up for automated code reviews on this repo. Configure here.