From e82c2db05cae70a0490a1f84b7211ef42c329671 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Fri, 25 May 2012 14:10:02 -0700 Subject: [PATCH] adb: Transmit key properties in banner of connect message protocol.txt says that the connect message should have three fields: :: In reality, what is transmitted is simply: :: The serialno is obtained via other means so doesn't really need to be a part of the connect message. This change puts the ro.product.name, ro.product.model and ro.product.device properties in the for devices. Each property is terminated by a semicolon (;) with the key and value separated by an equals sign (=). Example message: device::ro.product.name=;ro.product.model=;ro.product.device=; Making this change will enable the device list to provide more information to the user and to give the potential for being able to select which device to talk to with the -s option. Change-Id: I09200decde4facb8fc9b4056fdae910155f2bcb9 Signed-off-by: Scott Anderson --- adb/adb.c | 103 +++++++++++++++++++++++++++++++++++++---------- adb/adb.h | 2 + adb/protocol.txt | 2 +- adb/transport.c | 4 ++ 4 files changed, 89 insertions(+), 22 deletions(-) diff --git a/adb/adb.c b/adb/adb.c index 8c82a0c88..ebf7a7ed1 100644 --- a/adb/adb.c +++ b/adb/adb.c @@ -29,6 +29,8 @@ #include "sysdeps.h" #include "adb.h" +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + #if !ADB_HOST #include #include @@ -43,7 +45,9 @@ ADB_MUTEX_DEFINE( D_lock ); int HOST = 0; +#if !ADB_HOST static const char *adb_device_banner = "device"; +#endif void fatal(const char *fmt, ...) { @@ -218,6 +222,36 @@ static void send_close(unsigned local, unsigned remote, atransport *t) send_packet(p, t); } +static size_t fill_connect_data(char *buf, size_t bufsize) +{ +#if ADB_HOST + return snprintf(buf, bufsize, "host::") + 1; +#else + static const char *cnxn_props[] = { + "ro.product.name", + "ro.product.model", + "ro.product.device", + }; + static const int num_cnxn_props = ARRAY_SIZE(cnxn_props); + int i; + size_t remaining = bufsize; + size_t len; + + len = snprintf(buf, remaining, "%s::", adb_device_banner); + remaining -= len; + buf += len; + for (i = 0; i < num_cnxn_props; i++) { + char value[PROPERTY_VALUE_MAX]; + property_get(cnxn_props[i], value, ""); + len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value); + remaining -= len; + buf += len; + } + + return bufsize - remaining + 1; +#endif +} + static void send_connect(atransport *t) { D("Calling send_connect \n"); @@ -225,9 +259,8 @@ static void send_connect(atransport *t) cp->msg.command = A_CNXN; cp->msg.arg0 = A_VERSION; cp->msg.arg1 = MAX_PAYLOAD; - snprintf((char*) cp->data, sizeof cp->data, "%s::", - HOST ? "host" : adb_device_banner); - cp->msg.data_length = strlen((char*) cp->data) + 1; + cp->msg.data_length = fill_connect_data((char *)cp->data, + sizeof(cp->data)); send_packet(cp, t); #if ADB_HOST /* XXX why sleep here? */ @@ -254,29 +287,57 @@ static char *connection_state_name(atransport *t) } } +/* 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 + * was malloc'ed and needs to freed. A char buffer will be malloc'ed and + * filled with src and *dst will be set to + * point to the buffer. + */ +static void qual_overwrite(char **dst, const char *src) +{ + if (!dst) + return; + + free(*dst); + *dst = NULL; + + if (!src || !*src) + return; + + *dst = strdup(src); +} + void parse_banner(char *banner, atransport *t) { - char *type, *product, *end; + static const char *prop_seps = ";"; + static const char key_val_sep = '='; + char *cp, *type; D("parse_banner: %s\n", banner); type = banner; - product = strchr(type, ':'); - if(product) { - *product++ = 0; - } else { - product = ""; - } - - /* remove trailing ':' */ - end = strchr(product, ':'); - if(end) *end = 0; - - /* save product name in device structure */ - if (t->product == NULL) { - t->product = strdup(product); - } else if (strcmp(product, t->product) != 0) { - free(t->product); - t->product = strdup(product); + cp = strchr(type, ':'); + if (cp) { + *cp++ = 0; + /* Nothing is done with second field. */ + cp = strchr(cp, ':'); + if (cp) { + char *save; + char *key; + key = strtok_r(cp + 1, prop_seps, &save); + while (key) { + cp = strchr(key, key_val_sep); + if (cp) { + *cp++ = '\0'; + if (!strcmp(key, "ro.product.name")) + qual_overwrite(&t->product, cp); + else if (!strcmp(key, "ro.product.model")) + qual_overwrite(&t->model, cp); + else if (!strcmp(key, "ro.product.device")) + qual_overwrite(&t->device, cp); + } + key = strtok_r(NULL, prop_seps, &save); + } + } } if(!strcmp(type, "bootloader")){ diff --git a/adb/adb.h b/adb/adb.h index b99d7ac82..e095d70a8 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -185,6 +185,8 @@ struct atransport /* used to identify transports for clients */ char *serial; char *product; + char *model; + char *device; char *devpath; int adb_port; // Use for emulators (local transport) diff --git a/adb/protocol.txt b/adb/protocol.txt index 398d042f1..abd63f90a 100644 --- a/adb/protocol.txt +++ b/adb/protocol.txt @@ -72,7 +72,7 @@ large maxdata value, the connection with the other side must be closed. The system identity string should be "::" where systemtype is "bootloader", "device", or "host", serialno is some kind of unique ID (or empty), and banner is a human-readable version -or identifier string (informational only). +or identifier string. The banner is used to transmit useful properties. --- OPEN(local-id, 0, "destination") ----------------------------------- diff --git a/adb/transport.c b/adb/transport.c index 9c63640df..359b0d696 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -601,6 +601,10 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) free(t->product); if (t->serial) free(t->serial); + if (t->model) + free(t->model); + if (t->device) + free(t->device); if (t->devpath) free(t->devpath);