Last active
January 2, 2018 16:33
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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