Skip to content

Story Android rehearsal

CANCELLED 2026-10-25 (owner). ~/.local/share/story-android (25 GB) and ~/.cache/story-android deleted; ~/.android (adb key) and ~/story-publisher kept. Rebuilding needs the SDK/AVD set up from scratch. Was: PAUSED 2026-10-16 (Facebook/Instagram). Flag ~/.config/social-paused; resume steps in content-pipeline "Social pause". Website notes keep publishing.

User-space Android tooling for Story publisher. Source repository /home/angel/story-publisher, branch sandbox (the branch cron runs; private remote github.com/EmbeddedEra/story-publisher, corrected 2026-10-14). SDK/JDK, AVD and Appium extension state live in ~/.local/share/story-android. Downloads live in ~/.cache/story-android. Owner-authenticated Google/Meta session state is retained only in the private AVD.

Dedicated API 35 AVD story_rehearsal_api35, 480×800, 1536 MiB explicit lowram, Intel host graphics, Vulkan disabled. rehearse_android.py creates only a transient user service story-android-rehearsal.service: 2300 MiB max, zero swap, 150% CPU, 256 tasks and a default 480-second hard deadline. --observe-seconds accepts 60–900 seconds (default240); the hard deadline adds240seconds. Foreground monitor adds an available-RAM start gate and abort floor. No timer or boot autostart exists.

start_appium.sh creates transient story-appium-rehearsal.service: 512 MiB, zero swap, 100% CPU and 600-second deadline. Appium listens on 127.0.0.1:4727; UiAutomator2 uses port 8299. Emulator serial/console port is emulator-5580. ADB's user daemon uses loopback 5037. Source android_env.sh for tool PATH; no global shell profile was modified.

If you change this

Keep production social queues and ownership untouched until the approved pilot. Recheck host available memory and the actual cgroup limits before every run. Do not silently raise caps: initial API 35 boots without lowram hit the cap. Stop only the two rehearsal units on failure. ADB may be shared by another Android task; check before killing its server. Runtime metrics and screenshots are ignored under the local source repository's runtime/ directory.

Added Android platform 35 build stubs and a local offline test APK, built with existing Java/aapt2/d8/zipalign/apksigner tools. The fixture has no requested permissions and no Internet access. It displays a packaged PNG, stores an HTTPS URL, persists it across app restart and forwards it to an internal Activity after a native click. This is not a provider upload or browser destination check.

Added the official Google Play API 35 revision 9 image and separate AVD story_playstore_api35. It uses the same resource limits and cannot run alongside the original profile on the shared port. Real Play Store version 41.3.25 resolves Instagram's market URI and reached the unauthenticated sign-in screen. No Google or Meta account was signed in. Existing EmbeddedEra accounts are the chosen test target; actual publications still require existing approval.

The Play image is not accepted for unattended operation at 1536 MiB: ADB was intermittently offline and guest lowmemorykiller killed a Google services process. Host cgroup OOM is distinct from guest pressure; the observed Play run did not hit host cgroup OOM. Prefer adequate host RAM/normal guest allocation before a production pilot; see the machine card's 32 GB recommendation and unverified module layout. Both profiles remain bounded, manually invoked development tests.

Normal-memory Play retry — 2026-09-22

After the owner stopped ERP sandbox, Play profile uses 2560 MiB guest RAM without lowram, 3584 MiB cgroup cap and 4600 MiB MemAvailable start gate. Original profile limits unchanged. Both retain zero host swap, 700 MiB sustained host abort floor and bounded automatic teardown. Source commit 2cdde2d.

The Play profile passed the offline media/URL/restart fixture and 18 consecutive ADB probes. Official Play Store 41.3.25 still requires Google sign-in; no account login, Meta app installation or publication performed. Background Android service reclamation was observed, so fixture success is not unattended social-app acceptance.

Phone account setup — 2026-09-22

~/android-login (also ~/.local/bin/android-login) starts transient story-android-login.service; stop and status subcommands are available. Procedure: SOP-041. Source: ~/story-publisher/android_login.py and browser_auth.py. Runtime: separate Xvfb :91, official scrcpy 4.1, x11vnc Unix socket only, noVNC 1.7.0/websockify 0.13.0 on 127.0.0.1:6089. No X/desktop sharing or TCP VNC. 4608 MiB/no swap, 150% CPU, 30 minutes, host start gate 5200 MiB; early cgroup and host memory guards. Shared AVD lock excludes rehearsals. No boot startup.

