Add feature list to connection banner.
This allows us to test for features explicitly rather than relying on
the protocol version number, allowing us to fall back gracefully if a
feature is not supported.
This will be needed for the upcoming shell upgrades for stdout/stderr
separation and exit code reporting.
Change-Id: Ibb1d8ad2611f7209901ee76d51346b453e9c5873
diff --git a/adb/adb.cpp b/adb/adb.cpp
index a8737f5..180954b 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -58,6 +58,8 @@
#if !ADB_HOST
const char* adb_device_banner = "device";
static android::base::LogdLogger gLogdLogger;
+#else
+const char* adb_device_banner = "host";
#endif
void AdbLogger(android::base::LogId id, android::base::LogSeverity severity,
@@ -305,45 +307,50 @@
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[] = {
+std::string get_connection_string() {
+ std::vector<std::string> connection_properties;
+
+#if !ADB_HOST
+ 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++) {
+ for (const auto& prop_name : cnxn_props) {
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;
+ property_get(prop_name, value, "");
+ connection_properties.push_back(
+ android::base::StringPrintf("%s=%s", prop_name, value));
}
-
- return bufsize - remaining + 1;
#endif
+
+ connection_properties.push_back(android::base::StringPrintf(
+ "features=%s", android::base::Join(supported_features(), ',').c_str()));
+
+ return android::base::StringPrintf(
+ "%s::%s", adb_device_banner,
+ android::base::Join(connection_properties, ';').c_str());
}
-void send_connect(atransport *t)
-{
+void send_connect(atransport* t) {
D("Calling send_connect \n");
- apacket *cp = get_apacket();
+ apacket* cp = get_apacket();
cp->msg.command = A_CNXN;
cp->msg.arg0 = t->get_protocol_version();
cp->msg.arg1 = t->get_max_payload();
- cp->msg.data_length = fill_connect_data((char *)cp->data,
- MAX_PAYLOAD_V1);
+
+ std::string connection_str = get_connection_string();
+ // Connect and auth packets are limited to MAX_PAYLOAD_V1 because we don't
+ // yet know how much data the other size is willing to accept.
+ if (connection_str.length() > MAX_PAYLOAD_V1) {
+ LOG(FATAL) << "Connection banner is too long (length = "
+ << connection_str.length() << ")";
+ }
+
+ memcpy(cp->data, connection_str.c_str(), connection_str.length());
+ cp->msg.data_length = connection_str.length();
+
send_packet(cp, t);
}
@@ -356,8 +363,8 @@
*dst = strdup(src.c_str());
}
-void parse_banner(const char* banner, atransport* t) {
- D("parse_banner: %s\n", banner);
+void parse_banner(const std::string& banner, atransport* t) {
+ D("parse_banner: %s\n", banner.c_str());
// The format is something like:
// "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;".
@@ -380,6 +387,10 @@
qual_overwrite(&t->model, value);
} else if (key == "ro.product.device") {
qual_overwrite(&t->device, value);
+ } else if (key == "features") {
+ for (const auto& feature : android::base::Split(value, ",")) {
+ t->add_feature(feature);
+ }
}
}
}
@@ -407,6 +418,29 @@
}
}
+static void handle_new_connection(atransport* t, apacket* p) {
+ if (t->connection_state != kCsOffline) {
+ t->connection_state = kCsOffline;
+ handle_offline(t);
+ }
+
+ t->update_version(p->msg.arg0, p->msg.arg1);
+ std::string banner(reinterpret_cast<const char*>(p->data),
+ p->msg.data_length);
+ parse_banner(banner, t);
+
+#if ADB_HOST
+ handle_online(t);
+#else
+ if (!auth_required) {
+ handle_online(t);
+ send_connect(t);
+ } else {
+ send_auth_request(t);
+ }
+#endif
+}
+
void handle_packet(apacket *p, atransport *t)
{
asocket *s;
@@ -431,25 +465,8 @@
}
return;
- case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
- if(t->connection_state != kCsOffline) {
- t->connection_state = kCsOffline;
- handle_offline(t);
- }
-
- t->update_version(p->msg.arg0, p->msg.arg1);
- parse_banner(reinterpret_cast<const char*>(p->data), t);
-
-#if ADB_HOST
- handle_online(t);
-#else
- if (!auth_required) {
- handle_online(t);
- send_connect(t);
- } else {
- send_auth_request(t);
- }
-#endif
+ case A_CNXN: // CONNECT(version, maxdata, "system-id-string")
+ handle_new_connection(t, p);
break;
case A_AUTH: