之前遇到一个问题,就是cts挂测1-2天就会出现cts异常中断,后来找到原因是由于sn号改变,导致cts在手机重启后不能连上手机。


一、通过adb devices代码 得知pc获取手机sn号的方式

正常情况下,我们可以使用adb devices来查看手机的序列号,我们可以从adb 这块入手,去看pc是如何获取手机序列号的。

adb devices是pc侧的命令,我们先从adb的Commandline入手:

if (!strcmp(argv[0], "devices")) {
        const 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;
        }

        std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
        printf("List of devices attached\n");
        return adb_query_command(query);
    }

在处理adb devices的时候最后调用了adb_query_command

static int adb_query_command(const std::string& command) {
    std::string result;
    std::string error;
    if (!adb_query(command, &result, &error)) {
        fprintf(stderr, "error: %s\n", error.c_str());
        return 1;
    }
    printf("%s\n", result.c_str());
    return 0;
}

adb_query_command又调用了adb_query,在这个函数中又调用了adb_connect应该先和pc侧的server通信。

bool adb_query(const std::string& service, std::string* result, std::string* error) {
    D("adb_query: %s\n", service.c_str());
    int fd = adb_connect(service, error);
    if (fd < 0) {
        fprintf(stderr,"error: %s\n", error->c_str());
        return 0;
    }

    result->clear();
    if (!ReadProtocolString(fd, result, error)) {
        adb_close(fd);
        return false;
    }
    return true;
}

我们在看adb_main.cpp中有这么段代码,是在ADB_HOST这个宏中,说明是pc上的代码

#if ADB_HOST
    HOST = 1;

#ifdef WORKAROUND_BUG6558362
    if(is_daemon) adb_set_affinity();
#endif
    usb_init();//这个函数比较关键
    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
    adb_auth_init();

    std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
    if (install_listener(local_name, "*smartsocket*", NULL, 0)) {
        exit(1);
    }

usb_init函数,这就到了Usb_linux.cpp中了

void usb_init()
{
    adb_thread_t tid;
    struct sigaction    actions;
    LOG("%s: usb_linux usb_init\n", __FUNCTION__);

    memset(&actions, 0, sizeof(actions));
    sigemptyset(&actions.sa_mask);
    actions.sa_flags = 0;
    actions.sa_handler = sigalrm_handler;
    sigaction(SIGALRM,& actions, NULL);

    if(adb_thread_create(&tid, device_poll_thread, NULL)){
        fatal_errno("cannot create input thread");
    }
}

我们简单看下,usb_init是如何到Usb_linux.cpp中的,因为有好几个usb_init函数。

这个就需要看Android.mk文件了:

LOCAL_MODULE := adbd

LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
LOCAL_C_INCLUDES += system/extras/ext4_utils

LOCAL_STATIC_LIBRARIES := \
    libadbd \
    libbase \
    libfs_mgr \
    liblog \
    libcutils \
    libc \
    libmincrypt \
    libselinux \
    libext4_utils_static \

include $(BUILD_EXECUTABLE)

我们再来看libadbd这个静态库


LOCAL_MODULE := libadbd
LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
LOCAL_SRC_FILES := \
    $(LIBADB_SRC_FILES) \
    adb_auth_client.cpp \
    fdevent.cpp \
    jdwp_service.cpp \
    qemu_tracing.cpp \
    usb_linux_client.cpp \

LOCAL_SHARED_LIBRARIES := libbase

include $(BUILD_STATIC_LIBRARY)

这个静态库是包括usb_linux_client.cpp这个文件,说明adbd中参与编译的是usb_linux_client.cpp,而我们这边是usb_linux.cpp是host也就是pc侧的

如果是pc侧的代码,会定义类似下面这段代码,定义ADB_HOST这个宏

LOCAL_CFLAGS := -DADB_HOST=0

我们再回过头来看usb_init这个函数:

void usb_init()
{
    adb_thread_t tid;
    struct sigaction    actions;
    LOG("%s: usb_linux usb_init\n", __FUNCTION__);

    memset(&actions, 0, sizeof(actions));
    sigemptyset(&actions.sa_mask);
    actions.sa_flags = 0;
    actions.sa_handler = sigalrm_handler;
    sigaction(SIGALRM,& actions, NULL);

    if(adb_thread_create(&tid, device_poll_thread, NULL)){
        fatal_errno("cannot create input thread");
    }
}

