ANDROID: 超级好用的ADB FORWARD命令
之前,我們使用adb forward命令的時候,只是單純地將設備中的某些TCP端口給forward出來,如我們最常用的gdb調試native的代碼,會將設備的5039端口給forward出來,給gdb客戶端訪問。那么adb forward有什么更加強大的功能呢?
我們先看一下adb命令中關于forward的一些幫助信息(看了一下,還有reverse命令,也一同列了出來):
adb forward --list - list all forward socket connections.the format is a list of lines with the following format:<serial> " " <local> " " <remote> "\n"adb forward <local> <remote> - forward socket connectionsforward specs are one of: tcp:<port>localabstract:<unix domain socket name>localreserved:<unix domain socket name>localfilesystem:<unix domain socket name>dev:<character device name>jdwp:<process pid> (remote only)adb forward --no-rebind <local> <remote>- same as 'adb forward <local> <remote>' but failsif <local> is already forwardedadb forward --remove <local> - remove a specific forward socket connectionadb forward --remove-all - remove all forward socket connectionsadb reverse --list - list all reverse socket connections from deviceadb reverse <remote> <local> - reverse socket connectionsreverse specs are one of:tcp:<port>localabstract:<unix domain socket name>localreserved:<unix domain socket name>localfilesystem:<unix domain socket name>adb reverse --no-rebind <remote> <local>- same as 'adb reverse <remote> <local>' but failsif <remote> is already reversed.adb reverse --remove <remote>- remove a specific reversed socket connectionadb reverse --remove-all - remove all reversed socket connections from device我之前也寫道可以將Android系統中的設備forward出來,如將input設備forward出來:
adb forward tcp:8424 dev:/dev/input/event0但把這個設備forward出來用處也不大,還要專門寫一個程序來讀寫這個端口。
最近一直在做移植Brillo到RPi 2B上面,今天PRi 2B已經有雙系統了:可以在斷電開機的時候先運行recovery系統,以便我們將Brillo系統修改出問題不能再次開機的時候,可以方便地進行修復。這里的recovery系統,這個recovery系統其實也是一個Brillo系統,并不像Android系統的recovery系統,有sideload, 可以通過adb燒機。PRi 2B上面也沒有什么好用的bootloader, 或者是帶有fastboot協議,可以很方便地更新boot, system分區。這也是做recovery系統的初衷。現在系統是做好了,可以也想不出里面有什么好用的工具,可以更新system image。
即使不做Brillo系統system image的更新,在recovery系統下,對Brillo系統分區中的文件進行更新也是個很麻煩的事情,因為Brillo系統有了SELinux這個安全模塊,現在的copy(adb push/sync)文件并不是簡單地將文件copy進去就了事了。adb push/sync文件的時候,會對push進來的文件重新設置mode和SELinux label, 具體請看代碼(system/core/adb/file_sync_service.cpp @brillo-m8-release):
static bool handle_send_file(int s, const char* path, uid_t uid,gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {syncmsg msg;unsigned int timestamp = 0;int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);if (fd < 0 && errno == ENOENT) {if (!secure_mkdirs(adb_dirname(path))) {SendSyncFailErrno(s, "secure_mkdirs failed");goto fail;}fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);}if (fd < 0 && errno == EEXIST) {fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);}if (fd < 0) {SendSyncFailErrno(s, "couldn't create file");goto fail;} else {if (fchown(fd, uid, gid) == -1) {SendSyncFailErrno(s, "fchown failed");goto fail;}// Not all filesystems support setting SELinux labels. http://b/23530370.selinux_android_restorecon(path, 0);// fchown clears the setuid bit - restore it if present.// Ignore the result of calling fchmod. It's not supported// by all filesystems. b/12441485fchmod(fd, mode);}// ... }想要更新system image需要將system image先push到設備中,再通過dd命令寫入,也是件非常麻煩的事情。在不停地思考,如果系統中有個nc(netcat)命令就好了,于是運行adb shell nc;不行,沒有這個命令。再想想,再想想。對了,可以通過adb forward命令將分區給forward出來,這是個方法。那用什么命令可以讀寫這個TCP端口呢,dd行不行。如果dd可以的話,我們就可以去試試看一下dd能不能將system image直接寫入到這個分區。看了一下dd的手冊,沒有這樣的寫法,只好再次放棄了。腦子靈光一閃,又想到了nc命令。。。
- adb forward與nc配合使用真是太無敵了(太激動了!!!)
首先,我們將system image所在的分區(/dev/block/by-name/system)通過adb forward命令forward出來:
$ adb forward tcp:8424 dev:/dev/block/by-name/system除了使用TCP端口進行forward之外,我們還可以使用unix domain socket進行forward:
$ adb forward localfilesystem:socket dev:/dev/block/mmcblk0p6再通過adb forward –list命令,我們就可以看到分區已經被forward出來了:
$ adb forward --list 10.0.0.18:5555 tcp:8424 dev:/dev/block/by-name/system我們先試試將分區中的內容給讀取出來看看:
$ nc 127.0.0.1 8424 > system.bin查看文件格式與大小都沒有什么問題,使用fsck.ext4檢查也沒有問題:
$ file system.bin system.bin: Linux rev 1.0 ext4 filesystem data, UUID=da594c53-9beb-f85c-85c5-cedf76546f7a, volume name "system" (extents) (large files) $ ls -l system.bin -rw-rw-r-- 1 hzak hzak 268435456 Jan 3 04:56 system.bin $ fsck.ext4 -n -f -v system.bin e2fsck 1.42.9 (4-Feb-2014) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information713 inodes used (4.35%, out of 16384)0 non-contiguous files (0.0%)0 non-contiguous directories (0.0%)# of inodes with ind/dind/tind blocks: 0/0/0Extent depth histogram: 55519539 blocks used (29.81%, out of 65536)0 bad blocks0 large files532 regular files22 directories0 character device files0 block device files0 fifos0 links150 symbolic links (150 fast symbolic links)0 sockets ------------704 files將system.img文件寫進去看看:
$ cat system.img | nc 127.0.0.1 8424 > /dev/null # or $ nc 127.0.0.1 8424 < system.img > /dev/null對于Unix domain socket:
$ cat system.img | nc -U socketNOTE:
在這里,我突然聯想到某手機平臺不帶fastboot協議,每次燒機都得用專門的工具,真是太不方便了。現在想想,有了這個方法,fastboot都得找地方哭去。
[2016-01-04?21:56:03]
今天分析了相關的代碼,在設備端(adbd進程中)讀寫dev文件使用的是fd是同一個,讀寫的時候fd中的pos會發生變化。而在進行nc 127.0.0.1 8424 < system.img的時候,會首先去讀取文件,所以fd中的pos發生了變化,寫入的位置也就發生了改變。要解決這個問題,就要避免讀寫使用同一個fd進行操作。同時我們可以知道,單獨地去讀取文件是不會有問題的。
這也可以理解adb forward中的dev只支持character device,而不支持block device。
NOTE:
關于adbd的調試,可以參考文件: system/core/adb/adb_trace.cpp @brillo-m8-release, 設置系統屬性persist.adb.trace_mask為all, 再重啟adbd之后,可以在/data/adb/文件夾下看到log文件。
?
同時,由于Brillo系統中curl命令,可以通過在host(PC)中通過python建立一個簡單的http server, 再Brillo系統中使用curl命令可以實現系統分區的更新:
如在host (PC, IP地址10.0.0.10)中建立簡單的http server:
cd out/target/product/rpi && python -m SimpleHTTPServer在Brillo系統命令行中執行如下命令 (需要以root用戶執行):
# curl http://10.0.0.10:8000/system.img -o /dev/block/mmcblk0p6可以同時看到傳輸速度與剩余時間也是不錯的選擇:
% Total % Received % Xferd Average Speed Time Time Time CurrentDload Upload Total Spent Left Speed 100 256M 100 256M 0 0 10.3M 0 0:00:24 0:00:24 --:--:-- 10.5M https://www.brobwind.com/archives/260總結
以上是生活随笔為你收集整理的ANDROID: 超级好用的ADB FORWARD命令的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Understanding Genera
- 下一篇: (整理)用户空间_内核空间以及内存映射