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
sc_adb_accept_device(const struct sc_adb_device *device, const char *serial) {
if (!serial) {
sc_adb_accept_device(const struct sc_adb_device *device,
const struct sc_adb_device_selector *selector) {
switch (selector->type) {
case SC_ADB_DEVICE_SELECT_ALL:
return true;
}
case SC_ADB_DEVICE_SELECT_SERIAL:
assert(selector->serial);
char *device_serial_colon = strchr(device->serial, ':');
if (device_serial_colon) {
// The device serial is an IP:port...
char *serial_colon = strchr(serial, ':');
char *serial_colon = strchr(selector->serial, ':');
if (!serial_colon) {
// But the requested serial has no ':', so only consider the IP part
// of the device serial. This allows to use "192.168.1.1" to match
// any "192.168.1.1:port".
size_t serial_len = strlen(serial);
// But the requested serial has no ':', so only consider
// the IP part of the device serial. This allows to use
// "192.168.1.1" to match any "192.168.1.1:port".
size_t serial_len = strlen(selector->serial);
size_t device_ip_len = device_serial_colon - device->serial;
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 !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
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;
for (size_t i = 0; i < len; ++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 (idx_out && !count) {
*idx_out = i;
@ -502,8 +512,9 @@ sc_adb_device_check_state(struct sc_adb_device *device,
}
bool
sc_adb_select_device(struct sc_intr *intr, const char *serial, unsigned flags,
struct sc_adb_device *out_device) {
sc_adb_select_device(struct sc_intr *intr,
const struct sc_adb_device_selector *selector,
unsigned flags, struct sc_adb_device *out_device) {
struct sc_adb_device devices[16];
ssize_t count =
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_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 count > 0 && sel_count == 0, then necessarily a serial is provided
assert(serial);
LOGE("Could not find ADB device %s", serial);
// if count > 0 && sel_count == 0, then necessarily a selection is
// requested
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_destroy_all(devices, count);
return false;
}
if (sel_count > 1) {
if (serial) {
LOGE("Multiple (%" SC_PRIsizet ") ADB devices with serial %s:",
sel_count, serial);
} else {
switch (selector->type) {
case SC_ADB_DEVICE_SELECT_ALL:
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);
LOGE("Select a device via -s (--serial)");

View file

@ -18,6 +18,16 @@
const char *
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_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.
*/
bool
sc_adb_select_device(struct sc_intr *intr, const char *serial, unsigned flags,
struct sc_adb_device *out_device);
sc_adb_select_device(struct sc_intr *intr,
const struct sc_adb_device_selector *selector,
unsigned flags, struct sc_adb_device *out_device);
/**
* Execute `adb getprop <prop>`

View file

@ -687,9 +687,15 @@ run_server(void *data) {
bool need_initial_serial = !params->tcpip_dst;
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;
ok = sc_adb_select_device(&server->intr, params->req_serial, 0,
&device);
ok = sc_adb_select_device(&server->intr, &selector, 0, &device);
if (!ok) {
goto error_connection_failed;
}