Skip to content

Instantly share code, notes, and snippets.

@sleekweasel
Last active January 2, 2018 16:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sleekweasel/15bb61f8784bc728cf12864e98df95b1 to your computer and use it in GitHub Desktop.
Save sleekweasel/15bb61f8784bc728cf12864e98df95b1 to your computer and use it in GitHub Desktop.
Patch for adb usb bus and vid-pid based segregation (multiple, comma separated), boosting simulataneous emulators, and a bodgy mechanism for remote access to this adb. See https://badoo.com/techblog/blog/2016/07/21/segregating-android-devices-for-docker-containers/
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index f9ba7cbc2..f805ab9b4 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -120,6 +120,71 @@ static inline bool contains_non_digit(const char* name) {
return false;
}
+static int iterate_numbers(const char* list, int* rejects) {
+ const char* p = list;
+ char* end;
+ int count = 0;
+ while(true) {
+ long value = strtol(p, &end, 16);
+ D("%d, %p ... %p (%c) = %ld (...%s)\n", count, p, end, *end, value, p);
+ if (p == end) return count;
+ p = end + 1;
+ count++;
+ if (rejects) rejects[count] = value;
+ if (!*end || !*p) return count;
+ }
+}
+
+int* compute_reject_filter() {
+ char* filter = getenv("ADB_VID_PID_FILTER");
+ if (!filter || !*filter) {
+ filter = getenv("HOME");
+ if (filter) {
+ const char* suffix = "/.android/vidpid.filter";
+ filter = (char*) malloc(strlen(filter) + strlen(suffix) + 1);
+ *filter = 0;
+ strcat(filter, getenv("HOME"));
+ strcat(filter, suffix);
+ }
+ }
+ if (!filter || !*filter) {
+ return (int*) calloc(sizeof(int), 1);
+ }
+ if (*filter == '.' || *filter == '/') {
+ FILE *f = fopen(filter, "r");
+ if (!f) {
+ if (getenv("ADB_VID_PID_FILTER")) {
+ // Only report failure for non-default value
+ fprintf(stderr, "Unable to open file '%s'\n", filter);
+ }
+ return (int*) calloc(sizeof(int), 1);
+ }
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET); //same as rewind(f);
+ filter = (char*) malloc(fsize + 1); // Yes, it's a leak.
+ fsize = fread(filter, 1, fsize, f);
+ fclose(f);
+ filter[fsize] = 0;
+ }
+ int count = iterate_numbers(filter, 0);
+ if (count % 2) printf("WARNING: ADB_VID_PID_FILTER contained %d items - should be paired\n", count);
+ int* rejects = (int*)malloc((count + 1) * sizeof(int));
+ *rejects = count;
+ iterate_numbers(filter, rejects);
+ return rejects;
+}
+
+static int* rejects = 0;
+static bool reject_this_device(int vid, int pid) {
+ if (!*rejects) return false;
+ for ( int len = *rejects; len > 0; len -= 2 ) {
+ D("%4x:%4x vs %4x:%4x\n", vid, pid, rejects[len - 1], rejects[len]);
+ if ( vid == rejects[len - 1] && pid == rejects[len] ) return false;
+ }
+ return true;
+}
+
static void find_usb_device(const std::string& base,
void (*register_device_callback)(const char*, const char*,
unsigned char, unsigned char, int, int,
@@ -127,6 +192,26 @@ static void find_usb_device(const std::string& base,
std::unique_ptr<DIR, int(*)(DIR*)> bus_dir(opendir(base.c_str()), closedir);
if (!bus_dir) return;
+ // ------------------- ADB_DEV_BUS_USB
+ static char* s_bus_root = 0;
+ if (!s_bus_root) {
+ const char* bus_root = getenv("ADB_DEV_BUS_USB");
+ if (!bus_root || !*bus_root) {
+ bus_root = "/dev/bus/usb";
+ }
+ D("Device buses %s", bus_root);
+ int l = strlen(bus_root) + 2;
+ s_bus_root = (char*)malloc(l);
+ strncpy(s_bus_root, bus_root, l); // Two terminating nulls.
+ char* p = s_bus_root;
+ while (( l = strcspn(p, ",") )) {
+ p += l + 1;
+ D("Device bus tail %s", p);
+ p[-1] = 0;
+ }
+ }
+ // ------------------- ADB_DEV_BUS_USB ends
+
dirent* de;
while ((de = readdir(bus_dir.get())) != 0) {
if (contains_non_digit(de->d_name)) continue;
@@ -155,6 +240,14 @@ static void find_usb_device(const std::string& base,
continue;
}
+ // ------------------- ADB_DEV_BUS_USB ends
+ const char* bus_root = s_bus_root;
+ while (!strstr(dev_name.c_str(), bus_root)) {
+ bus_root += strlen(bus_root) + 1;
+ }
+ if (!*bus_root) continue;
+ // ------------------- ADB_DEV_BUS_USB ends
+
int fd = unix_open(dev_name.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
continue;
@@ -182,6 +275,12 @@ static void find_usb_device(const std::string& base,
pid = device->idProduct;
DBGX("[ %s is V:%04x P:%04x ]\n", dev_name.c_str(), vid, pid);
+ if(reject_this_device(vid, pid)) {
+ D("usb_config_vid_pid_reject");
+ unix_close(fd);
+ continue;
+ }
+
// should have config descriptor next
config = (struct usb_config_descriptor *)bufptr;
bufptr += USB_DT_CONFIG_SIZE;
@@ -580,6 +679,7 @@ static void register_device(const char* dev_name, const char* dev_path, unsigned
static void device_poll_thread() {
adb_thread_setname("device poll");
D("Created device thread");
+ rejects = compute_reject_filter();
while (true) {
// TODO: Use inotify.
find_usb_device("/dev/bus/usb", register_device);
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index 14eb16b98..d317d7946 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -52,6 +52,8 @@ struct LocalSocketType {
bool available;
};
+static const char* adb_localhost = getenv("ADB_LOCALHOST");
+
static auto& kLocalSocketTypes = *new std::unordered_map<std::string, LocalSocketType>({
#if ADB_HOST
{ "local", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } },
@@ -112,7 +114,9 @@ bool parse_tcp_socket_spec(const std::string& spec, std::string* hostname, int*
static bool tcp_host_is_local(const std::string& hostname) {
// FIXME
- return hostname.empty() || hostname == "localhost";
+ // Allow connection from remote clients if ADB_LOCALHOST is set (to match ADB_SERVER_SOCKET)
+ std::string s = std::string(adb_localhost && *adb_localhost ? adb_localhost : "");
+ return s.find(hostname) != std::string::npos || hostname == "localhost";
}
bool is_socket_spec(const std::string& spec) {
@@ -156,9 +160,13 @@ int socket_spec_connect(const std::string& spec, std::string* error) {
#if ADB_HOST
result = network_connect(hostname, port, SOCK_STREAM, 0, error);
#else
- // Disallow arbitrary connections in adbd.
- *error = "adbd does not support arbitrary tcp connections";
- return -1;
+ if (adb_localhost && *adb_localhost) {
+ result = network_connect(hostname, port, SOCK_STREAM, 0, error);
+ } else {
+ // Disallow arbitrary connections in adbd.
+ *error = "adbd does not support arbitrary tcp connections without ADB_LOCALHOST";
+ return -1;
+ }
#endif
}
@@ -195,13 +203,13 @@ int socket_spec_listen(const std::string& spec, std::string* error, int* resolve
}
int result;
- if (hostname.empty() && gListenAll) {
+ if ((hostname.empty() && gListenAll) || (adb_localhost && *adb_localhost)) {
result = network_inaddr_any_server(port, SOCK_STREAM, error);
} else if (tcp_host_is_local(hostname)) {
result = network_loopback_server(port, SOCK_STREAM, error);
} else {
// TODO: Implement me.
- *error = "listening on specified hostname currently unsupported";
+ *error = "listening on specified hostname currently unsupported without ADB_LOCALHOST";
return -1;
}
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 3ee286a12..a64b3d7a2 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -48,8 +48,8 @@
// Android Wear has been using port 5601 in all of its documentation/tooling,
// but we search for emulators on ports [5554, 5555 + ADB_LOCAL_TRANSPORT_MAX].
// Avoid stomping on their port by limiting the number of emulators that can be
-// connected.
-#define ADB_LOCAL_TRANSPORT_MAX 16
+// connected, at least by default.
+static int adb_local_transport_max = 16;
static std::mutex& local_transports_lock = *new std::mutex();
@@ -57,7 +57,7 @@ static std::mutex& local_transports_lock = *new std::mutex();
* local transport it is connected. The list is used to detect when we're
* trying to connect twice to a given local transport.
*/
-static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
+static atransport** local_transports = 0;
#endif /* ADB_HOST */
static int remote_read(apacket *p, atransport *t)
@@ -177,7 +177,7 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e
static void PollAllLocalPortsForEmulator() {
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
- int count = ADB_LOCAL_TRANSPORT_MAX;
+ int count = adb_local_transport_max;
// Try to connect to any number of running emulator instances.
for ( ; count > 0; count--, port += 2 ) {
@@ -398,6 +398,11 @@ void local_init(int port)
#if ADB_HOST
func = client_socket_thread;
debug_name = "client";
+
+ char* env_max_s = getenv("ADB_LOCAL_TRANSPORT_MAX");
+ int env_max = atoi(env_max_s ? env_max_s : "");
+ if (env_max) { adb_local_transport_max = env_max; }
+ local_transports = (atransport**)calloc(adb_local_transport_max, sizeof(atransport*));
#else
// For the adbd daemon in the system image we need to distinguish
// between the device, and the emulator.
@@ -425,7 +430,7 @@ static void remote_kick(atransport *t)
#if ADB_HOST
int nn;
std::lock_guard<std::mutex> lock(local_transports_lock);
- for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
+ for (nn = 0; nn < adb_local_transport_max; nn++) {
if (local_transports[nn] == t) {
local_transports[nn] = NULL;
break;
@@ -461,7 +466,7 @@ static void remote_close(atransport *t)
static atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
{
int i;
- for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
+ for (i = 0; i < adb_local_transport_max; i++) {
int local_port;
if (local_transports[i] && local_transports[i]->GetLocalPortForEmulator(&local_port)) {
if (local_port == adb_port) {
@@ -494,7 +499,7 @@ atransport* find_emulator_transport_by_console_port(int console_port)
int get_available_local_transport_index_locked()
{
int i;
- for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
+ for (i = 0; i < adb_local_transport_max; i++) {
if (local_transports[i] == NULL) {
return i;
}
@@ -533,7 +538,7 @@ int init_socket_transport(atransport *t, int s, int adb_port, int local)
fail = -1;
} else if (index < 0) {
// Too many emulators.
- D("cannot register more emulators. Maximum is %d", ADB_LOCAL_TRANSPORT_MAX);
+ D("cannot register more emulators. Maximum is %d", adb_local_transport_max);
fail = -1;
} else {
local_transports[index] = t;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment