Skip to content

Instantly share code, notes, and snippets.

@sleekweasel

sleekweasel/README

Last active Jul 17, 2017
Embed
What would you like to do?
Patches to allow remote access to adbd on a Linux host
See also https://techblog.badoo.com/blog/2016/07/21/segregating-android-devices-for-docker-containers/
Two patches in one:
1. Filter devices by USB VID:PID and USB bus device on Linux, in case you need to segregate devices onto different
ADB dameons running on different server ports (like we needed several groups of Samsung phones, and they re-use
their VID:PID for ALL devives):
ADB_DEV_BUS_USB=/dev/bus/usb/bus01 \
ADB_VID_PID_FILTER=1234:8794,1344:2334 \
ANDROID_ADB_SERVER_PORT=9123 adb devices
2. Bodge to grant unauthenticated access to adbd on a remote machine, and allow lots more emulators (we use this for 64 emulators):
Emulator host:
ADB_LOCAL_TRANSPORT_MAX=64 \
ADB_LOCALHOST=name.of.this.hosting.machine.com \
./adb start-server
Client host:
ADB_SERVER_SOCKET=tcp:name.of.hosting.machine.com:5037 ./adb devices
Note: the remote access is a bodge: run the patched adb on the emulator host, but the normal one elsewhere.
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index f9ba7cbc2..f6b3d47ec 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,
@@ -182,6 +247,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,9 +651,14 @@ 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);
+ const char* bus_root = getenv("ADB_DEV_BUS_USB");
+ if (!bus_root || !*bus_root) {
+ bus_root = "/dev/bus/usb";
+ }
+ find_usb_device(bus_root, register_device);
kick_disconnected_devices();
std::this_thread::sleep_for(1s);
}
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..137d462ff 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 ) {
@@ -396,9 +396,19 @@ void local_init(int port)
const char* debug_name = "";
#if ADB_HOST
+ D("transport: local init adb host");
func = client_socket_thread;
debug_name = "client";
+ D("transport: local init func");
+ D("transport: local init func %s",getenv("ADB_LOCAL_TRANSPORT_MAX"));
+
+ char* env_max_s = getenv("ADB_LOCAL_TRANSPORT_MAX");
+ int env_max = atoi(env_max_s ? env_max_s : "");
+ D("transport: local init func %d %d", env_max, adb_local_transport_max);
+ if (env_max) { adb_local_transport_max = env_max; }
+ local_transports = (atransport**)calloc(adb_local_transport_max, sizeof(atransport*));
#else
+ D("transport: local init not adb host");
// For the adbd daemon in the system image we need to distinguish
// between the device, and the emulator.
if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
@@ -425,7 +435,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 +471,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 +504,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 +543,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