refactor(android): allow providers to install prepared app artifacts
Summary
Allow hosted Android artifact installers through shared deployment operations; preserve installer results and materialized package identity. Four files; extraction requested in #4174. Local ADB remains the default; no production provider switches here.
Related work
Independent siblings: lease lifecycle #4195, recordings #4196. Apple hooks follow this; native Limrun XCTest follows all layers to replace AX.
Validation
Tested 4d65affa7cddbb7ad0a3340a4dc36c12b9c13aea, base a2c169fa502a53f1f2a1da25b1cd16b9c731af39. pnpm check:affected --run --base <base> --head <head> passed (exactCommit:true, 17,144 unit tests; one skipped). Identity regressions fail without fixes.
Live device: emulator-5588, Android 16 Google Play ARM64, SDK 36.1. Built SDK calls routed through the daemon:
import {createAgentDeviceClient} from './dist/src/index.js';
const root = '/private/tmp/agent-device-review2/android-live';
const client = createAgentDeviceClient({session: 'android-installer-review4194', stateDir: `${root}/state`, debug: true});
const target = {platform: 'android', serial: 'emulator-5588'};
const app = 'com.agentdevice.installerreview';
await client.apps.install({...target, appPath: `${root}/fixtures/v1/installer-review.apk`});
await client.apps.open({...target, app});
await client.apps.reinstall({...target, app, appPath: `${root}/fixtures/v2/installer-review.apk`});
await client.apps.open({...target, app});
await client.apps.installFromSource({...target, source: {kind: 'path', path: `${root}/fixtures/source-v3.zip`}});
await client.apps.open({...target, app});
Observed outputs:
| Operation | Result |
|---|---|
| Path | appId=package=com.agentdevice.installerreview; versionCode=1; MainActivity resumed. |
| Reinstall | versionCode=2; adb -s emulator-5588 shell run-as com.agentdevice.installerreview ls files/pre-reinstall-marker changed from present to No such file or directory. |
| ZIP | appId=packageName=launchTarget=com.agentdevice.installerreview; versionCode=3; extracted directory removed; source ZIP/data preserved. |
Each snapshot -i --json showed its version title and androidSnapshot={backend:"android-helper",helperVersion:"0.21.37-dev"}, matching package.json. Session/daemon/emulator cleanup passed. Complete commands/outputs, reproduction.
Independent review passed. GitHub owns remaining device/coverage/provider checks; Vercel requires maintainer authorization.
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.