am 9526a788: Merge "adb: Add ability to specify device path" into ics-aah

* commit '9526a788a6bd528e14622404e8750bdcc147d15a':
  adb: Add ability to specify device path
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index be4d50b..d9aa09c 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -17,8 +17,10 @@
     upgrade.
 
 host:devices
+host:devices-l
     Ask to return the list of available Android devices and their
-    state. After the OKAY, this is followed by a 4-byte hex len,
+    state. devices-l includes the device paths in the state.
+    After the OKAY, this is followed by a 4-byte hex len,
     and a string that will be dumped as-is by the client, then
     the connection is closed
 
@@ -88,6 +90,9 @@
     Returns the serial number of the corresponding device/emulator.
     Note that emulator serial numbers are of the form "emulator-5554"
 
+<host-prefix>:get-devpath
+    Returns the device path of the corresponding device/emulator.
+
 <host-prefix>:get-state
     Returns the state of a given device as a string.
 
diff --git a/adb/adb.c b/adb/adb.c
index f4ee448..44eaebb 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -1201,16 +1201,19 @@
     }
 
     // return a list of all connected devices
-    if (!strcmp(service, "devices")) {
+    if (!strncmp(service, "devices", 7)) {
         char buffer[4096];
-        memset(buf, 0, sizeof(buf));
-        memset(buffer, 0, sizeof(buffer));
-        D("Getting device list \n");
-        list_transports(buffer, sizeof(buffer));
-        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
-        D("Wrote device list \n");
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
+        int use_long = !strcmp(service+7, "-l");
+        if (use_long || service[7] == 0) {
+            memset(buf, 0, sizeof(buf));
+            memset(buffer, 0, sizeof(buffer));
+            D("Getting device list \n");
+            list_transports(buffer, sizeof(buffer), use_long);
+            snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
+            D("Wrote device list \n");
+            writex(reply_fd, buf, strlen(buf));
+            return 0;
+        }
     }
 
     // add a new TCP transport, device or emulator
@@ -1276,6 +1279,16 @@
         writex(reply_fd, buf, strlen(buf));
         return 0;
     }
+    if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
+        char *out = "unknown";
+         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+       if (transport && transport->devpath) {
+            out = transport->devpath;
+        }
+        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
+        writex(reply_fd, buf, strlen(buf));
+        return 0;
+    }
     // indicates a new emulator instance has started
     if (!strncmp(service,"emulator:",9)) {
         int  port = atoi(service+9);
diff --git a/adb/adb.h b/adb/adb.h
index 03a7393..4a9b53c 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -190,6 +190,7 @@
         /* used to identify transports for clients */
     char *serial;
     char *product;
+    char *devpath;
     int adb_port; // Use for emulators (local transport)
 
         /* a list of adisconnect callbacks called when the transport is kicked */
@@ -253,7 +254,7 @@
 ** get_device_transport does an acquire on your behalf before returning
 */
 void init_transport_registration(void);
-int  list_transports(char *buf, size_t  bufsize);
+int  list_transports(char *buf, size_t  bufsize, int show_devpath);
 void update_transports(void);
 
 asocket*  create_device_tracker(void);
@@ -286,7 +287,7 @@
 void unregister_transport(atransport *t);
 void unregister_all_tcp_transports();
 
-void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
+void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
 
 /* this should only be used for transports with connection_state == CS_NOPERM */
 void unregister_usb_transport(usb_handle *usb);
diff --git a/adb/commandline.c b/adb/commandline.c
index 47c9bec..a6f1ce2 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -84,8 +84,8 @@
         "                                 returns an error if more than one USB device is present.\n"
         " -e                            - directs command to the only running emulator.\n"
         "                                 returns an error if more than one emulator is running.\n"
-        " -s <serial number>            - directs command to the USB device or emulator with\n"
-        "                                 the given serial number. Overrides ANDROID_SERIAL\n"
+        " -s <specific device>          - directs command to the device or emulator with the given\n"
+        "                                 serial number or device path. Overrides ANDROID_SERIAL\n"
         "                                 environment variable.\n"
         " -p <product name or path>     - simple product name like 'sooner', or\n"
         "                                 a relative/absolute path to a product\n"
@@ -93,7 +93,8 @@
         "                                 If -p is not specified, the ANDROID_PRODUCT_OUT\n"
         "                                 environment variable is used, which must\n"
         "                                 be an absolute path.\n"
-        " devices                       - list all connected devices\n"
+        " devices [-l]                  - list all connected devices\n"
+        "                                 ('-l' means list device paths)\n"
         " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
         "                                 Port 5555 is used by default if no port number is specified.\n"
         " disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.\n"
@@ -159,6 +160,7 @@
         "  adb kill-server              - kill the server if it is running\n"
         "  adb get-state                - prints: offline | bootloader | device\n"
         "  adb get-serialno             - prints: <serial-number>\n"
+        "  adb get-devpath              - prints: <device-path>\n"
         "  adb status-window            - continuously print device status for a specified device\n"
         "  adb remount                  - remounts the /system partition on the device read-write\n"
         "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
@@ -1016,7 +1018,16 @@
 
     if(!strcmp(argv[0], "devices")) {
         char *tmp;
-        snprintf(buf, sizeof buf, "host:%s", argv[0]);
+        char *listopt;
+        if (argc < 2)
+            listopt = "";
+        else if (argc == 2 && !strcmp(argv[1], "-l"))
+            listopt = argv[1];
+        else {
+            fprintf(stderr, "Usage: adb devices [-l]\n");
+            return 1;
+        }
+        snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
         tmp = adb_query(buf);
         if(tmp) {
             printf("List of devices attached \n");
@@ -1298,7 +1309,8 @@
     /* passthrough commands */
 
     if(!strcmp(argv[0],"get-state") ||
-        !strcmp(argv[0],"get-serialno"))
+        !strcmp(argv[0],"get-serialno") ||
+        !strcmp(argv[0],"get-devpath"))
     {
         char *tmp;
 
diff --git a/adb/transport.c b/adb/transport.c
index 2f7bd27..29cb582 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -370,7 +370,7 @@
     char  head[5];
     int   len;
 
-    len = list_transports(buffer+4, bufferlen-4);
+    len = list_transports(buffer+4, bufferlen-4, 0);
     snprintf(head, sizeof(head), "%04x", len);
     memcpy(buffer, head, 4);
     len += 4;
@@ -601,6 +601,8 @@
             free(t->product);
         if (t->serial)
             free(t->serial);
+        if (t->devpath)
+            free(t->devpath);
 
         memset(t,0xee,sizeof(atransport));
         free(t);
@@ -762,6 +764,10 @@
                 result = t;
                 break;
             }
+            if (t->devpath && !strcmp(serial, t->devpath)) {
+                result = t;
+                break;
+            }
         } else {
             if (ttype == kTransportUsb && t->type == kTransportUsb) {
                 if (result) {
@@ -837,7 +843,7 @@
     }
 }
 
-int list_transports(char *buf, size_t  bufsize)
+int list_transports(char *buf, size_t  bufsize, int show_devpath)
 {
     char*       p   = buf;
     char*       end = buf + bufsize;
@@ -850,7 +856,13 @@
         const char* serial = t->serial;
         if (!serial || !serial[0])
             serial = "????????????";
-        len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
+        if (show_devpath) {
+            const char* devpath = t->devpath;
+            if (!devpath || !devpath[0])
+                devpath = "????????????";
+            len = snprintf(p, end - p, "%s\t%s\t%s\n", serial, devpath, statename(t));
+        } else
+            len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
 
         if (p + len >= end) {
             /* discard last line if buffer is too short */
@@ -911,6 +923,9 @@
         if (t->serial && !strcmp(serial, t->serial)) {
             break;
         }
+        if (t->devpath && !strcmp(serial, t->devpath)) {
+            break;
+        }
      }
     adb_mutex_unlock(&transport_lock);
 
@@ -956,7 +971,7 @@
 
 #endif
 
-void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
+void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
 {
     atransport *t = calloc(1, sizeof(atransport));
     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
@@ -965,6 +980,9 @@
     if(serial) {
         t->serial = strdup(serial);
     }
+    if(devpath) {
+        t->devpath = strdup(devpath);
+    }
     register_transport(t);
 }
 
diff --git a/adb/usb_libusb.c b/adb/usb_libusb.c
index 8c75266..06ff5dc 100644
--- a/adb/usb_libusb.c
+++ b/adb/usb_libusb.c
@@ -347,7 +347,7 @@
 
     adb_mutex_unlock(&usb_lock);
 
-    register_usb_transport(usb, serial, 1); 
+    register_usb_transport(usb, serial, NULL, 1); 
 
     return (1);
 }
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 4d55b74..7bf2057 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -116,7 +116,8 @@
 
 }
 
-static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
+static void register_device(const char *dev_name, const char *devpath,
+                            unsigned char ep_in, unsigned char ep_out,
                             int ifc, int serial_index, unsigned zero_mask);
 
 static inline int badname(const char *name)
@@ -129,7 +130,7 @@
 
 static void find_usb_device(const char *base,
         void (*register_device_callback)
-                (const char *, unsigned char, unsigned char, int, int, unsigned))
+                (const char *, const char *, unsigned char, unsigned char, int, int, unsigned))
 {
     char busname[32], devname[32];
     unsigned char local_ep_in, local_ep_out;
@@ -227,6 +228,11 @@
                             is_adb_interface(vid, pid, interface->bInterfaceClass,
                             interface->bInterfaceSubClass, interface->bInterfaceProtocol))  {
 
+                        struct stat st;
+                        char pathbuf[128];
+                        char link[256];
+                        char *devpath = NULL;
+
                         DBGX("looking for bulk endpoints\n");
                             // looks like ADB...
                         ep1 = (struct usb_endpoint_descriptor *)bufptr;
@@ -263,7 +269,26 @@
                             local_ep_out = ep1->bEndpointAddress;
                         }
 