https://android.embeddedera.com/vnc.html routes through the plex tunnel with Administration-only Google Access app EmbeddedEra Android; onboard admin mapping includes it. cloudflared validates the app AUD and browser_auth verifies JWT signature/issuer/audience/expiry/email and websocket Origin. Private origin config: ~/.local/share/story-android/browser-access.json. Owner login state is retained in the AVD, never version controlled. No input/frame recording. User-space dependencies, checksums and local browser verification are documented in ~/story-publisher/docs/LOGIN.md. Google/Meta owner login is pending.

2026-09-22 owner Google Play login succeeded. Official Meta apps now installed via com.android.vending: Instagram448.0.0.52.84 and Facebook579.0.0.52.74. Native launches observed; Meta account authentication and Story capabilities remain unverified. Owner phone session remains bounded and no account input is recorded.

2026-09-22 evening: owner logged into Instagram; own professional embedded_era profile verified. Native Story menu exists; photos permission/media/link-sticker rehearsal remains pending. Facebook owner login is next. No posts or Story submissions.

2026-09-22 evening: Facebook owner login completed and active EmbeddedEra Page identity verified via native menu and Professional dashboard. Both Instagram/Facebook identities authenticated; login service stopped after verification, AVD retained. Session persistence across restart and clickable Story capability remain to be tested. No publication.

Native Story composition — 2026-09-22

Current headless Play profile: 2560MiB guest, 4096MiB cgroup cap, 4800MiB host start gate; zero swap, 700MiB sustained host floor and shared device lock retained. Browser login profile remains separately capped at4608MiB/start5200MiB. Both Meta sessions persisted across restart. Instagram's native Link sticker and Facebook Page Custom link accepted the website URL in unpublished test editors. Drafts discarded; emulator stopped. Facebook full image/video permission was revoked after testing; selected-photo permission remains. Technical results and limitations: ~/story-publisher/docs/META-REHEARSAL.md. This is not proof of a published link or unattended reliability. No real Story was submitted.

Draft-only driver — 2026-09-22

~/story-publisher/rehearse_meta.py --platform instagram|facebook --account NAME uses native ADB/UIAutomator with the separately supervised headless Play AVD. It holds runtime/meta-driver.lock, refuses a running phone viewer, verifies the known app version/own account/fixture, and stops at unpublished composition and discard. No new service, timer, listener or public repository. Temporary media permissions are restored and verified; camera/audio requests are denied. Per-run reports and editor screenshots stay in ignored private runtime/meta-rehearsals/. Final cold-boot composition/discard runs passed on both platforms; emulator is off. Source 4dce262; procedure/limits docs/META-REHEARSAL.md. No live publication.

2026-09-22 handoff check: rehearsal, browser login and Appium units all inactive. No runtime configuration changed during the memory/notes update. Public Story content rules and real-note pilot readiness belong in ../../../projects/story-publisher and ../../../projects/story-publisher-pilot; the fixed-fixture runner remains unchanged.

Real-note previews and session independence — 2026-09-23

The real-note draft mode and evidence belong in ../../../projects/story-publisher and ../../../projects/story-publisher-pilot. Runtime limits remain unchanged. Foreground tool monitor/driver processes received external SIGTERM during this session; the sender was not established. Temporary user units story-android-pilot-monitor, story-android-pilot-instagram and story-android-pilot-facebook completed the final drafts independently of the calling session. They are created on demand with systemd-run --collect, not installed/enabled services or timers. No boot autostart or publishing schedule.

Monitor:128MiB/no swap,64tasks,840-second hard limit; it runs the existing 600-second bounded Play observation, retaining the4096MiB emulator cap and 4800MiB start gate. Drivers:128MiB/no swap,64tasks,450-second limit and95-second stop allowance. The existing device lock still excludes concurrent drivers/viewers. SIGTERM handling and atomic private draft checkpoints preserve the original permission baseline for recovery. Procedure: story-publisher/docs/REAL-NOTE-PILOT.md.

