Android USB Tethering的实现以及代码流程
分析还不是很全,kernel层的代码还在看,同步更新吧
直接略过界面层,界面一系列处理后调用Tethering.java的setUsbTethering函数。
public int setUsbTethering(boolean enable) {if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);synchronized (mPublicSync) {if (enable) {if (mRndisEnabled) {tetherUsb(true);} else {mUsbTetherRequested = true;usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);//一开始因为rndis还没有enable,所以会先设置function}} else {tetherUsb(false);if (mRndisEnabled) {usbManager.setCurrentFunction(null, false);}mUsbTetherRequested = false;}}return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
Java层改变usb的function,其实就是设置内核提供的接口文件进行操作的
具体可以在init.usbmode.sh里面看到
echo 0 > /sys/class/android_usb/android0/enable
echo ${VENDOR_ID} > /sys/class/android_usb/android0/idVendorif [ ${ENG_PROP} -eq 1 ] ; thenset_engpid ${USB_FUNCTION}
fiecho ${PID} > /sys/class/android_usb/android0/idProduct
/system/bin/log -t ${TAG} -p i "usb product id: ${PID}"echo 0 > /sys/class/android_usb/android0/bDeviceClass
echo 0 > /sys/class/android_usb/android0/bDeviceSubClass
echo 0 > /sys/class/android_usb/android0/bDeviceProtocolecho ${USB_FUNCTION} > /sys/class/android_usb/android0/functions
/system/bin/log -t ${TAG} -p i "enabled usb functions: ${USB_FUNCTION}"echo 1 > /sys/class/android_usb/android0/enable
首先设置enable为0,即断开,然后设置functions等,最后再 将enable设为1,也就是代表连接上了USB。设置enable会调用android.c的enable_store函数,设置fucntions会调用functions_store函数。
android.c里面的代码:
static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, functions_store);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
functions_store只是把enable的function存储到一个enabled_list里面。
重点是enable_store函数
static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,const char *buff, size_t size)
{
struct android_dev *dev = dev_get_drvdata(pdev);
struct usb_composite_dev *cdev = dev->cdev;
struct android_usb_function *f;
struct android_configuration *conf;
int enabled = 0;
static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);if (!cdev)
return -ENODEV;mutex_lock(&dev->mutex);sscanf(buff, "%d", &enabled);
if (enabled && !dev->enabled) { //enable从0设置为1时进入这个分支
/** Update values in composite driver's copy of* device descriptor.*/
cdev->desc.idVendor = device_desc.idVendor;
cdev->desc.idProduct = device_desc.idProduct;
cdev->desc.bcdDevice = device_desc.bcdDevice;
cdev->desc.bDeviceClass = device_desc.bDeviceClass;
cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
list_for_each_entry(conf, &dev->configs, list_item)
list_for_each_entry(f, &conf->enabled_functions,
enabled_list) {
if (f->enable)
f->enable(f);
}
android_enable(dev);
dev->enabled = true;
} else if (!enabled && dev->enabled) {
android_disable(dev);
list_for_each_entry(conf, &dev->configs, list_item)
list_for_each_entry(f, &conf->enabled_functions,
enabled_list) {
if (f->disable)
f->disable(f);
}
dev->enabled = false;
} else if (__ratelimit(&rl)) {
pr_err("android_usb: already %s\n",
dev->enabled ? "enabled" : "disabled");
}mutex_unlock(&dev->mutex);return size;
}
因为rndis_function没有定义enable函数,所以直接执行android_enable(dev)。Rndis_function的定义
static struct android_usb_function rndis_function = {
.name = "rndis",
.init = rndis_function_init,
.cleanup = rndis_function_cleanup,
.bind_config = rndis_function_bind_config,
.unbind_config = rndis_function_unbind_config,
.attributes = rndis_function_attributes,
};
接着看android_enable这个函数
static void android_enable(struct android_dev *dev)
{
struct usb_composite_dev *cdev = dev->cdev;
struct android_configuration *conf;if (WARN_ON(!dev->disable_depth))
return;if (--dev->disable_depth == 0) {list_for_each_entry(conf, &dev->configs, list_item)
usb_add_config(cdev, &conf->usb_config,
android_bind_config);usb_gadget_connect(cdev->gadget);//Enables the D+ (or potentially D-) pullup
}
}
主要是执行了usb_add_config函数,并且将android_bind_config传给了一个函数指针。
Usb_add_config是composite.c里面的函数
int usb_add_config(struct usb_composite_dev *cdev,
struct usb_configuration *config,
int (*bind)(struct usb_configuration *))
{
。。。。。。
status = bind(config);
。。。。。。
}
这里又回到android.c的android_bind_config函数
android_bind_config调用android_bind_enabled_functions,继续调用每个function自己注册的bind_config函数。这里调用的就是rndis的了。看看该函数rndis_function_bind_config。
static int
rndis_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
int ret;
struct rndis_function_config *rndis = f->config;if (!rndis) {
pr_err("%s: rndis_pdata\n", __func__);
return -1;
}pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);//初始化一个ethernet-over-usb link
ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "usb");
if (ret) {
pr_err("%s: gether_setup failed\n", __func__);
return ret;
}if (rndis->wceis) {
/* "Wireless" RNDIS; auto-detected by Windows */
rndis_iad_descriptor.bFunctionClass =
USB_CLASS_WIRELESS_CONTROLLER;
rndis_iad_descriptor.bFunctionSubClass = 0x01;
rndis_iad_descriptor.bFunctionProtocol = 0x03;
rndis_control_intf.bInterfaceClass =
USB_CLASS_WIRELESS_CONTROLLER;
rndis_control_intf.bInterfaceSubClass = 0x01;
rndis_control_intf.bInterfaceProtocol = 0x03;
}return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,rndis->manufacturer);
}
继续回到kernel来,现在走到了U_ether的gether_setup_name函数 这里有个rndis_function_config,他是在UsbDeviceManager初始化的时候通过sysfs赋值的。UsbDeviceManager的构造函数调用了一个叫initRndisAddress的函数。
int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname)
{
struct eth_dev *dev;
struct net_device *net;
int status;if (the_dev)
return -EBUSY;net = alloc_etherdev(sizeof *dev);
if (!net)
return -ENOMEM;dev = netdev_priv(net);
spin_lock_init(&dev->lock);
spin_lock_init(&dev->req_lock);
INIT_WORK(&dev->work, eth_work);
INIT_WORK(&dev->rx_work, process_rx_w);
INIT_LIST_HEAD(&dev->tx_reqs);
INIT_LIST_HEAD(&dev->rx_reqs);skb_queue_head_init(&dev->rx_frames);/* network device setup */
dev->net = net;
snprintf(net->name, sizeof(net->name), "%s%%d", netname);if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&g->dev,
"using random %s ethernet address\n", "self");if (get_host_ether_addr(host_ethaddr, dev->host_mac))
dev_warn(&g->dev, "using random %s ethernet address\n", "host");
else
dev_warn(&g->dev, "using previous %s ethernet address\n", "host");if (ethaddr)
memcpy(ethaddr, dev->host_mac, ETH_ALEN);net->netdev_ops = ð_netdev_ops;SET_ETHTOOL_OPS(net, &ops);dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev);
SET_NETDEV_DEVTYPE(net, &gadget_type);status = register_netdev(net); //注册网络设备
if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
free_netdev(net);
} else {
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);the_dev = dev;/* two kinds of host-initiated state changes:* - iff DATA transfer is active, carrier is "on"* - tx queueing enabled if open *and* carrier is "on"*/
netif_carrier_off(net);
}return status;
}
Eth_dev结构体包含了一个usb_gadget结构体和net_device结构体
等待补充更新
完成后,kernel会发送一个uevent
Netd接收到并处理
void NetlinkHandler::onEvent(NetlinkEvent *evt) {const char *subsys = evt->getSubsystem();if (!strcmp(subsys, "net")) {int action = evt->getAction();const char *iface = evt->findParam("INTERFACE");if (action == evt->NlActionAdd) {notifyInterfaceAdded(iface);} else if (action == evt->NlActionRemove) {notifyInterfaceRemoved(iface);} else if (action == evt->NlActionChange) {evt->dump();notifyInterfaceChanged("nana", true);} else if (action == evt->NlActionLinkUp) {notifyInterfaceLinkChanged(iface, true);} else if (action == evt->NlActionLinkDown) {notifyInterfaceLinkChanged(iface, false);}
void NetlinkHandler::notifyInterfaceAdded(const char *name) {char msg[255];snprintf(msg, sizeof(msg), "Iface added %s", name);mNm->getBroadcaster()->sendBroadcast(ResponseCode::InterfaceChange,msg, false);
}
接着就调用interfaceAdded
这里是通过socket给clients发送消息,NetworkManagementService.java的NetdCallbackReceiver会收到消息,在onEvent中进行处理
public boolean onEvent(int code, String raw, String[] cooked) {switch (code) {case NetdResponseCode.InterfaceChange:/** a network interface change occured* Format: "NNN Iface added <name>"* "NNN Iface removed <name>"* "NNN Iface changed <name> <up/down>"* "NNN Iface linkstatus <name> <up/down>"*/if (cooked.length < 4 || !cooked[1].equals("Iface")) {throw new IllegalStateException(String.format("Invalid event from daemon (%s)", raw));}if (cooked[2].equals("added")) {notifyInterfaceAdded(cooked[3]);return true;} else if (cooked[2].equals("removed")) {notifyInterfaceRemoved(cooked[3]);return true;} else if (cooked[2].equals("changed") && cooked.length == 5) {notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));return true;} else if (cooked[2].equals("linkstate") && cooked.length == 5) {notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));return true;}throw new IllegalStateException(String.format("Invalid event from daemon (%s)", raw));// break;
private void notifyInterfaceAdded(String iface) {final int length = mObservers.beginBroadcast();for (int i = 0; i < length; i++) {try {mObservers.getBroadcastItem(i).interfaceAdded(iface);} catch (RemoteException e) {}}mObservers.finishBroadcast();
}
notifyInterfaceAdded会调用到Tethering.java里面的interfaceAdded函数
具体为什么会调用到tethering.java里的函数,是因为ConnectivityService在初始化的时候将Tethering的对象mTethering register到了INetworkManagementService的实例mNetd
ConnectivityService.java
public ConnectivityService(Context context, INetworkManagementService netManager,INetworkStatsService statsService, INetworkPolicyManager policyManager,NetworkFactory netFactory) {
。。。。。。。。。。
try {mNetd.registerObserver(mTethering);mNetd.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {loge("Error registering observer :" + e);
}
registerObserver其实是把mTethering放到一个callbacklist里面,调用的时候会从这个list’里面取出来
继续看Tethering.java的interfaceAdded,
public void interfaceAdded(String iface) { boolean found = false; boolean usb = false; synchronized (mPublicSync) { if (isWifi(iface)) { found = true; } if (isUsb(iface)) { found = true; usb = true; } if (isBluetooth(iface)) { found = true; } if (found == false) { if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring"); return; } TetherInterfaceSM sm = mIfaces.get(iface); if (sm != null) { if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");return; } sm = new TetherInterfaceSM(iface, mLooper, usb); mIfaces.put(iface, sm); sm.start(); }
}
Android USB Tethering的实现以及代码流程相关推荐
- Android USB tethering相关代码
1. 代码位置 packages/apps/Settings/src/com/android/settings/TetherSettings.java frameworks/base/services ...
- Android 4.0 截屏(Screenshot)代码流程小结
Android 4.0 截屏 在Android 4.0 之前,Android手机上如果要使用截屏功能,只能通过Root手机,且使用第3方截图软件来实现截屏功能. Android4.0中,系统自带了截屏 ...
- Android Q USB Tethering 端口切换分析
需求:在开启 USB Tethering 后,同时需要开启 diag 端口供 QXDM 调试使用.于是 trace code 大概分析了一下设置 USB Tethering 过程,比较毛糙,如有不正之 ...
- Android USB转串口通信开发基本流程
好久没有写文章了,年前公司新开了一个项目,是和usb转串口通信相关的,需求是用安卓平板通过usb转接后与好几个外设进行通信.一直忙到近期,才慢慢闲下来,趁着这个周末不忙.记录下usb转串口通信开发的基 ...
- android加载efi分区,高通Android UEFI XBL 代码流程分析
高通Android UEFI XBL 代码流程分析 背景 之前学习的lk阶段点亮LCD的流程算是比较经典,但是高通已经推出了很多种基于UEFI方案的启动架构. 所以需要对这块比较新的技术进行学习.在学 ...
- android uefi 编译报错,【Android SDM660开机流程】- UEFI XBL 代码流程分析
[Android SDM660开机流程]- UEFI XBL 代码流程分析 一.UEFI XBL 1.1 boot_images代码目录 1.2 UEFI代码运行流程 1.3 SEC (安全验证) 1 ...
- Android usb学习笔记:Android AOA协议Android端 流程总结
背景 上篇文章中我们了解了嵌入式设备端将Android手机设置为accessory模式的流程以及嵌入式设备端接收和发送数据的流程,本文将对应介绍Android端accessory模式被激活的过程,以及 ...
- 全志 android 编译,全志A20启动代码流程分析 ——Android
现在的CPU都固化了内部 ROM,内部 ROM中有一般都有一段程序,一般有如下几个功能: 1,初始化,部分外设,如USB,SDCARD 2,初始化DDR(内存)和NandFlash 3,加载boot( ...
- 全志android 编译,全志A20启动代码流程分析 ——Android
现在的CPU都固化了内部 ROM,内部 ROM中有一般都有一段程序,一般有如下几个功能: 1,初始化,部分外设,如USB,SDCARD 2,初始化DDR(内存)和NandFlash 3,加载boot( ...
最新文章
- 鸿蒙系统3.0演示,华为鸿蒙系统3.0-华为鸿蒙系统3.0官网申请地址预约 v1.0-优盘手机站...
- 启动ubuntu什么时候按shift_找回消失的ubuntu启动选项
- Java 第二章 程序设计基础
- jquery $(document).ready() 与window.onload的区别
- C/C++语言宏定义##连接符和符#的使用
- 怎么让员工服从管理_为什么现在的员工执行力和服从性越来越差,管理一严格就辞职?...
- 利用Aria2高速下载网盘文件
- LumaQQ.NET,基于LumaQQ的.NET开源QQ开发包
- python函数后面的点_对python函数后面有多个括号的理解?
- python学习手册(1)
- 部分beamforming知识汇总
- jQuery手动触发事件
- 解决win10桌面无法删除ie浏览器图标
- IT与DT技术几点解释
- iOS常用的第三方库
- 微信公众号第三方平台授权流程
- 券商Robinhood大量客户被最低价格强平-交易成本拉大500倍,游戏驿站GME只能平仓不能开仓-看看行政总裁Vlad Tenev是如何回复这些问题的?
- slot具名卡槽和props
- 波段测试软件,超好用的波段副图(通达信公式 副图 源码 测试图)
- LocalDate、LocalTime、LocalDateTime使用与区别
热门文章
- pandas常用操作以及eda分析笔记(自用)
- 开源项目 ——API接口管理平台数据库原型设计(三)
- Android Material Design简单使用 http://www.cnblogs.com/android-blogs/p/5632103.html
- 格美净水器:家用净水器必看的6点
- 关于TR1900错误的一些解决方法(引用冯哥)
- 【电脑办公软件有哪些】万彩办公大师教程丨重复音频文件探测工具
- 数字图像处理:局部直方图处理(Local Histogram Processing)
- 用Notepad++ 宏功能 将json数据转换为EXCEL
- Programming Rust Fast, Safe Systems Development(译) 表达式(第六章 完)
- 2021-08-30-全排列-逆序数-排列的奇偶性