1import * as Log from '../../../log';
2import { installExitHooks } from '../../../utils/exit';
3import { adbArgs, Device, getAttachedDevicesAsync, getServer, logUnauthorized } from './adb';
4
5const debug = require('debug')('expo:start:platforms:android:adbReverse') as typeof console.log;
6
7let removeExitHook: (() => void) | null = null;
8
9export async function startAdbReverseAsync(ports: number[]): Promise<boolean> {
10  // Install cleanup automatically...
11  removeExitHook = installExitHooks(() => {
12    stopAdbReverseAsync(ports);
13  });
14
15  const devices = await getAttachedDevicesAsync();
16  for (const device of devices) {
17    for (const port of ports) {
18      if (!(await adbReverseAsync(device, port))) {
19        debug(`Failed to start reverse port ${port} on device "${device.name}"`);
20        return false;
21      }
22    }
23  }
24  return true;
25}
26
27export async function stopAdbReverseAsync(ports: number[]): Promise<void> {
28  removeExitHook?.();
29
30  const devices = await getAttachedDevicesAsync();
31  for (const device of devices) {
32    for (const port of ports) {
33      await adbReverseRemoveAsync(device, port);
34    }
35  }
36}
37
38async function adbReverseAsync(device: Device, port: number): Promise<boolean> {
39  if (!device.isAuthorized) {
40    logUnauthorized(device);
41    return false;
42  }
43
44  try {
45    await getServer().runAsync(adbArgs(device.pid, 'reverse', `tcp:${port}`, `tcp:${port}`));
46    return true;
47  } catch (error: any) {
48    Log.warn(`[ADB] Couldn't reverse port ${port}: ${error.message}`);
49    return false;
50  }
51}
52
53async function adbReverseRemoveAsync(device: Device, port: number): Promise<boolean> {
54  if (!device.isAuthorized) {
55    return false;
56  }
57
58  try {
59    await getServer().runAsync(adbArgs(device.pid, 'reverse', '--remove', `tcp:${port}`));
60    return true;
61  } catch (error: any) {
62    // Don't send this to warn because we call this preemptively sometimes
63    debug(`Could not unforward port ${port}: ${error.message}`);
64    return false;
65  }
66}
67