android USB绑定功能实现(fr…
2013-12-19 20:56
423 查看
settings app中点击使能Tether的开关进入到如下函数:
TetherSettings.java:
[java] view
plaincopy
private void setUsbTethering(boolean enabled) {
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm.setUsbTethering(enabled) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
mUsbTether.setChecked(false);
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
return;
}
mUsbTether.setSummary("");
}
ConnectivityManager cm远程调用
ConnectivityService中的函数:
[java] view
plaincopy
public int setUsbTethering(boolean enable) {
enforceTetherAccessPermission();
if (isTetheringSupported()) {
return mTethering.setUsbTethering(enable);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
}
其中mTethering是一个Tethering对象。
--Tethering.java:
[java] view
plaincopy
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);
}
} else {
tetherUsb(false);
if (mRndisEnabled) {
usbManager.setCurrentFunction(null, false);
}
mUsbTetherRequested = false;
}
}
return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
mRndisEnabled表示驱动中USB
Tether设备是否成功加载。该变量在以下函数中更新:
[java] view
plaincopy
private class StateReceiver extends BroadcastReceiver {
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
if (action.equals(UsbManager.ACTION_USB_STATE)) {
synchronized (Tethering.this.mPublicSync) {
boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
boolean usbMass = intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false);
mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
// start tethering if we have a request pending
if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
tetherUsb(true);
} else if (!usbConnected ) {
Log.d(TAG, "usb disconnected ,try Tethering down");
tetherUsb(false);
}
mUsbTetherRequested = false;
}
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
}
}
}
据实际分析,在USB
DeviceManager中发送 ACTION_USB_STATE广播时,将Extra域都置为了true。所以这里mRndisEnabled
= true
代码参考;
[java] view
plaincopy
private void updateUsbState() {
// send a sticky broadcast containing current USB state
Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
if (mCurrentFunctions != null) {
String[] functions = mCurrentFunctions.split(",");
for (int i = 0; i < functions.length; i++) {
intent.putExtra(functions[i], true);
}
}
mContext.sendStickyBroadcast(intent);
}
下面执行到 tetherUsb(true);
[java] view
plaincopy
private void tetherUsb(boolean enable) {
if (VDBG) Log.d(TAG, "tetherUsb " + enable);
String[] ifaces = new String[0];
try {
ifaces = mNMService.listInterfaces();
} catch (Exception e) {
Log.e(TAG, "Error listing Interfaces", e);
return;
}
for (String iface : ifaces) {
if (VDBG) Log.d(TAG, "iface = " + iface);
if (isUsb(iface)) {
int result = (enable ? tether(iface) : untether(iface));
if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
return;
}
}
}
Log.e(TAG, "unable start or stop USB tethering");
}
ListInterfaces函数会通过socket发送一个 list
interface命令给netd,netd收到这个命令后,会扫描sys/class/net目录下的设备,并且报告给java层。这样 ifaces中就存储了系统所有网络设备。接下来循环通过isUsb判断这个接口是不是USB
tether类型。判断方式是通过一个config文件的定义的正则表达式来的。所以在移植tether这部分代码的时候注意关系config.xml中的表达式是否能正确匹配到网络接口设备。
继续执行到 tether函数:
[java] view
plaincopy
public int tether(String iface) {
if (DBG) Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null;
synchronized (mPublicSync) {
sm = mIfaces.get(iface);
//add by kondy
if (sm == null) {
if (DBG) Log.d(TAG, "try add " + iface);
interfaceAdded(iface);
sm = mIfaces.get(iface);
}
}
if (sm == null) {
Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
}
if (!sm.isAvailable() && !sm.isErrored()) {
Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
}
sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
mIfaces记录了netd主动上发了接口 add
remove change消息的接口信息,与上面ifaces存储的内容有主动和被动的差别。mIfaces记录所这些接口理论上也是从netd(是一个网络设备相关的守护程序)通过socket发送(主动)给java层的。当内核中有网络设备 add
remove state change等发生的时候,会通过netlink通知用户空间。Netd就是一个监听netlink消息的程序。但是也许是因为本系统的usb
tether设备驱动是静态加载的。可能没有add消息产生,所以导致 mNMService中激励的interface
list中不存在usb0设备。所以上面代码中我主动往mIfaces中增加了我们的tether设备。
随后应该去看看CMD_TETHER_REQUEST的消息处理了:
[java] view
plaincopy
case CMD_TETHER_REQUESTED:
setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
TetherInterfaceSM.this);
transitionTo(mStartingState);
break;
上面的代码通过transitionTo函数让当前Tether状态从init转换到starting,android的状态机的实现使能执行该函数时会自动释放前一状态使用的资源,并且执行下一个状态的初始化过程。
MstartingState的定义是一个State变量,但是实际是一个子类对象,让SmHandle通过多态进行管理
[java] view
plaincopy
mStartingState = new StartingState();
addState(mStartingState);
transitionTo会自动条用 StartingState的enter函数:
[java] view
plaincopy
public void enter() {
setAvailable(false);
if (mUsb) {
if (!Tethering.this.configureUsbIface(true)) {
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
TetherInterfaceSM.this);
setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
transitionTo(mInitialState);
return;
}
}
sendTetherStateChangedBroadcast();
// Skipping StartingState
transitionTo(mTetheredState);
}
enter中通过函数 configureUsbIface的作用是将上层的配置发送到netd,使上下配置同步。继续往下走,将当前状态由Starting,改为Tethered。MTetheredState是一个 TetheredState 类型的状态机变量。TetheredState的enter函数定义如下:
[java] view
plaincopy
public void enter() {
try {
mNMService.tetherInterface(mIfaceName);
} catch (Exception e) {
Log.e(TAG, "Error Tethering: " + e.toString());
setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
transitionTo(mInitialState);
return;
}
if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
setAvailable(false);
setTethered(true);
sendTetherStateChangedBroadcast();
}
其中调用了tetherInterface便是真正执行tether操作的函数了。我们去networkManagerService.java中看看这个函数:
果然!通过发送命令 tether
interface add usb0到netd程序完成与Native的通信。
在netd的CommandListener中会处理这个消息。
CommandListenner.c TetherCmd::runCommand函数中有如下定义:
[cpp] view
plaincopy
else if (!strcmp(argv[1], "interface")) {
if (!strcmp(argv[2], "add")) {
rc = sTetherCtrl->tetherInterface(argv[3]);
} else if (!strcmp(argv[2], "remove")) {
rc = sTetherCtrl->untetherInterface(argv[3]);
} else if (!strcmp(argv[2], "list")) {
InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
InterfaceCollection::iterator it;
for (it = ilist->begin(); it != ilist->end(); ++it) {
cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
}
} else {
cli->sendMsg(ResponseCode::CommandParameterError,
"Unknown tether interface operation", false);
return 0;
}
}
如果命令是add,则会执行TetherController中的 tetherInterface。我们一起去看看这个函数:
[cpp] view
plaincopy
int TetherController::tetherInterface(const char *interface) {
LOGD("tetherInterface [%s]", interface);
//add by kondy
if (!strcmp(interface, USB_TETHER_INTERFACE)) {
enableRNDIS(true);
}
mInterfaces->push_back(strdup(interface));
return 0;
}
该函数将参数表示的接口添加进一个队列。注意移植本程序时需要在这个函数中真正开启Tether功能。至于开启的方法则与驱动有关。此处通过调用 enableRNDIS会像USB0驱动程序暴露的一个enable文件写1来使能驱动程序。如果是动态insmod的驱动,可能需要手动加载驱动。
至于驱动程序,应该将device模拟成一个USB网卡。网上应该有相关源码,ubuntu可以自动加载驱动,erwindows需要下载一个inf文件手动加载驱动。
至此,从app->
framework ->Native ->驱动接口流程便走通了,至于tether的其他操作莫不遵循此条主线。
By kuangkondy@gmail.com
2012 0223
TetherSettings.java:
[java] view
plaincopy
private void setUsbTethering(boolean enabled) {
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm.setUsbTethering(enabled) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
mUsbTether.setChecked(false);
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
return;
}
mUsbTether.setSummary("");
}
ConnectivityManager cm远程调用
ConnectivityService中的函数:
[java] view
plaincopy
public int setUsbTethering(boolean enable) {
enforceTetherAccessPermission();
if (isTetheringSupported()) {
return mTethering.setUsbTethering(enable);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
}
其中mTethering是一个Tethering对象。
--Tethering.java:
[java] view
plaincopy
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);
}
} else {
tetherUsb(false);
if (mRndisEnabled) {
usbManager.setCurrentFunction(null, false);
}
mUsbTetherRequested = false;
}
}
return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
mRndisEnabled表示驱动中USB
Tether设备是否成功加载。该变量在以下函数中更新:
[java] view
plaincopy
private class StateReceiver extends BroadcastReceiver {
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
if (action.equals(UsbManager.ACTION_USB_STATE)) {
synchronized (Tethering.this.mPublicSync) {
boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
boolean usbMass = intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false);
mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
// start tethering if we have a request pending
if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
tetherUsb(true);
} else if (!usbConnected ) {
Log.d(TAG, "usb disconnected ,try Tethering down");
tetherUsb(false);
}
mUsbTetherRequested = false;
}
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
}
}
}
据实际分析,在USB
DeviceManager中发送 ACTION_USB_STATE广播时,将Extra域都置为了true。所以这里mRndisEnabled
= true
代码参考;
[java] view
plaincopy
private void updateUsbState() {
// send a sticky broadcast containing current USB state
Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
if (mCurrentFunctions != null) {
String[] functions = mCurrentFunctions.split(",");
for (int i = 0; i < functions.length; i++) {
intent.putExtra(functions[i], true);
}
}
mContext.sendStickyBroadcast(intent);
}
下面执行到 tetherUsb(true);
[java] view
plaincopy
private void tetherUsb(boolean enable) {
if (VDBG) Log.d(TAG, "tetherUsb " + enable);
String[] ifaces = new String[0];
try {
ifaces = mNMService.listInterfaces();
} catch (Exception e) {
Log.e(TAG, "Error listing Interfaces", e);
return;
}
for (String iface : ifaces) {
if (VDBG) Log.d(TAG, "iface = " + iface);
if (isUsb(iface)) {
int result = (enable ? tether(iface) : untether(iface));
if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
return;
}
}
}
Log.e(TAG, "unable start or stop USB tethering");
}
ListInterfaces函数会通过socket发送一个 list
interface命令给netd,netd收到这个命令后,会扫描sys/class/net目录下的设备,并且报告给java层。这样 ifaces中就存储了系统所有网络设备。接下来循环通过isUsb判断这个接口是不是USB
tether类型。判断方式是通过一个config文件的定义的正则表达式来的。所以在移植tether这部分代码的时候注意关系config.xml中的表达式是否能正确匹配到网络接口设备。
继续执行到 tether函数:
[java] view
plaincopy
public int tether(String iface) {
if (DBG) Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null;
synchronized (mPublicSync) {
sm = mIfaces.get(iface);
//add by kondy
if (sm == null) {
if (DBG) Log.d(TAG, "try add " + iface);
interfaceAdded(iface);
sm = mIfaces.get(iface);
}
}
if (sm == null) {
Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
}
if (!sm.isAvailable() && !sm.isErrored()) {
Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
}
sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
mIfaces记录了netd主动上发了接口 add
remove change消息的接口信息,与上面ifaces存储的内容有主动和被动的差别。mIfaces记录所这些接口理论上也是从netd(是一个网络设备相关的守护程序)通过socket发送(主动)给java层的。当内核中有网络设备 add
remove state change等发生的时候,会通过netlink通知用户空间。Netd就是一个监听netlink消息的程序。但是也许是因为本系统的usb
tether设备驱动是静态加载的。可能没有add消息产生,所以导致 mNMService中激励的interface
list中不存在usb0设备。所以上面代码中我主动往mIfaces中增加了我们的tether设备。
随后应该去看看CMD_TETHER_REQUEST的消息处理了:
[java] view
plaincopy
case CMD_TETHER_REQUESTED:
setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
TetherInterfaceSM.this);
transitionTo(mStartingState);
break;
上面的代码通过transitionTo函数让当前Tether状态从init转换到starting,android的状态机的实现使能执行该函数时会自动释放前一状态使用的资源,并且执行下一个状态的初始化过程。
MstartingState的定义是一个State变量,但是实际是一个子类对象,让SmHandle通过多态进行管理
[java] view
plaincopy
mStartingState = new StartingState();
addState(mStartingState);
transitionTo会自动条用 StartingState的enter函数:
[java] view
plaincopy
public void enter() {
setAvailable(false);
if (mUsb) {
if (!Tethering.this.configureUsbIface(true)) {
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
TetherInterfaceSM.this);
setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
transitionTo(mInitialState);
return;
}
}
sendTetherStateChangedBroadcast();
// Skipping StartingState
transitionTo(mTetheredState);
}
enter中通过函数 configureUsbIface的作用是将上层的配置发送到netd,使上下配置同步。继续往下走,将当前状态由Starting,改为Tethered。MTetheredState是一个 TetheredState 类型的状态机变量。TetheredState的enter函数定义如下:
[java] view
plaincopy
public void enter() {
try {
mNMService.tetherInterface(mIfaceName);
} catch (Exception e) {
Log.e(TAG, "Error Tethering: " + e.toString());
setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
transitionTo(mInitialState);
return;
}
if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
setAvailable(false);
setTethered(true);
sendTetherStateChangedBroadcast();
}
其中调用了tetherInterface便是真正执行tether操作的函数了。我们去networkManagerService.java中看看这个函数:
果然!通过发送命令 tether
interface add usb0到netd程序完成与Native的通信。
在netd的CommandListener中会处理这个消息。
CommandListenner.c TetherCmd::runCommand函数中有如下定义:
[cpp] view
plaincopy
else if (!strcmp(argv[1], "interface")) {
if (!strcmp(argv[2], "add")) {
rc = sTetherCtrl->tetherInterface(argv[3]);
} else if (!strcmp(argv[2], "remove")) {
rc = sTetherCtrl->untetherInterface(argv[3]);
} else if (!strcmp(argv[2], "list")) {
InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
InterfaceCollection::iterator it;
for (it = ilist->begin(); it != ilist->end(); ++it) {
cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
}
} else {
cli->sendMsg(ResponseCode::CommandParameterError,
"Unknown tether interface operation", false);
return 0;
}
}
如果命令是add,则会执行TetherController中的 tetherInterface。我们一起去看看这个函数:
[cpp] view
plaincopy
int TetherController::tetherInterface(const char *interface) {
LOGD("tetherInterface [%s]", interface);
//add by kondy
if (!strcmp(interface, USB_TETHER_INTERFACE)) {
enableRNDIS(true);
}
mInterfaces->push_back(strdup(interface));
return 0;
}
该函数将参数表示的接口添加进一个队列。注意移植本程序时需要在这个函数中真正开启Tether功能。至于开启的方法则与驱动有关。此处通过调用 enableRNDIS会像USB0驱动程序暴露的一个enable文件写1来使能驱动程序。如果是动态insmod的驱动,可能需要手动加载驱动。
至于驱动程序,应该将device模拟成一个USB网卡。网上应该有相关源码,ubuntu可以自动加载驱动,erwindows需要下载一个inf文件手动加载驱动。
至此,从app->
framework ->Native ->驱动接口流程便走通了,至于tether的其他操作莫不遵循此条主线。
By kuangkondy@gmail.com
2012 0223
相关文章推荐
- android&nbsp;USB绑定功能实现(fr…
- 使用 Android 手机上的 "USB 绑定"功能
- Android&nbsp;软件自动更新功能的实现
- WinCE的USB Device功能实现(S…
- android USB绑定功能实现(framework)
- android USB绑定功能实现(framework)
- android USB绑定功能实现(framework)
- WinCE系统 USB Serial实现
- Linux USB Gadget 实现我们自己的ADB(android debug bridge ),Linux下高级调试功能(一)
- Android&nbsp;ViewPager实现应用…
- UT-S3C6410 android系统实现同伙usb wifi无线上网功能
- Android中ListView绑定CheckBox实现全选增加和删除功能(DEMO)
- android 简单截图功能…
- Android高级控件(一)——ListView绑定CheckBox实现全选,增加和删除等功能
- android&nbsp;如何实现apk&nbsp;search出现在…
- android中Handler简介&利用Handler实现计时功能
- 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重新启动的功能(二)Androidclient功能展示
- android 实现图片加水印
- Android高级控件(一)——ListView绑定CheckBox实现全选,增加和删除等功能
- Android高级控件(一)——ListView绑定CheckBox实现全选,增加和删除等功能