Skip to content

Commit 9b4aa0b

Browse files
committed
Simplify Android boot path in session handler
1 parent 1389737 commit 9b4aa0b

4 files changed

Lines changed: 7 additions & 153 deletions

File tree

src/daemon/handlers/__tests__/session.test.ts

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,6 @@ test('boot --headless launches Android emulator when no running device matches',
391391
resolveTargetDevice: async () => {
392392
throw new AppError('DEVICE_NOT_FOUND', 'No devices found');
393393
},
394-
resolveAndroidBootSelectorDevice: async () => undefined,
395394
ensureAndroidEmulatorBoot: async ({ avdName, serial, headless }) => {
396395
launchCalls.push({ avdName, serial, headless });
397396
return {
@@ -435,7 +434,6 @@ test('boot launches Android emulator with GUI when no running device matches', a
435434
resolveTargetDevice: async () => {
436435
throw new AppError('DEVICE_NOT_FOUND', 'No devices found');
437436
},
438-
resolveAndroidBootSelectorDevice: async () => undefined,
439437
ensureAndroidEmulatorBoot: async ({ avdName, serial, headless }) => {
440438
launchCalls.push({ avdName, serial, headless });
441439
return {
@@ -478,7 +476,6 @@ test('boot --headless requires avd selector when device cannot be resolved', asy
478476
resolveTargetDevice: async () => {
479477
throw new AppError('DEVICE_NOT_FOUND', 'No devices found');
480478
},
481-
resolveAndroidBootSelectorDevice: async () => undefined,
482479
ensureAndroidEmulatorBoot: async () => {
483480
bootCalled = true;
484481
throw new Error('unexpected');
@@ -494,45 +491,6 @@ test('boot --headless requires avd selector when device cannot be resolved', asy
494491
}
495492
});
496493

497-
test('boot uses fast Android selector lookup for already booted device', async () => {
498-
const sessionStore = makeSessionStore();
499-
let ensureCalls = 0;
500-
const response = await handleSessionCommands({
501-
req: {
502-
token: 't',
503-
session: 'default',
504-
command: 'boot',
505-
positionals: [],
506-
flags: { platform: 'android', device: 'Pixel 9 Pro XL' },
507-
},
508-
sessionName: 'default',
509-
logPath: path.join(os.tmpdir(), 'daemon.log'),
510-
sessionStore,
511-
invoke: noopInvoke,
512-
ensureReady: async () => {
513-
ensureCalls += 1;
514-
},
515-
resolveTargetDevice: async () => {
516-
throw new Error('resolveTargetDevice should not be called when fast lookup succeeds');
517-
},
518-
resolveAndroidBootSelectorDevice: async () => ({
519-
platform: 'android',
520-
id: 'emulator-5554',
521-
name: 'Pixel 9 Pro XL',
522-
kind: 'emulator',
523-
target: 'mobile',
524-
booted: true,
525-
}),
526-
});
527-
assert.ok(response);
528-
assert.equal(response?.ok, true);
529-
assert.equal(ensureCalls, 0);
530-
if (response && response.ok) {
531-
assert.equal(response.data?.platform, 'android');
532-
assert.equal(response.data?.id, 'emulator-5554');
533-
}
534-
});
535-
536494
test('appstate on iOS requires active session on selected device', async () => {
537495
const sessionStore = makeSessionStore();
538496
const sessionName = 'default';

src/daemon/handlers/session.ts

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,6 @@ type EnsureAndroidEmulatorBoot = (params: {
5454
headless?: boolean;
5555
}) => Promise<DeviceInfo>;
5656

57-
type ResolveAndroidBootSelectorDevice = (params: {
58-
deviceName?: string;
59-
serial?: string;
60-
includeTarget?: boolean;
61-
}) => Promise<DeviceInfo | undefined>;
62-
6357
const IOS_APPSTATE_SESSION_REQUIRED_MESSAGE =
6458
'iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).';
6559
const BATCH_PARENT_FLAG_KEYS: Array<keyof CommandFlags> = ['platform', 'target', 'device', 'udid', 'serial', 'verbose', 'out'];
@@ -259,11 +253,6 @@ const defaultEnsureAndroidEmulatorBoot: EnsureAndroidEmulatorBoot = async ({ avd
259253
return await ensureAndroidEmulatorBooted({ avdName, serial, headless });
260254
};
261255

262-
const defaultResolveAndroidBootSelectorDevice: ResolveAndroidBootSelectorDevice = async ({ deviceName, serial, includeTarget }) => {
263-
const { resolveAndroidBootSelectorDevice } = await import('../../platforms/android/devices.ts');
264-
return await resolveAndroidBootSelectorDevice({ deviceName, serial, includeTarget });
265-
};
266-
267256
const defaultReinstallOps: ReinstallOps = {
268257
ios: async (device, app, appPath) => {
269258
const { reinstallIosApp } = await import('../../platforms/ios/index.ts');
@@ -481,7 +470,6 @@ export async function handleSessionCommands(params: {
481470
stop: typeof stopAppLog;
482471
};
483472
ensureAndroidEmulatorBoot?: EnsureAndroidEmulatorBoot;
484-
resolveAndroidBootSelectorDevice?: ResolveAndroidBootSelectorDevice;
485473
resolveAndroidPackageForOpen?: (
486474
device: DeviceInfo,
487475
openTarget: string | undefined,
@@ -503,7 +491,6 @@ export async function handleSessionCommands(params: {
503491
stop: stopAppLog,
504492
},
505493
ensureAndroidEmulatorBoot: ensureAndroidEmulatorBootOverride = defaultEnsureAndroidEmulatorBoot,
506-
resolveAndroidBootSelectorDevice: resolveAndroidBootSelectorDeviceOverride = defaultResolveAndroidBootSelectorDevice,
507494
resolveAndroidPackageForOpen: resolveAndroidPackageForOpenOverride = resolveAndroidPackageForOpen,
508495
} = params;
509496
const dispatch = dispatchOverride ?? dispatchCommand;
@@ -600,34 +587,21 @@ export async function handleSessionCommands(params: {
600587
const normalizedPlatform = normalizePlatformSelector(flags.platform) ?? session?.device.platform;
601588
const targetsAndroid = normalizedPlatform === 'android';
602589
const wantsAndroidHeadless = flags.headless === true;
603-
const shouldUseFastAndroidSelectorLookup = targetsAndroid && Boolean(flags.device || flags.serial);
604590
const fallbackAvdName = resolveAndroidEmulatorAvdName({
605591
flags,
606592
sessionDevice: session?.device,
607593
});
608594
const canFallbackLaunchAndroidEmulator = targetsAndroid && Boolean(fallbackAvdName);
609595
let device: DeviceInfo;
610596
let launchedAndroidEmulator = false;
611-
const fastLookupDeviceCandidate = shouldUseFastAndroidSelectorLookup
612-
? await resolveAndroidBootSelectorDeviceOverride({
613-
deviceName: flags.device,
614-
serial: flags.serial,
615-
includeTarget: Boolean(flags.target),
616-
})
617-
: undefined;
618-
const targetMismatch = Boolean(flags.target)
619-
&& fastLookupDeviceCandidate
620-
&& (fastLookupDeviceCandidate.target ?? 'mobile') !== flags.target;
621-
const fastLookupDevice = targetMismatch ? undefined : fastLookupDeviceCandidate;
622597
try {
623-
device = fastLookupDevice
624-
?? (await resolveCommandDevice({
625-
session,
626-
flags,
627-
ensureReadyFn: ensureReady,
628-
resolveTargetDeviceFn: resolveDevice,
629-
ensureReady: false,
630-
}));
598+
device = await resolveCommandDevice({
599+
session,
600+
flags,
601+
ensureReadyFn: ensureReady,
602+
resolveTargetDeviceFn: resolveDevice,
603+
ensureReady: false,
604+
});
631605
} catch (error) {
632606
const appErr = asAppError(error);
633607
if (targetsAndroid && wantsAndroidHeadless && !fallbackAvdName && appErr.code === 'DEVICE_NOT_FOUND') {

src/platforms/android/__tests__/devices.test.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
parseAndroidAvdList,
99
parseAndroidFeatureListForTv,
1010
parseAndroidTargetFromCharacteristics,
11-
resolveAndroidBootSelectorDevice,
1211
resolveAndroidAvdName,
1312
} from '../devices.ts';
1413

@@ -181,24 +180,3 @@ test('ensureAndroidEmulatorBooted launches emulator with GUI by default', async
181180
assert.doesNotMatch(log, /-no-window/);
182181
});
183182
});
184-
185-
test('resolveAndroidBootSelectorDevice matches emulator by device name', async () => {
186-
await withMockedAndroidTools(async () => {
187-
await fs.writeFile(process.env.AGENT_DEVICE_TEST_EMU_BOOTED_FILE!, 'ready', 'utf8');
188-
const device = await resolveAndroidBootSelectorDevice({ deviceName: 'Pixel 9 Pro XL', includeTarget: true });
189-
assert.ok(device);
190-
assert.equal(device?.id, 'emulator-5554');
191-
assert.equal(device?.kind, 'emulator');
192-
assert.equal(device?.target, 'mobile');
193-
assert.equal(device?.booted, true);
194-
});
195-
});
196-
197-
test('resolveAndroidBootSelectorDevice matches by serial', async () => {
198-
await withMockedAndroidTools(async () => {
199-
await fs.writeFile(process.env.AGENT_DEVICE_TEST_EMU_BOOTED_FILE!, 'ready', 'utf8');
200-
const device = await resolveAndroidBootSelectorDevice({ serial: 'emulator-5554' });
201-
assert.ok(device);
202-
assert.equal(device?.id, 'emulator-5554');
203-
});
204-
});

src/platforms/android/devices.ts

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -187,62 +187,6 @@ async function listAndroidDeviceEntries(): Promise<AndroidDeviceEntry[]> {
187187
return parseAndroidDeviceEntries(result.stdout);
188188
}
189189

190-
export async function resolveAndroidBootSelectorDevice(params: {
191-
deviceName?: string;
192-
serial?: string;
193-
includeTarget?: boolean;
194-
}): Promise<DeviceInfo | undefined> {
195-
const adbAvailable = await whichCmd('adb');
196-
if (!adbAvailable) {
197-
throw new AppError('TOOL_MISSING', 'adb not found in PATH');
198-
}
199-
200-
const entries = await listAndroidDeviceEntries();
201-
if (entries.length === 0) return undefined;
202-
203-
const serialSelector = params.serial?.trim();
204-
const deviceNameSelector = params.deviceName?.trim();
205-
206-
let matched: AndroidDeviceEntry | undefined;
207-
let matchedName: string | undefined;
208-
209-
if (serialSelector) {
210-
matched = entries.find((entry) => entry.serial === serialSelector);
211-
if (!matched) return undefined;
212-
matchedName = await resolveAndroidDeviceName(matched.serial, matched.rawModel);
213-
} else if (deviceNameSelector) {
214-
const target = normalizeAndroidName(deviceNameSelector);
215-
for (const entry of entries) {
216-
const modelName = entry.rawModel.replace(/_/g, ' ').trim();
217-
if (normalizeAndroidName(modelName) === target) {
218-
matched = entry;
219-
matchedName = modelName || entry.serial;
220-
break;
221-
}
222-
const resolvedName = await resolveAndroidDeviceName(entry.serial, entry.rawModel);
223-
if (normalizeAndroidName(resolvedName) === target) {
224-
matched = entry;
225-
matchedName = resolvedName;
226-
break;
227-
}
228-
}
229-
} else {
230-
return undefined;
231-
}
232-
233-
if (!matched) return undefined;
234-
const booted = await isAndroidBooted(matched.serial);
235-
const target = params.includeTarget ? await resolveAndroidTarget(matched.serial) : undefined;
236-
return {
237-
platform: 'android',
238-
id: matched.serial,
239-
name: matchedName ?? (matched.rawModel.replace(/_/g, ' ').trim() || matched.serial),
240-
kind: isEmulatorSerial(matched.serial) ? 'emulator' : 'device',
241-
target,
242-
booted,
243-
};
244-
}
245-
246190
export function parseAndroidAvdList(rawOutput: string): string[] {
247191
return rawOutput
248192
.split('\n')

0 commit comments

Comments
 (0)