adb: Generalizing -s to take qualifiers.
Prior to this change, -s could take either a serial number or a
device path (e.g. "-s 01498B1F02015015" or "-s usb:1-4.2"). This
change extends -s to also allow product, model or device names
(e.g. "-s product:mysid"). These new qualifiers will only be
available on devices that are running an adb daemon that provides
properties in the connect message per Change-Id:
I09200decde4facb8fc9b4056fdae910155f2bcb9
The product, model and device are derived from the
ro.product.name, ro.product.model and ro.product.device
properties respectively. They are prefixed with "product:",
"model:" or "device:" as appropriate. In addition, any
non-alphanumerics in the model are changed to underscores.
If the -s parameter matches multiple devices, the result will be
the same as when multiple devices are connected but no -d, -e or
-s option is specified. In general, this means the user will get
"error: more than one device". However for get-state,
get-devpath and get-serialno, they will get "unknown".
The format of "devices -l" was changed to list all of the
qualifiers that are available. The following example output
(with the last digits of the serial numbers replaced with X's) is
with a Galaxy Prime with an older adb daemon and another Galaxy
Prime and Galaxy S both with the enhanced adb daemons:
List of devices attached
016B75D60A0060XX device usb:2-5 product:mysid model:Galaxy_Nexus device:toro
3731B535FAC200XX device usb:1-4.2 product:soju model:Nexus_S device:crespo
01498B1F020150XX device usb:1-4.1
Note that the serial number and state are now column oriented
instead of tab delimited. After the serial number and state, all
qualifiers are listed with each preceded by a space. The output
of the original devices command (without -l) is unchanged.
Change-Id: Iceeb2789874effc25a630d514a375d6f1889dc56
Signed-off-by: Scott Anderson <saa@android.com>
This commit is contained in:
parent
e82c2db05c
commit
2ca3e6b35f
5 changed files with 126 additions and 27 deletions
|
|
@ -289,9 +289,7 @@ static char *connection_state_name(atransport *t)
|
||||||
|
|
||||||
/* qual_overwrite is used to overwrite a qualifier string. dst is a
|
/* qual_overwrite is used to overwrite a qualifier string. dst is a
|
||||||
* pointer to a char pointer. It is assumed that if *dst is non-NULL, it
|
* pointer to a char pointer. It is assumed that if *dst is non-NULL, it
|
||||||
* was malloc'ed and needs to freed. A char buffer will be malloc'ed and
|
* was malloc'ed and needs to freed. *dst will be set to a dup of src.
|
||||||
* filled with src and *dst will be set to
|
|
||||||
* point to the buffer.
|
|
||||||
*/
|
*/
|
||||||
static void qual_overwrite(char **dst, const char *src)
|
static void qual_overwrite(char **dst, const char *src)
|
||||||
{
|
{
|
||||||
|
|
@ -311,7 +309,8 @@ void parse_banner(char *banner, atransport *t)
|
||||||
{
|
{
|
||||||
static const char *prop_seps = ";";
|
static const char *prop_seps = ";";
|
||||||
static const char key_val_sep = '=';
|
static const char key_val_sep = '=';
|
||||||
char *cp, *type;
|
char *cp;
|
||||||
|
char *type;
|
||||||
|
|
||||||
D("parse_banner: %s\n", banner);
|
D("parse_banner: %s\n", banner);
|
||||||
type = banner;
|
type = banner;
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ int adb_main(int is_daemon, int server_port);
|
||||||
** get_device_transport does an acquire on your behalf before returning
|
** get_device_transport does an acquire on your behalf before returning
|
||||||
*/
|
*/
|
||||||
void init_transport_registration(void);
|
void init_transport_registration(void);
|
||||||
int list_transports(char *buf, size_t bufsize, int show_devpath);
|
int list_transports(char *buf, size_t bufsize, int long_listing);
|
||||||
void update_transports(void);
|
void update_transports(void);
|
||||||
|
|
||||||
asocket* create_device_tracker(void);
|
asocket* create_device_tracker(void);
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ void help()
|
||||||
" -e - directs command to the only running emulator.\n"
|
" -e - directs command to the only running emulator.\n"
|
||||||
" returns an error if more than one emulator is running.\n"
|
" returns an error if more than one emulator is running.\n"
|
||||||
" -s <specific device> - directs command to the device or emulator with the given\n"
|
" -s <specific device> - directs command to the device or emulator with the given\n"
|
||||||
" serial number or device path. Overrides ANDROID_SERIAL\n"
|
" serial number or qualifier. Overrides ANDROID_SERIAL\n"
|
||||||
" environment variable.\n"
|
" environment variable.\n"
|
||||||
" -p <product name or path> - simple product name like 'sooner', or\n"
|
" -p <product name or path> - simple product name like 'sooner', or\n"
|
||||||
" a relative/absolute path to a product\n"
|
" a relative/absolute path to a product\n"
|
||||||
|
|
@ -94,7 +94,7 @@ void help()
|
||||||
" environment variable is used, which must\n"
|
" environment variable is used, which must\n"
|
||||||
" be an absolute path.\n"
|
" be an absolute path.\n"
|
||||||
" devices [-l] - list all connected devices\n"
|
" devices [-l] - list all connected devices\n"
|
||||||
" ('-l' means list device paths)\n"
|
" ('-l' will also list device qualifiers)\n"
|
||||||
" connect <host>[:<port>] - connect to a device via TCP/IP\n"
|
" connect <host>[:<port>] - connect to a device via TCP/IP\n"
|
||||||
" Port 5555 is used by default if no port number is specified.\n"
|
" Port 5555 is used by default if no port number is specified.\n"
|
||||||
" disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n"
|
" disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n"
|
||||||
|
|
|
||||||
|
|
@ -591,15 +591,29 @@ unsigned unhex(unsigned char *s, int len)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PREFIX(str) { str, sizeof(str) - 1 }
|
||||||
|
static const struct prefix_struct {
|
||||||
|
const char *str;
|
||||||
|
const size_t len;
|
||||||
|
} prefixes[] = {
|
||||||
|
PREFIX("usb:"),
|
||||||
|
PREFIX("product:"),
|
||||||
|
PREFIX("model:"),
|
||||||
|
PREFIX("device:"),
|
||||||
|
};
|
||||||
|
static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
|
||||||
|
|
||||||
/* skip_host_serial return the position in a string
|
/* skip_host_serial return the position in a string
|
||||||
skipping over the 'serial' parameter in the ADB protocol,
|
skipping over the 'serial' parameter in the ADB protocol,
|
||||||
where parameter string may be a host:port string containing
|
where parameter string may be a host:port string containing
|
||||||
the protocol delimiter (colon). */
|
the protocol delimiter (colon). */
|
||||||
char *skip_host_serial(char *service) {
|
char *skip_host_serial(char *service) {
|
||||||
char *first_colon, *serial_end;
|
char *first_colon, *serial_end;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!strncmp(service, "usb:", 4)) {
|
for (i = 0; i < num_prefixes; i++) {
|
||||||
return strchr(service + 4, ':');
|
if (!strncmp(service, prefixes[i].str, prefixes[i].len))
|
||||||
|
return strchr(service + prefixes[i].len, ':');
|
||||||
}
|
}
|
||||||
|
|
||||||
first_colon = strchr(service, ':');
|
first_colon = strchr(service, ':');
|
||||||
|
|
|
||||||
122
adb/transport.c
122
adb/transport.c
|
|
@ -743,6 +743,45 @@ void remove_transport_disconnect(atransport* t, adisconnect* dis)
|
||||||
dis->next = dis->prev = dis;
|
dis->next = dis->prev = dis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qual_char_is_invalid(char ch)
|
||||||
|
{
|
||||||
|
if ('A' <= ch && ch <= 'Z')
|
||||||
|
return 0;
|
||||||
|
if ('a' <= ch && ch <= 'z')
|
||||||
|
return 0;
|
||||||
|
if ('0' <= ch && ch <= '9')
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qual_match(const char *to_test,
|
||||||
|
const char *prefix, const char *qual, int sanitize_qual)
|
||||||
|
{
|
||||||
|
if (!to_test || !*to_test)
|
||||||
|
/* Return true if both the qual and to_test are null strings. */
|
||||||
|
return !qual || !*qual;
|
||||||
|
|
||||||
|
if (!qual)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (prefix) {
|
||||||
|
while (*prefix) {
|
||||||
|
if (*prefix++ != *to_test++)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*qual) {
|
||||||
|
char ch = *qual++;
|
||||||
|
if (sanitize_qual && qual_char_is_invalid(ch))
|
||||||
|
ch = '_';
|
||||||
|
if (ch != *to_test++)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Everything matched so far. Return true if *to_test is a NUL. */
|
||||||
|
return !*to_test;
|
||||||
|
}
|
||||||
|
|
||||||
atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
|
atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
|
||||||
{
|
{
|
||||||
|
|
@ -764,13 +803,19 @@ retry:
|
||||||
|
|
||||||
/* check for matching serial number */
|
/* check for matching serial number */
|
||||||
if (serial) {
|
if (serial) {
|
||||||
if (t->serial && !strcmp(serial, t->serial)) {
|
if ((t->serial && !strcmp(serial, t->serial)) ||
|
||||||
|
(t->devpath && !strcmp(serial, t->devpath)) ||
|
||||||
|
qual_match(serial, "product:", t->product, 0) ||
|
||||||
|
qual_match(serial, "model:", t->model, 1) ||
|
||||||
|
qual_match(serial, "device:", t->device, 0)) {
|
||||||
|
if (result) {
|
||||||
|
if (error_out)
|
||||||
|
*error_out = "more than one device";
|
||||||
|
ambiguous = 1;
|
||||||
|
result = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
result = t;
|
result = t;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (t->devpath && !strcmp(serial, t->devpath)) {
|
|
||||||
result = t;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ttype == kTransportUsb && t->type == kTransportUsb) {
|
if (ttype == kTransportUsb && t->type == kTransportUsb) {
|
||||||
|
|
@ -846,7 +891,58 @@ static const char *statename(atransport *t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int list_transports(char *buf, size_t bufsize, int show_devpath)
|
static void add_qual(char **buf, size_t *buf_size,
|
||||||
|
const char *prefix, const char *qual, int sanitize_qual)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
int prefix_len;
|
||||||
|
|
||||||
|
if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
|
||||||
|
return;
|
||||||
|
|
||||||
|
len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
|
||||||
|
|
||||||
|
if (sanitize_qual) {
|
||||||
|
char *cp;
|
||||||
|
for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
|
||||||
|
if (qual_char_is_invalid(*cp))
|
||||||
|
*cp = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf_size -= len;
|
||||||
|
*buf += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t format_transport(atransport *t, char *buf, size_t bufsize,
|
||||||
|
int long_listing)
|
||||||
|
{
|
||||||
|
const char* serial = t->serial;
|
||||||
|
if (!serial || !serial[0])
|
||||||
|
serial = "????????????";
|
||||||
|
|
||||||
|
if (!long_listing) {
|
||||||
|
return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
|
||||||
|
} else {
|
||||||
|
size_t len, remaining = bufsize;
|
||||||
|
|
||||||
|
len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
|
||||||
|
remaining -= len;
|
||||||
|
buf += len;
|
||||||
|
|
||||||
|
add_qual(&buf, &remaining, " ", t->devpath, 0);
|
||||||
|
add_qual(&buf, &remaining, " product:", t->product, 0);
|
||||||
|
add_qual(&buf, &remaining, " model:", t->model, 1);
|
||||||
|
add_qual(&buf, &remaining, " device:", t->device, 0);
|
||||||
|
|
||||||
|
len = snprintf(buf, remaining, "\n");
|
||||||
|
remaining -= len;
|
||||||
|
|
||||||
|
return bufsize - remaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int list_transports(char *buf, size_t bufsize, int long_listing)
|
||||||
{
|
{
|
||||||
char* p = buf;
|
char* p = buf;
|
||||||
char* end = buf + bufsize;
|
char* end = buf + bufsize;
|
||||||
|
|
@ -856,17 +952,7 @@ int list_transports(char *buf, size_t bufsize, int show_devpath)
|
||||||
/* XXX OVERRUN PROBLEMS XXX */
|
/* XXX OVERRUN PROBLEMS XXX */
|
||||||
adb_mutex_lock(&transport_lock);
|
adb_mutex_lock(&transport_lock);
|
||||||
for(t = transport_list.next; t != &transport_list; t = t->next) {
|
for(t = transport_list.next; t != &transport_list; t = t->next) {
|
||||||
const char* serial = t->serial;
|
len = format_transport(t, p, end - p, long_listing);
|
||||||
if (!serial || !serial[0])
|
|
||||||
serial = "????????????";
|
|
||||||
if (show_devpath) {
|
|
||||||
const char* devpath = t->devpath;
|
|
||||||
if (!devpath || !devpath[0])
|
|
||||||
devpath = "????????????";
|
|
||||||
len = snprintf(p, end - p, "%s\t%s\t%s\n", serial, devpath, statename(t));
|
|
||||||
} else
|
|
||||||
len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
|
|
||||||
|
|
||||||
if (p + len >= end) {
|
if (p + len >= end) {
|
||||||
/* discard last line if buffer is too short */
|
/* discard last line if buffer is too short */
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue