Tuesday, September 23, 2014

The most comprehensive write up on how to make adb work in a debian based linux environment

It is very surprising to me to see how many people are still to this day (almost 7 years since the first public release of Android) confused about proper way of making adb command work in linux environment.

The most common misconceptions about running adb in linux are:

1. You have to install some kind of "adb" driver

2. You have to install full Android SDK

3. You have to run adb as root

none of which are true!

Here are some actual issues to take care of:

1. Where to get the adb binary from?

While there are plenty of third party packages available personally I prefer to use the binary which comes directly from Google themselves - the one included with the official Android SDK. But what if we need just the adb binary alone and do not want to install the whole SDK? The first of the following commands downloads and parses the source code of the latest SDK Manager to find the link for the latest version of platform-tools package containing the adb binary. The second command downloads platform-tools package and extracts the binary into the current directory. The third one obviously makes the binary executable:

~$ eval $(wget -qO - "https://android.googlesource.com/platform/tools/base/+/master/sdklib/src/main/"\
"java/com/android/sdklib/repository/SdkRepoConstants.java?format=text" | base64 -d | tr '\n;' ' \n' | \
sed -e "s/\(NS_LATEST_VERSION\|URL_GOOGLE_SDK_SITE\|URL_FILENAME_PATTERN\)/\n\1/g" \
-e "s/%1\$d/\$NS_LATEST_VERSION/" | tr -d ' ' | grep "^[A-Z_]*=" | sort)

~$ wget -qO - "$URL_GOOGLE_SDK_SITE$(wget -qO - "$URL_GOOGLE_SDK_SITE$URL_FILENAME_PATTERN?format=text" | xml2 | \
grep "/sdk:platform-tool/" | grep "\-linux\.zip$" | tail -n 1 | cut -d= -f2)" | funzip 2> /dev/null 1> ./adb

~$ chmod 755 ./adb



2. I downloaded the binary but it does not run! Why?

The Google adb binary has some dependencies. It requires the following libraries to be installed: libncurses5 libstdc++6. Also the Google adb binary is 32bit and if your linux system is 64bit you need to make sure that 32bit versions of those libraries are also installed. In most debian based systems you can solve those dependencies by running the following commands:

~$ sudo dpkg --add-architecture i386 2>/dev/null
~$ sudo apt-get -qqy update
~$ sudo apt-get -qqy install libncurses5:i386 libstdc++6:i386 zlib1g:i386


After that running ./adb devices command should produce at least these lines:

~$ ./adb devices
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
List of devices attached



3. Running ./adb devices returns an empty list!

In linux no special driver is required for user space programs to access USB devices privided they have permissions and are willing to handle the exchange protocol by themselves. The adb binary uses low level libusb library to access the device. So how does it know to which out of all connected USB devices it needs to talk to? It is looking for devices with a specific interface. Let's examine the lsusb -v command's output on a system which has an android device with enabled "USB debugging" connected to it:

~$ lsusb -v | grep -B 3 -i iInterface
    bInterfaceClass     255 Vendor Specific Class
    bInterfaceSubClass   66
    bInterfaceProtocol    1
    iInterface            4 ADB Interface


You can check any Android device from any manufacturer - its adb interface will always have

  bInterfaceClass=255
  bInterfaceSubClass=66
  bInterfaceProtocol=1

Because this is exactly what adb tool is looking for! But in some misguided optimization effort Google decided to filter out devices with "unknown" USB Vendor IDs first. You can see the latest list of the "Google approved" Vendor IDs by running the following command:

~$ wget -qO - "https://android.googlesource.com/platform/system/core/+/master/adb/usb_vendors.c?format=text" | \
base64 -d | grep "define VENDOR_ID"


What to do if your device's manufacturer did not make the list? If you already know its USB Vendor ID you can add it in 0xffff hexadecimal format (one ID per line if you have multiple IDs) to the ~/.android/adb_usb.ini file. Make sure to run ./adb kill-server command afterwards. Because while being just a single file the adb tool actually consists of 2 distinct parts - adb daemon and adb client. When you ran very first adb command like ./adb devices - it left the daemon part still running. And since the configuration file is only being read by the daemon part when it is starting up - the only way to make it read the changes we just made to the ini file is to kill the daemon and restart again.


4. I don't know my device's Vendor ID or I added it to the adb_usb.ini but ./adb devices still shows nothing!

There is a way to check if any adb devices are connected to the system. And by "adb devices" I mean Android devices with adb interface enumerated (i.e. with "USB debugging" option enabled on the device). The following command does not depend on the local adb configuration. In fact I should have probably started with it before downloading any files or installing any packages:

~$ find -L /sys/bus/usb/devices -maxdepth 2 -path "*/modalias" -printf "%h\t" -exec cat {} \; | \
awk -F: '/icFFisc42ip0/ {print $1}' | xargs -i cat {}/idVendor | awk '{print"0x"$1}'



This command should produce exactly one line with Vendor ID per connected adb device. If you do not see any output - you need to start looking at other possible reasons for the adb interface enumeration failure like always popular:

    "USB debugging" is not enabled on the device
    Defective/disconnected USB cable
    Defective USB hub (if used) or USB port in your system

Let's rule out the hardware issues first. Unplug your Android device and run the following command:

~$ bash -c 'LSUSB=$(lsusb|sort); read; diff -a <(lsusb|sort) <(echo "$LSUSB")' | grep "^<" | awk '{print $7}' | \
xargs -i lsusb -v -d {} | grep -B 3 iInterface


It is not supposed to produce any output or even return back to the command prompt just yet. Plug your Android device back in, wait for like 5 seconds and press [enter] key on the keyboard. Now you should get your command prompt back. But most importantly you should expect to see some lines printed out. If you did not get any output - that means that your android device does not enumerate any interfaces at all. Which is very unlikely and suggests a hardware problem. But if you got some interfaces listed just not the adb interface - this means that the hardware (USB cable/hub/port) is working fine but you have "USB debugging" switched off on the device.


SO STOP WASTING TIME AND TURN "USB debugging" ON!!!


In case of hardware problems replace the USB cable, connect your device directly to the USB port on the PC if you used a USB hub before, try connecting to a different USB port and try again...

So you fixed all problems and the find -L /sys/bus/usb/devices ... command finally started printing some numbers. As I mentioned before those numbers are USB Vendor IDs for all currently connected adb devices. If you had not added them yet to your adb_usb.ini file do it now:

~$ find -L /sys/bus/usb/devices -maxdepth 2 -path "*/modalias" -printf "%h\t" -exec cat {} \; | \
awk -F: '/icFFisc42ip0/ {print $1}' | xargs -i cat {}/idVendor | awk '{print"0x"$1}' | sort -u >> ~/.android/adb_usb.ini
~$ ./adb kill-server



5. ./adb devices command shows ???????????? no permissions!

This is the best news you got all day! Congratulations! This means that adb tool can finally see and recognize your device. It just does not have permissions to access it. Let's give it the permissions:

~$ echo 'ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:ff420?:*", MODE="0666", '\
'GROUP="plugdev", SYMLINK+="android/$env{ID_SERIAL_SHORT}"' | sudo tee /etc/udev/rules.d/90-universal-android.rules
~$ sudo udevadm control --reload-rules
~$ sudo udevadm trigger --action=add --subsystem-match=usb
~$ sudo killall -9 adb



6. Finally ./adb devices command shows my device and all other adb commands also work properly! Thank You!!!



You are welcome. You can move the adb binary to a directory in your $PATH now.

Also for your convenience I put all the above commands into a single shell file:

No comments:

Post a Comment