Final drafts explicitly discarded; known fixture JPEG restored. Both apps' READ_MEDIA_IMAGES and READ_MEDIA_VIDEO were verified false before shutdown. Facebook began its final run with full grants true, so final cleanup explicitly restored the documented restricted baseline rather than claiming that was its starting state. Selected-photo grants were not changed. One earlier zero-byte interrupted media file was quarantined outside the gallery, not assumed valid art. Private evidence: story-publisher/runtime/pilot-2026-09-23/final-cleanup.json. Rehearsal/login/Appium units inactive and pilot units stopped/collected at handoff; host available5019MiB. No live Story was submitted.

Resized for 40 GiB host — 2026-09-25

Measured after the RAM upgrade (source 152e431, branch sandbox). Old Play profile sat on its 4096 MiB cap from 80 s and on the 150% CPU quota for ~2.5 min; guest had ~1.1 GB free. Current limits, all zero swap, 700 MiB host abort floor unchanged:

Profile Guest cgroup cap Start gate CPU Measured peak / boot
Play story_playstore_api35 4096 MiB 7168 MiB 8000 MiB 200% 6.1 GB / 24 s (was 35 s)
Plain story_rehearsal_api35 2560 MiB, no lowram 5120 MiB 5900 MiB 200% 4.3 GB / 24 s
Browser login 4096 MiB 7680 MiB (early guard 7300) 8500 MiB 200% not run; needs owner session

200% matches -cores 2; the guest stays CPU-bound for minutes after boot either way (Play services settling), so more CPU would need -cores 3 on a 4-thread host — not done. Guest am_kill counts (2-4 per run) persisted with 2 GB free: normal cached-process trimming, not a pressure signal. Earlier sections' numbers are history.

GPU check 2026-09-26: every run logs "Your GPU cannot be used for hardware rendering" yet the renderer is Mesa Intel HD Graphics 630 via gfxstream — the warning is cosmetic. A/B on the Play profile: -gpu host boot 24 s / peak 6.1 GB vs swiftshader_indirect boot 50 s / peak 7.2 GB (hit cap). Keep -gpu host; the post-boot CPU load is Play services, not rendering.

Quick-boot snapshot — 2026-09-26

Source story-publisher commit after 152e431 on sandbox. -no-snapshot removed from rehearse_android.py and android_login.py: the emulator saves default_boot on a graceful exit (adb emu kill, waited up to 90 s; unit TimeoutStopSec 90 / login 120) and resumes from it. Play AVD: resume 9 s vs 24 s cold, avg CPU 29% vs 86%; save ~8-10 s; snapshot 3.8 GB in .../story_playstore_api35.avd/snapshots/default_boot. Account/app state already persisted on disk, so behaviour is unchanged except running-app RAM state now carries over too. Fallbacks: a changed -memory/GPU/cores flag or a failed load means one cold boot; a hard kill skips the save and the next start resumes the older snapshot. Save briefly pushes the cgroup to ~7.0 GB of the 7168 cap (page cache, reclaimable). Login profile shares the same flags so the snapshot should load there too; not yet run with the owner. To force a clean cold start, delete the default_boot folder while the emulator is stopped.

Cron needs the user bus — 2026-09-27

The first unattended Story from cron failed: story-publish-due ran every 15 min from 09:15 with Could not start the bounded emulator: Failed to connect to bus: No medium found. Cron has no login session, so systemd-run --user had no XDG_RUNTIME_DIR / DBUS_SESSION_BUS_ADDRESS. Fixed in ~/.local/bin/story-publish-due (untracked file) with os.environ.setdefault to /run/user/<uid> and its bus. This works because Linger=yes keeps the user manager up. The 27 Sep Facebook Story was posted at 10:00 after the fix. Anything else started from cron that calls systemd-run --user or systemctl --user needs the same two variables.

2026-10-14 blocked slot and collision fixed

18:15 Instagram slot blocked on 'Expected screen not established: Profile' (4th time): wait_drawn returns on the first app window and the old four quick looks for 'Profile' gave up before the tab bar drew. 18:30 retry failed: monitor unit still active ('already loaded'). 18:40 hq-retry posted it (story 18478460029119045, ~35 min late). Fixed in story-publisher 222cddd: Profile waits up to APP_DRAW_SECONDS; a blocked untouched slot stops both rehearsal units; the settle wait checks the monitor unit too.