Public
ADB with the vanilla Linux 3.8 kernel
So at ABS, I was talking with +mark gross and he expressed his frustration in getting ADB up and running during device bring-up. I mentioned that the Android gadget driver had been upstreamed into staging, but was re-named as the ccg driver, but mark pointed out that it was missing the ADB functionality. So I dug in and sure enough, the ADB bits were dropped when ccg was merged into staging.
I played around a little bit to add the ADB functionality to the ccg driver, but as I read up around it, I found that there's a similar gadget driver called the FunctionFS driver already upstream. Interestingly Andrzej Pietrasiewicz, the same developer who was working on the ccg driver, submitted patches to AOSP to get the adbd daemon to use the FunctionFS gadget. +Benoit Goby then reworked and merged those changes in AOSP last summer.
The net of it is, ADB can already work with the vanilla Linux kernel! Its just not well documented.
For me the process was as follows:
1) Make sure you have Jelly Bean 4.2 Android userland image.
Linaro provides a number of images for different boards here:
http://www.linaro.org/downloads/
2) When building your kernel, make sure to configure in FunctionFS:
Device Drivers -> USB Support -> USB Gadget Support
-> USB Gadget Driver -> Function Filesystem
3) Modify your boot parameters to set the vendor and product ids so adb on your host recognizes the device.
g_ffs.idVendor=0x18d1 g_ffs.idProduct=0x4e26
Alternatively this can also be done if you built the gadget driver as a module at load time:
insmod g_ffs.ko idVendor=0x18d1 idProduct=0x4e26
4) Now here I'm assuming you've got a serial port working. Boot your target device with your new kernel (and insmod the g_ffs driver if necessary), and setup the functionfs directory:
# mkdir /dev/usb-ffs
# mkdir /dev/usb-ffs/adb
# mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb
5) If everything is working, you can kill adbd and when it restarts it should find the functionfs mount and make use of it.
# ps adbd
# kill <pid for adbd>
6) On your host system, connect to the target using the adb program:
$ ./adb shell
root@android:/#
Hooray there's your shell!
Now for something more permanent, you should probably modify init.rc to include the steps in #4 above prior to loading adbd. That way adbd starts up using the functionfs gadget and you don't need the serial console to get it going.
There's still some quirks with the instructions above:
* I ran into problems with functionfs somehow causing hangs at boot. Its a bit of a Heisenbug, as adding initcall_debug to my boot parameters causes the issue to disappear.
* While the above works fine, FunctionFS alone is fairly static configuration wise, which means once you've set it up as in the case above, you're not able to dynamically change what devices it composites, which contrasts with the more flexible Android gadget driver. Apparently in the future, some configfs based gadget will be merged which will provide the dynamic configuration aspect of the Android gadget driver.
So at ABS, I was talking with +mark gross and he expressed his frustration in getting ADB up and running during device bring-up. I mentioned that the Android gadget driver had been upstreamed into staging, but was re-named as the ccg driver, but mark pointed out that it was missing the ADB functionality. So I dug in and sure enough, the ADB bits were dropped when ccg was merged into staging.
I played around a little bit to add the ADB functionality to the ccg driver, but as I read up around it, I found that there's a similar gadget driver called the FunctionFS driver already upstream. Interestingly Andrzej Pietrasiewicz, the same developer who was working on the ccg driver, submitted patches to AOSP to get the adbd daemon to use the FunctionFS gadget. +Benoit Goby then reworked and merged those changes in AOSP last summer.
The net of it is, ADB can already work with the vanilla Linux kernel! Its just not well documented.
For me the process was as follows:
1) Make sure you have Jelly Bean 4.2 Android userland image.
Linaro provides a number of images for different boards here:
http://www.linaro.org/downloads/
2) When building your kernel, make sure to configure in FunctionFS:
Device Drivers -> USB Support -> USB Gadget Support
-> USB Gadget Driver -> Function Filesystem
3) Modify your boot parameters to set the vendor and product ids so adb on your host recognizes the device.
g_ffs.idVendor=0x18d1 g_ffs.idProduct=0x4e26
Alternatively this can also be done if you built the gadget driver as a module at load time:
insmod g_ffs.ko idVendor=0x18d1 idProduct=0x4e26
4) Now here I'm assuming you've got a serial port working. Boot your target device with your new kernel (and insmod the g_ffs driver if necessary), and setup the functionfs directory:
# mkdir /dev/usb-ffs
# mkdir /dev/usb-ffs/adb
# mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb
5) If everything is working, you can kill adbd and when it restarts it should find the functionfs mount and make use of it.
# ps adbd
# kill <pid for adbd>
6) On your host system, connect to the target using the adb program:
$ ./adb shell
root@android:/#
Hooray there's your shell!
Now for something more permanent, you should probably modify init.rc to include the steps in #4 above prior to loading adbd. That way adbd starts up using the functionfs gadget and you don't need the serial console to get it going.
There's still some quirks with the instructions above:
* I ran into problems with functionfs somehow causing hangs at boot. Its a bit of a Heisenbug, as adding initcall_debug to my boot parameters causes the issue to disappear.
* While the above works fine, FunctionFS alone is fairly static configuration wise, which means once you've set it up as in the case above, you're not able to dynamically change what devices it composites, which contrasts with the more flexible Android gadget driver. Apparently in the future, some configfs based gadget will be merged which will provide the dynamic configuration aspect of the Android gadget driver.
View 5 previous comments
- I'm getting an odd warning (which is repetitively written to the screen) as soon as I kill the ADB process after hooking up the mount points. I'm running a 3.8 kernel and 4.2.2 on my BBB. Any ideas? WARNING: at drivers/usb/gadget/g_ffs.c:251 ffs_ep0_write+... Modules Linked in: ... slowpath_common. blah.Feb 4, 2014
- Odd. You can ignore my prior post; recompiled a new kernel from a fresh checkout and all is working.Feb 11, 2014
- I followed the steps described above with a TI evm running kernel 3.12 and Android 4.3. When I run adb devices I get "?????????? offline" as a result. I suspect it has something to do with the RSA fingerprint needed since Android 4.2. However I never get the popup on my device to accept the RSA fingerprint and even after manually copying the key to /data/misc/adb/adb_keys the device stays offline. Any ideas?Apr 25, 2014
- can we use above steps "Linux OS "May 25, 2015
- thanks~~~~
finally it works well with vanilla kernel~~
wow~8w - hi guys
I got an issue.
The adb shell works well.
When trying to push and pull adb, a "remote permission denied" error occurs.
The / ttt permission is 777.
Partitions are mounted as rw.
any ideas?
thanks.
B70SH-AR76B1E:~/work2$ strace adb push ./rt2870.bin /ttt
execve("/usr/bin/adb", ["adb", "push", "./rt2870.bin", "/ttt"], [/* 35 vars /]) = 0
brk(NULL) = 0x5573a100c000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
readlink("/proc/self/exe", "/usr/bin/adb", 4096) = 12
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/usr/bin/../lib64/tls/x86_64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/../lib64/tls/x86_64", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/usr/bin/../lib64/tls/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/../lib64/tls", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/usr/bin/../lib64/x86_64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/../lib64/x86_64", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/usr/bin/../lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/../lib64", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/usr/bin/lib64/tls/x86_64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/lib64/tls/x86_64", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/usr/bin/lib64/tls/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/lib64/tls", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/usr/bin/lib64/x86_64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/lib64/x86_64", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/usr/bin/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/bin/lib64", 0x7ffe9e1505d0) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=112592, ...}) = 0
mmap(NULL, 112592, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7faf0960c000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\r\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=14608, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0960b000
mmap(NULL, 2109680, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf091ff000
mprotect(0x7faf09202000, 2093056, PROT_NONE) = 0
mmap(0x7faf09401000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7faf09401000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260`\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=138696, ...}) = 0
mmap(NULL, 2212904, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf08fe2000
mprotect(0x7faf08ffa000, 2093056, PROT_NONE) = 0
mmap(0x7faf091f9000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17000) = 0x7faf091f9000
mmap(0x7faf091fb000, 13352, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf091fb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0V\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=1088952, ...}) = 0
mmap(NULL, 3178744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf08cd9000
mprotect(0x7faf08de1000, 2093056, PROT_NONE) = 0
mmap(0x7faf08fe0000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x107000) = 0x7faf08fe0000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0!\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=31712, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf0960a000
mmap(NULL, 2128832, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf08ad1000
mprotect(0x7faf08ad8000, 2093056, PROT_NONE) = 0
mmap(0x7faf08cd7000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7faf08cd7000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=89696, ...}) = 0
mmap(NULL, 2185488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf088bb000
mprotect(0x7faf088d1000, 2093056, PROT_NONE) = 0
mmap(0x7faf08ad0000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x7faf08ad0000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1868984, ...}) = 0
mmap(NULL, 3971488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7faf084f1000
mprotect(0x7faf086b1000, 2097152, PROT_NONE) = 0
mmap(0x7faf088b1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7faf088b1000
mmap(0x7faf088b7000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7faf088b7000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf09609000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf09608000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf09607000
arch_prctl(ARCH_SET_FS, 0x7faf09608700) = 0
mprotect(0x7faf088b1000, 16384, PROT_READ) = 0
mprotect(0x7faf091f9000, 4096, PROT_READ) = 0
mprotect(0x7faf08cd7000, 4096, PROT_READ) = 0
mprotect(0x7faf08fe0000, 4096, PROT_READ) = 0
mprotect(0x7faf09401000, 4096, PROT_READ) = 0
mprotect(0x55739fad2000, 86016, PROT_READ) = 0
mprotect(0x7faf09628000, 4096, PROT_READ) = 0
munmap(0x7faf0960c000, 112592) = 0
set_tid_address(0x7faf096089d0) = 5323
set_robust_list(0x7faf096089e0, 24) = 0
rt_sigaction(SIGRTMIN, {0x7faf08fe7b50, [], SA_RESTORER|SA_SIGINFO, 0x7faf08ff3390}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {0x7faf08fe7be0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7faf08ff3390}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
brk(NULL) = 0x5573a100c000
brk(0x5573a102d000) = 0x5573a102d000
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7faf085264b0}, {SIG_DFL, [], 0}, 8) = 0
ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(5037), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
write(3, "000chost:version", 16) = 16
read(3, "OKAY", 4) = 4
read(3, "0004", 4) = 4
read(3, "0027", 4) = 4
read(3, "", 16) = 0
close(3) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(5037), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
write(3, "000dhost:features", 17) = 17
read(3, "OKAY", 4) = 4
read(3, "0000", 4) = 4
read(3, "", 16) = 0
close(3) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(5037), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
write(3, "000chost:version", 16) = 16
read(3, "OKAY", 4) = 4
read(3, "0004", 4) = 4
read(3, "0027", 4) = 4
read(3, "", 16) = 0
close(3) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(5037), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
write(3, "0012host:transport-any", 22) = 22
read(3, "OKAY", 4) = 4
write(3, "0005sync:", 9) = 9
read(3, "OKAY", 4) = 4
write(3, "STAT\4\0\0\0/ttt", 12) = 12
read(3, "STAT\0\0\0\0\0\0\0\0\0\0\0\0", 16) = 16
stat("./rt2870.bin", {st_mode=S_IFREG|0664, st_size=8192, ...}) = 0
stat("./rt2870.bin", {st_mode=S_IFREG|0664, st_size=8192, ...}) = 0
open("./rt2870.bin", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0664, st_size=8192, ...}) = 0
read(4, "\377\377\377\2\20(\2\0202\2\20}\2\25\2\2\25\3\2\25\"\2\25'\22\25#\"\2\32i\2"..., 8192) = 8192
read(4, "", 8192) = 0
close(4) = 0
write(3, "SEND\n\0\0\0/ttt,33204DATA\0 \0\0\377\377\377\2\20("..., 8226) = 8226
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
ioctl(0, TIOCGWINSZ, {ws_row=69, ws_col=221, ws_xpixel=1547, ws_ypixel=966}) = 0
[100%] /ttt) = 15
read(3, "FAIL\21\0\0\0", 8) = 8
read(3, "Permission denied", 17) = 17
adb: error: failed to copy './rt2870.bin' to '/ttt': remote Permission denied
) = 79
ioctl(0, TIOCGWINSZ, {ws_row=69, ws_col=221, ws_xpixel=1547, ws_ypixel=966}) = 0
./rt2870.bin: 0 files pushed. 0.2 MB/s (8192 bytes in 0.047s)) = 65
write(1, "\n", 1
) = 1
write(3, "QUIT\0\0\0\0", 8) = 8
read(3, "", 16) = 0
close(3) = 0
exit_group(1) = ?
+++ exited with 1 +++7w
Add a comment...