Introduce adb device selector

Currently, a device is selected either from a specific serial, or if it
is the only one connected.

In order to support selecting the only device connected via USB or via
TCP/IP separately, introduce a new selection structure.

PR #3005 <https://github.com/Genymobile/scrcpy/pull/3005>
This commit is contained in:
Romain Vimont 2022-02-06 16:06:46 +01:00
parent 5ed13ef477
commit 146f65d7b2
3 changed files with 85 additions and 38 deletions

View file

@ -424,39 +424,49 @@ sc_adb_list_devices(struct sc_intr *intr, unsigned flags,
} }
static bool static bool
sc_adb_accept_device(const struct sc_adb_device *device, const char *serial) { sc_adb_accept_device(const struct sc_adb_device *device,
if (!serial) { const struct sc_adb_device_selector *selector) {
switch (selector->type) {
case SC_ADB_DEVICE_SELECT_ALL:
return true; return true;
} case SC_ADB_DEVICE_SELECT_SERIAL:
assert(selector->serial);
char *device_serial_colon = strchr(device->serial, ':'); char *device_serial_colon = strchr(device->serial, ':');
if (device_serial_colon) { if (device_serial_colon) {
// The device serial is an IP:port... // The device serial is an IP:port...
char *serial_colon = strchr(serial, ':'); char *serial_colon = strchr(selector->serial, ':');
if (!serial_colon) { if (!serial_colon) {
// But the requested serial has no ':', so only consider the IP part // But the requested serial has no ':', so only consider
// of the device serial. This allows to use "192.168.1.1" to match // the IP part of the device serial. This allows to use
// any "192.168.1.1:port". // "192.168.1.1" to match any "192.168.1.1:port".
size_t serial_len = strlen(serial); size_t serial_len = strlen(selector->serial);
size_t device_ip_len = device_serial_colon - device->serial; size_t device_ip_len = device_serial_colon - device->serial;
if (serial_len != device_ip_len) { if (serial_len != device_ip_len) {
// They are not equal, they don't even have the same length // They are not equal, they don't even have the same
// length
return false; return false;
} }
return !strncmp(serial, device->serial, device_ip_len); return !strncmp(selector->serial, device->serial,
device_ip_len);
} }
} }
return !strcmp(selector->serial, device->serial);
default:
assert(!"Missing SC_ADB_DEVICE_SELECT_* handling");
break;
}
return !strcmp(serial, device->serial); return false;
} }
static size_t static size_t
sc_adb_devices_select(struct sc_adb_device *devices, size_t len, sc_adb_devices_select(struct sc_adb_device *devices, size_t len,
const char *serial, size_t *idx_out) { const struct sc_adb_device_selector *selector,
size_t *idx_out) {
size_t count = 0; size_t count = 0;
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
struct sc_adb_device *device = &devices[i]; struct sc_adb_device *device = &devices[i];
device->selected = sc_adb_accept_device(device, serial); device->selected = sc_adb_accept_device(device, selector);
if (device->selected) { if (device->selected) {
if (idx_out && !count) { if (idx_out && !count) {
*idx_out = i; *idx_out = i;
@ -502,8 +512,9 @@ sc_adb_device_check_state(struct sc_adb_device *device,
} }
bool bool
sc_adb_select_device(struct sc_intr *intr, const char *serial, unsigned flags, sc_adb_select_device(struct sc_intr *intr,
struct sc_adb_device *out_device) { const struct sc_adb_device_selector *selector,
unsigned flags, struct sc_adb_device *out_device) {
struct sc_adb_device devices[16]; struct sc_adb_device devices[16];
ssize_t count = ssize_t count =
sc_adb_list_devices(intr, flags, devices, ARRAY_LEN(devices)); sc_adb_list_devices(intr, flags, devices, ARRAY_LEN(devices));
@ -518,23 +529,42 @@ sc_adb_select_device(struct sc_intr *intr, const char *serial, unsigned flags,
} }
size_t sel_idx; // index of the single matching device if sel_count == 1 size_t sel_idx; // index of the single matching device if sel_count == 1
size_t sel_count = sc_adb_devices_select(devices, count, serial, &sel_idx); size_t sel_count =
sc_adb_devices_select(devices, count, selector, &sel_idx);
if (sel_count == 0) { if (sel_count == 0) {
// if count > 0 && sel_count == 0, then necessarily a serial is provided // if count > 0 && sel_count == 0, then necessarily a selection is
assert(serial); // requested
LOGE("Could not find ADB device %s", serial); assert(selector->type != SC_ADB_DEVICE_SELECT_ALL);
switch (selector->type) {
case SC_ADB_DEVICE_SELECT_SERIAL:
assert(selector->serial);
LOGE("Could not find ADB device %s:", selector->serial);
break;
default:
assert(!"Unexpected selector type");
break;
}
sc_adb_devices_log(SC_LOG_LEVEL_ERROR, devices, count); sc_adb_devices_log(SC_LOG_LEVEL_ERROR, devices, count);
sc_adb_devices_destroy_all(devices, count); sc_adb_devices_destroy_all(devices, count);
return false; return false;
} }
if (sel_count > 1) { if (sel_count > 1) {
if (serial) { switch (selector->type) {
LOGE("Multiple (%" SC_PRIsizet ") ADB devices with serial %s:", case SC_ADB_DEVICE_SELECT_ALL:
sel_count, serial);
} else {
LOGE("Multiple (%" SC_PRIsizet ") ADB devices:", sel_count); LOGE("Multiple (%" SC_PRIsizet ") ADB devices:", sel_count);
break;
case SC_ADB_DEVICE_SELECT_SERIAL:
assert(selector->serial);
LOGE("Multiple (%" SC_PRIsizet ") ADB devices with serial %s:",
sel_count, selector->serial);
break;
default:
assert(!"Unexpected selector type");
break;
} }
sc_adb_devices_log(SC_LOG_LEVEL_ERROR, devices, count); sc_adb_devices_log(SC_LOG_LEVEL_ERROR, devices, count);
LOGE("Select a device via -s (--serial)"); LOGE("Select a device via -s (--serial)");

View file

@ -18,6 +18,16 @@
const char * const char *
sc_adb_get_executable(void); sc_adb_get_executable(void);
enum sc_adb_device_selector_type {
SC_ADB_DEVICE_SELECT_ALL,
SC_ADB_DEVICE_SELECT_SERIAL,
};
struct sc_adb_device_selector {
enum sc_adb_device_selector_type type;
const char *serial;
};
sc_pid sc_pid
sc_adb_execute(const char *const argv[], unsigned flags); sc_adb_execute(const char *const argv[], unsigned flags);
@ -79,8 +89,9 @@ sc_adb_disconnect(struct sc_intr *intr, const char *ip_port, unsigned flags);
* Return true if a single matching device is found, and write it to out_device. * Return true if a single matching device is found, and write it to out_device.
*/ */
bool bool
sc_adb_select_device(struct sc_intr *intr, const char *serial, unsigned flags, sc_adb_select_device(struct sc_intr *intr,
struct sc_adb_device *out_device); const struct sc_adb_device_selector *selector,
unsigned flags, struct sc_adb_device *out_device);
/** /**
* Execute `adb getprop <prop>` * Execute `adb getprop <prop>`

View file

@ -687,9 +687,15 @@ run_server(void *data) {
bool need_initial_serial = !params->tcpip_dst; bool need_initial_serial = !params->tcpip_dst;
if (need_initial_serial) { if (need_initial_serial) {
struct sc_adb_device_selector selector;
if (params->req_serial) {
selector.type = SC_ADB_DEVICE_SELECT_SERIAL;
selector.serial = params->req_serial;
} else {
selector.type = SC_ADB_DEVICE_SELECT_ALL;
}
struct sc_adb_device device; struct sc_adb_device device;
ok = sc_adb_select_device(&server->intr, params->req_serial, 0, ok = sc_adb_select_device(&server->intr, &selector, 0, &device);
&device);
if (!ok) { if (!ok) {
goto error_connection_failed; goto error_connection_failed;
} }