1.ADB介绍
ADB(Android Debug Bridge)安卓的调试桥,debug工具。借助adb工具可以管理设备或手机模拟器的工作状态,还可以进行很多手机操作,如安装软件,运行shell命令等。
注意:adb shell进去之后,debug版本终端是以#开头,而USER版本终端是以$开头。
1、adb其实就是个socket通信,数据发过来发过去。
2、adb每次都是发送的一个数据包,数据结构是struct apacket,其中包含msg消息部分,及data数据部分。
3、从PC跟device通信的过程,有一条协议流程,通过不断的数据交互发送,实现数据文件传递。
4、socket数据建立传输过程,会创建socket,创建事件监听线程,注册回调响应函数。
1.1 adb shell 连接
进行实际操作:我的pc的ip是192.168.1.102, 我的android手机的ip为192.168.1.100
1、在pc上执行:netstat -nao | findstr 5037
发现结果是空白。
2、执行adb shell, 肯定是进不了任何shell啊, 然后执行:netstat -nao | findstr 5037
结果是:TCP 127.0.0.1:5037 0.0.0.0:0 LISTENING 3840
可见3840进程正在监听5037端口, 这个进程实际上就是adb server
3、打开android手机,执行adb connect 192.168.1.100, 确保adb能连接上手机哈。
发现, 界面提示adb成功连接上了手机。
执行netstat -nao | findstr 5037, 居然仍然是:
TCP 127.0.0.1:5037 0.0.0.0:0 LISTENING 3840
执行adb shell, 进入手机的android系统, 再次在pc的cmd中(非前面的shell中)执行netstat -nao | findstr 5037, 结果为:
TCP 127.0.0.1:1571 127.0.0.1:5037 ESTABLISHED 4496
TCP 127.0.0.1:5037 0.0.0.0:0 LISTENING 3840
TCP 127.0.0.1:5037 127.0.0.1:1571 ESTABLISHED 3840
表明,adb client和adb server建立tcp连接了。
4、不需要退出上面的shell, 仅在另一个cmd中执行 netstat -nao | findstr 5555, 结果为:
TCP 192.168.1.102:1559 192.168.1.100:5555 ESTABLISHED 3840
表明, adb server和adbd建立起了tcp连接。
5、前面已经进入了手机的shell, 现在在shell中执行:netstat -nao | busybox grep 5555, 结果为:
tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN
tcp 0 0 192.168.1.100:5555 192.168.1.102:1559 ESTABLISHED
进一步证实, adb server和adbd建立起了tcp连接。
归纳:
adb client(pid:4496) <--->adb server(监听5037端口, pid:3840)<--->adbd(监听5555端口, pid:未显示)
|<------------------------- 在 pc 端 ----------------> | |<------------ 在手机端------------>|
其中, adb server作为adb client的服务端, 而adbd又作为adb server的服务端, 实际上就是下面这个意思:
儿子 <------------------------------> 爸爸<------------------------------------->爷爷
1.2 adb抓log
(1)获取KMSG信息:在命令行窗口下,进入adb_fastboot工具的目录:
adb pull /proc/kmsg kmsg.txt log会保存在adb_fastboot目录下
adb shell dmesg > dmsg.txt
(1)dmesg 打印已有的log
(2)dmesg -c 打印已有的log(不包含上次打印出的log)
(3)cat /proc/kmsg 实时log
(2)获取LOGCAT信息
adb logcat -v time > logcat.txt
adb logcat -b radio -v time> logcat_radio.txt
adb logcat -b main -v time> logcat_main.txt
下面的命令直接获取上面三种log信息:
adb logcat –b radio –b main –b system –v time > logcat.txt
2.ADB常用命令
adb install xxx //安装文件
adb shell bugreport > bugreport.txt //查看bug报告,这里面有大量系统信息,包括有dmesg在里面
adb pull <手机路径> <本机路径> //从手机中拉取信息到本地电脑上
adb push <本机路径> <手机路径> //从本地电脑推送信息到手机上
adb pull /sbin/usb/compositions/8401 D:/
adb push D:/8401 /sbin/usb/compositions/
2.1 挂载可读写
2.2 fastboot 模式命令
(1)adb devices——查看手机是否连接上
(2)adb reboot bootloader——将手机重启到Fastboot模式
(3)fastboot devices——查看Fastboot模式下连接的手机
(4)分区写入如下:
fastboot flash boot boot.img
(5)分区擦除如下:
fastboot erase boot
(6)fastboot reboot——Fastboot模式下重启手机
2.2.1 Fastboot 刷机流程
在设备进入到 fastboot 环境后,根据需求执行下面的命令进行刷机:
fastboot flashing unlock # 设备解锁,开始刷机
fastboot flash boot boot.img # 刷入 boot 分区。如果修改了 kernel 代码,则应该刷入此分区以生效
fastboot flash system system.img # 刷入 system 分区。如果修改的代码会影响 out/system/ 路径下生成的文件,则应该刷入此分区以生效
fastboot erase frp # 擦除 frp 分区,frp 即 Factory Reset Protection,用于防止用户信息在手机丢失后外泄
fastboot format data # 格式化 data 分区
fastboot flashing lock # 设备上锁,刷机完毕
fastboot continue # 自动重启设备
2.3 特殊命令
(1)在adb shell下:[将rootfs重挂为可读写]
mount -o remount,rw -t rootfs /
(2)修改文件权限,在cmd下:
adb shell chmod 755 /data/hello.ko
3.Log分类
Android日志主要分为kernel、radio、event、main这四种log。
(1)Kernel Log:kernel log属于Linux内核的log ,可以通过读取/proc/kmsg或者通过串口来抓取。(需要有root权限):
adb shell cat /proc/kmsg > kernel.log
(2)Radio Log:-b radio参数可以抓取Android RIL层 log,在调试Android通信方面的代码时,这个Log非常关键。抓取命令如下:
adb logcat -b radio > radio.log
(3)Main Log:main log和我们在eclipse里通过DDMS中看到的log是一致的。抓取命令如下:
adb logcat -b main > main.log
(4)Event Log:event log属于system log,平时可以跟在main log之后。抓取命令如下:
adb logcat -b event -v time > event.log //-v time表示在log中加入每条log发生的时间
(5)完整Log:adb logcat -b选项是可以复用的,因此我们抓取所有Log的命令就是复用了-b选项。抓取命令如下:
adb logcat -b main -b system -b radio -b events -v time > all.log
3 adb devices ID
3.1 Yocto系统的ID
参考文档:
kba-180912014938_2_where_does_adb_device’s_serial_number_come_from_.pdf
C:\Users\>adb devices
List of devices attached
c12ca333 device
c12ca333 这个没有什么特殊含义,就是一个 serial number,这个是固定的,软件里写入,刷同一个版本是一样的。如果需要修改,也可以修改为其它值。
(1)上层修改方法:
/sys/devices/virtual/android_usb/android0 # cat iSerial
c12ca333
(2)源码修改方法:
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 94820c1..ee499a1 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -3435,7 +3435,13 @@ field ## _store(struct device *dev, struct device_attribute *attr, \
{ \
if (size >= sizeof(buffer)) \
return -EINVAL; \
- strlcpy(buffer, buf, sizeof(buffer)); \
+ if (buffer == serial_string) { \
+ strlcpy(buffer, "oem-test", sizeof("oem-test")); \
+ printk(KERN_DEBUG "[oem][udc][%s] serial_string: %s\n", \
+ __func__, buffer); \
+ } else { \
+ strlcpy(buffer, buf, sizeof(buffer)); \
+ } \
strim(buffer); \
return size; \
} \
@@ -3561,7 +3567,10 @@ static int android_bind(struct usb_composite_dev *cdev)
strlcpy(manufacturer_string, "Android",
sizeof(manufacturer_string) - 1);
strlcpy(product_string, "Android", sizeof(product_string) - 1);
- strlcpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1);
+ // oem-start
+ strlcpy(serial_string, "oem-test", sizeof(serial_string) - 1);
+ // strlcpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1);
+ // oem-end
id = usb_string_id(cdev);
if (id < 0)
3.2 Android系统ID
device id是从emmc芯片读取的emmc serail id,它是唯一的。这个ID对于每个emmc芯片都是唯一的,所以不同的设备有不同的编号。如果想更改它,可以修改如下文件:
android/device/qcom/common/rootdir/etc/init.qcom.usb.rc:
write /sys/class/android_usb/android0/iSerial ${ro.serialno}
iSerial的值是从 ro.serialno得到的,此值是LK过程从emmc读取的,如果要为iseral指定一个固定值,可以尝试重写上面的内容。
(1)通过命令行获取序列号:
getprop ro.serialno
(2)android系统层:
/system/core/init/init.c:
1. static void import_kernel_nv(char *name, int for_emulator)
2. {
3. if (!strcmp(name,"qemu")) {
4. strlcpy(qemu, value, sizeof(qemu));
5. } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
6. const char *boot_prop_name = name + 12; // boot_prop_name: "serialno\0"
7. char prop[PROP_NAME_MAX];
8. int cnt;
9.
10. // prop: "ro.boot.serialno"
11. cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
12. if (cnt < PROP_NAME_MAX)
13. property_set(prop, value);
14. }
以上确定是通过androidboot.serialno获取的,即通过uboot传递给kernel的cmdline获取的,通过cat /proc/cmdline来查看androidboot.serialno的值即是序列号了,接下来再看bootloader。
(3)bootloader:
找到androidboot.serialno的定义:
1. bootloader/lk/app/aboot/aboot.c:
2. static const char *usb_sn_cmdline = " androidboot.serialno=";
查看usb_sn_cmdline的赋值:
1. unsigned char *update_cmdline(const char * cmdline)
2. {
3. cmdline_len += strlen(usb_sn_cmdline);
4. cmdline_len += strlen(sn_buf);
5. }
猜测sn_buf就是要找的序列号,继续跟踪sn_buf的赋值处:
1. bootloader/lk/app/aboot/aboot.c
2. void aboot_init(const struct app_descriptor *app)
3. {
4. target_serialno((unsigned char *) sn_buf);
5. }
6.
7. //找到对应target平台下的相应实现:
8. void target_serialno(unsigned char *buf)
9. {
10. uint32_t serialno;
11. if (target_is_emmc_boot()) {
12. serialno = mmc_get_psn();
13. snprintf((char *)buf, 13, "%x", serialno);
14. }
15. }
16.
17. // 再找对应的mmc_get_psn的实现(到此基本可以确定如果是emmcboot的方式,sn应该就是emmc的chipid了)
18. bootloader/lk/platform/msm_shared/mmc.c:
19. unsigned mmc_get_psn(void)
20. {
21. return mmc_card.cid.psn;
22. }