-                        register_device_callback(devname, local_ep_in, local_ep_out,
+                            // Determine the device path
+                        if (!fstat(fd, &st) && S_ISCHR(st.st_mode)) {
+                            char *slash;
+                            ssize_t link_len;
+                            snprintf(pathbuf, sizeof(pathbuf), "/sys/dev/char/%d:%d",
+                                     major(st.st_rdev), minor(st.st_rdev));
+                            link_len = readlink(pathbuf, link, sizeof(link) - 1);
+                            if (link_len > 0) {
+                                link[link_len] = '\0';
+                                slash = strrchr(link, '/');
+                                if (slash) {
+                                    snprintf(pathbuf, sizeof(pathbuf),
+                                             "usb:%s", slash + 1);
+                                    devpath = pathbuf;
+                                }
+                            }
+                        }
+
+                        register_device_callback(devname, devpath,
+                                local_ep_in, local_ep_out,
                                 interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
                         break;
                     }
@@ -532,7 +557,7 @@
     return 0;
 }
 
-static void register_device(const char *dev_name,
+static void register_device(const char *dev_name, const char *devpath,
                             unsigned char ep_in, unsigned char ep_out,
                             int interface, int serial_index, unsigned zero_mask)
 {
@@ -644,7 +669,7 @@
     usb->next->prev = usb;
     adb_mutex_unlock(&usb_lock);
 
-    register_usb_transport(usb, serial, usb->writeable);
+    register_usb_transport(usb, serial, devpath, usb->writeable);
     return;
 
 fail:
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 635fa4b..b110ed8 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -72,7 +72,7 @@
         usb->fd = fd;
 
         D("[ usb_thread - registering device ]\n");
-        register_usb_transport(usb, 0, 1);
+        register_usb_transport(usb, 0, 0, 1);
     }
 
     // never gets here
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 00d02da..45ce444 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -125,10 +125,13 @@
     IOUSBDeviceInterface197  **dev = NULL;
     HRESULT                  result;
     SInt32                   score;
+    UInt32                   locationId;
     UInt16                   vendor;
     UInt16                   product;
     UInt8                    serialIndex;
     char                     serial[256];
+    char                     devpathBuf[64];
+    char                     *devpath = NULL;
 
     while ((usbInterface = IOIteratorNext(iterator))) {
         //* Create an intermediate interface plugin
@@ -192,6 +195,11 @@
 
         kr = (*dev)->GetDeviceVendor(dev, &vendor);
         kr = (*dev)->GetDeviceProduct(dev, &product);
+        kr = (*dev)->GetLocationID(dev, &locationId);
+        if (kr == 0) {
+            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId);
+            devpath = devpathBuf;
+        }
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
 
 	if (serialIndex > 0) {
@@ -256,7 +264,7 @@
         }
 
         DBG("AndroidDeviceAdded calling register_usb_transport\n");
-        register_usb_transport(handle, (serial[0] ? serial : NULL), 1);
+        register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
 
         // Register for an interest notification of this device being removed.
         // Pass the reference to our private data as the refCon for the
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index b216999..a2fbb79 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -490,7 +490,7 @@
                                 true)) {
             // Lets make sure that we don't duplicate this device
             if (register_new_device(handle)) {
-              register_usb_transport(handle, serial_number, 1);
+              register_usb_transport(handle, serial_number, NULL, 1);
             } else {
               D("register_new_device failed for %s\n", interf_name);
               usb_cleanup_handle(handle);