我最近在调试Android系统的gadget功能,通过make menuconfig发现gadget是编译成module模式的。里面有很多可选项,其中有个Android的选项,其实就是提供ADB和Storage的功能的。
具体查看代码在/drivers/usb/gadget下,三个文件:android.c f_adb.c f_mass_storage.c
g_android.ko 是由这三个文件而来,其中android.c 依赖于f_adb.c 和f_mass_storage.c(这两个文件之间无依赖关系)
可以在android.c中的
static int __init android_bind_config(struct usb_configuration *c) { struct android_dev *dev = _android_dev; int ret; printk(KERN_DEBUG "android_bind_config/n"); ret = mass_storage_function_add(dev->cdev, c, dev->nluns); if (ret) return ret; return adb_function_add(dev->cdev, c); }
看到关系
============================================================
下面说说我的问题,
1.当我将Android编译成module模式,既g_android.ko时候,然后放入rootfs中手动加载,Okay, no problem!非常happy。但是,当我关闭adb进程,rmmod g_android的时候,出现死锁状态,打开代码进行查询,发现问题出现在
struct usb_request *req_get(struct adb_dev *dev, struct list_head *head, int DD) { unsigned long flags; struct usb_request *req; spin_lock_irqsave(&dev->lock, flags);//被锁了,郁闷 if (list_empty(head)) { req = 0; } else { req = list_first_entry(head, struct usb_request, list); list_del(&req->list); } spin_unlock_irqrestore(&dev->lock, flags); return req; }
一直死锁,通过打开kernel hacking中的spinlock debug发现 是自己把自己锁了,找阿找阿。。。。
看了下rmmod时候 函数调用过程当我rmmod的时候,首先会去执行__exit cleanup(void)中的usb_composite_unregister(&android_usb_driver)这句话中还调用composite.c中的函数 (不细说),反正最后会调到f_adb.c中的
adb_function_unbind(struct usb_configuration *c, struct usb_function *f)
看看这个函数
static void adb_function_unbind(struct usb_configuration *c, struct usb_function *f) { struct adb_dev *dev = func_to_dev(f); struct usb_request *req; spin_lock_irq(&dev->lock);//锁死你个req_get,谁叫我们共用一个dev->lock while ((req=req_get(dev, &dev->rx_idle,0)))//被所到死 { adb_request_free(req, dev->ep_out); } while ((req=req_get(dev, &dev->tx_idle,0))) { adb_request_free(req, dev->ep_in); } dev->online = 0; dev->error = 1; spin_unlock_irq(&dev->lock); misc_deregister(&adb_device); kfree(_adb_dev); _adb_dev = NULL; }
所以感觉 req_get代码中的spinlock有问题,没办法,只能写了个req_get_free_lock(不加锁)替代while循环中的req_get函数
rebuild 内核,Okay 卸载g_android.ko 没问题 哈哈。正当自己高兴的时候,发现乐极生悲了。。。
===========================================================
卸载完了g_android.ko 我再次insmod g_android.ko 挂了,不过不是kernel panic而是提示
"sysfs: duplicate filename 'usb_mass_storage' can not be created"
恩 这次出在f_mass_storage.c这个文件中,根据信息提示应该是没因为上次没卸载完全。没办法,在几个与insmod和rmmod的函数中加入打印信息。主要是mass_storage_function_add, fsg_function_bind,fsg_function_unbind三个函数,前两个是跟insmod有关,后者跟rmmod有关。
通过打印信息发现一个Android开发者的 小纰漏 导致的问题,就是在
int __init mass_storage_function_add(struct usb_composite_dev *cdev, struct usb_configuration *c, int nluns) { int rc; struct fsg_dev *fsg; printk(KERN_INFO "mass_storage_function_add/n"); rc = fsg_alloc(); if (rc) return rc; fsg = the_fsg; fsg->nluns = nluns; spin_lock_init(&fsg->lock); init_rwsem(&fsg->filesem); kref_init(&fsg->ref); init_completion(&fsg->thread_notifier); the_fsg->buf_size = BULK_BUFFER_SIZE; the_fsg->sdev.name = DRIVER_NAME; the_fsg->sdev.print_name = print_switch_name; the_fsg->sdev.print_state = print_switch_state; rc = switch_dev_register(&the_fsg->sdev);//卸载的时候没有swith_dev_unregister if (rc < 0) goto err_switch_dev_register; wake_lock_init(&the_fsg->wake_lock, WAKE_LOCK_SUSPEND, "usb_mass_storage"); fsg->cdev = cdev; fsg->function.name = shortname; fsg->function.descriptors = fs_function; fsg->function.bind = fsg_function_bind; fsg->function.unbind = fsg_function_unbind; fsg->function.setup = fsg_function_setup; fsg->function.set_alt = fsg_function_set_alt; fsg->function.disable = fsg_function_disable; rc = usb_add_function(c, &fsg->function); if (rc != 0) goto err_usb_add_function; return 0; err_usb_add_function: switch_dev_unregister(&the_fsg->sdev); err_switch_dev_register: kref_put(&the_fsg->ref, fsg_release); return rc; }
在掉用过/drivers/switch/class_switch.c 中的 switch_dev_register后,除了出错处理再也没作擦屁股的动作(unregister)汗,这不是占着XX不拉什么吗?没办法,去fsg_function_unbind函数中的
for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; if (curlun->registered) { switch_dev_unregister(&the_fsg->sdev);//加入擦屁股的一句 device_remove_file(&curlun->dev, &dev_attr_file); device_unregister(&curlun->dev); curlun->registered = 0; } }
Okay 万事Okay 主阿!其实都不是什么大的问题拉。但是导致的现象确很恐怖。android developer太忙了,毕竟也是人阿。呵呵,以前都不敢改他们代码,总是推敲自己是不是哪边错了。想报bug去android开发者论坛,但是被该死的河蟹给和谐了,打不开report issue界面。感谢伟大的政府让我们这些P民,成为白痴和弱智。
草泥马的 !