调用了device_poll_thread函数:

static void* device_poll_thread(void* unused) {
    D("Created device thread\n");
    while (true) {
        // TODO: Use inotify.
        find_usb_device("/dev/bus/usb", register_device);
        kick_disconnected_devices();
        sleep(1);
    }
    return nullptr;
}

这个函数中又调用了register_device函数:

std::string serial_path = android::base::StringPrintf(
        "/sys/bus/usb/devices/%s/serial", dev_path + 4);
    std::string serial;
    if (!android::base::ReadFileToString(serial_path, &serial)) {
        D("[ usb read %s failed: %s ]\n", serial_path.c_str(), strerror(errno));
        // We don't actually want to treat an unknown serial as an error because
        // devices aren't able to communicate a serial number in early bringup.
        // http://b/20883914
        serial = "";
    }

在register_device函数中最后是去读取sys/bus/usb/devices/%s/serial这个节点的。

说明adb devices读取sn号是通过pc侧读取的,而不是通过adb 到手机侧获取sn号,再传输过来。就是说明当pc和手机连接的时候,手机的usb驱动会和pc的usb驱动同步,从而将手机侧的sn号同步到pc侧。


二、设置sn号与连接usb

通过上面adb devices的分析,我们大体知道pc侧是如何获取到手机的sn号的。而我们现在就需要分析,为何手机多次重启后,sn号会改变,变成默认的sn号。

由此我想到了,我们的代码设置sn号,是在set_usb_serial_action函数中,而我们之前猜测,pc和手机是在usb连接的时候同步sn号的,而我们还有一个函数是get_amt_mode

是根据开机原因设置sys.lc.amtmode这个属性

void get_amt_mode()
{
    char *amt_file = "/sys/bootinfo/get_boot_mode";
    char amt_mode[15];
    int fd, n;
    fd = open(amt_file, O_RDONLY);
    if (fd < 0) goto error;
    n = read(fd, amt_mode, 14);
    close(fd);
    if (n < 0) goto error;
    if(!strncmp(amt_mode, "amt1", 4)) {
        property_set("sys.lc.amtmode", "1");
    }else if(!strncmp(amt_mode, "amt3", 4)) {
        property_set("sys.lc.amtmode", "3");
    }else if(!strncmp(amt_mode, "normal", 6)) {
        property_set("sys.lc.amtmode", "0");
    }
    return ;
error:
    property_set("sys.lc.amtmode", "0");
}

而在init.rc中会监听这个属性,监听这个动作就有连接usb这块

on property:sys.lc.amtmode=3
    write /sys/class/android_usb/android0/enable 0
    write /sys/class/android_usb/android0/idVendor 18D1
    write /sys/class/android_usb/android0/idProduct 181B
    write /sys/class/android_usb/android0/functions serial,adb
    write /sys/class/android_usb/android0/f_serial/serial_port_num 5
    write /sys/class/android_usb/android0/enable 1
    setprop sys.usb.state serial,adb
    setprop sys.usb.config serial,adb
    start adbd
    start emsd
    start debuggerd
    start akmd09911
    start memsicd
    start AcdApiDaemon
    start fmt
    class_start amt3_services


on property:sys.lc.amtmode=1
    write /sys/class/android_usb/android0/enable 0
    write /sys/class/android_usb/android0/idVendor 18D1
    write /sys/class/android_usb/android0/idProduct 181B
    write /sys/class/android_usb/android0/functions serial,adb
    write /sys/class/android_usb/android0/f_serial/serial_port_num 5
    write /sys/class/android_usb/android0/enable 1
    setprop sys.usb.state serial,adb
    setprop sys.usb.config serial,adb
    start adbd
    start lc-oms-sa
    start emsd_amt
    start lc-oms-amt-1
    start lc-oms-mla1-u
    start lc-oms-mla2-u
    start lc-oms-mla3-u
    start lc-oms-mla4-u
    start lc-oms-mla5-u

而我们之前两个函数是get_amt_mode在前,set_usb_serial_action在后,这样在get_amt_mode执行完就会设置sys.lc.amtmode这个属性,这个属性的监听在init进程中,而后才去在set_usb_serial_action中设置sn号,这样两个动作就是异步的,就有可能会有先后问题。最后解决方法很简单,就是把这两个函数的先后顺序换一换。