现在的位置: 首页 > 综合 > 正文

android USB绑定功能实现(framework)

2013年03月06日 ⁄ 综合 ⁄ 共 20025字 ⁄ 字号 评论关闭
分类:
Android

1357人阅读
评论(0)
收藏
举报

settings app中点击使能Tether的开关进入到如下函数:

TetherSettings.java

  1. private void setUsbTethering(boolean enabled) {  
  2.     ConnectivityManager cm =  
  3.         (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);  
  4.     if (cm.setUsbTethering(enabled) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {  
  5.         mUsbTether.setChecked(false);  
  6.         mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);  
  7.         return;  
  8.     }  
  9.     mUsbTether.setSummary("");  
  10. }  

ConnectivityManager cm远程调用  ConnectivityService中的函数:

  1. public int setUsbTethering(boolean enable) {  
  2.     enforceTetherAccessPermission();  
  3.     if (isTetheringSupported()) {  
  4.         return mTethering.setUsbTethering(enable);  
  5.     } else {  
  6.         return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;  
  7.     }  
  8. }  

其中mTethering是一个Tethering对象。

--Tethering.java

  1. public int setUsbTethering(boolean enable) {  
  2.     if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");  
  3.     UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);  
  4.   
  5.     synchronized (mPublicSync) {  
  6.         if (enable) {  
  7.             if (mRndisEnabled) {  
  8.                 tetherUsb(true);  
  9.             } else {  
  10.                 mUsbTetherRequested = true;  
  11.                 usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);  
  12.             }  
  13.         } else {  
  14.             tetherUsb(false);  
  15.             if (mRndisEnabled) {  
  16.                 usbManager.setCurrentFunction(nullfalse);  
  17.             }  
  18.             mUsbTetherRequested = false;  
  19.         }  
  20.     }  
  21.     return ConnectivityManager.TETHER_ERROR_NO_ERROR;  
  22. }  

mRndisEnabled表示驱动中USB Tether设备是否成功加载。该变量在以下函数中更新:

    

  1. private class StateReceiver extends BroadcastReceiver {  
  2.         public void onReceive(Context content, Intent intent) {  
  3.             String action = intent.getAction();  
  4.             if (action.equals(UsbManager.ACTION_USB_STATE)) {  
  5.                 synchronized (Tethering.this.mPublicSync) {  
  6.                     boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);  
  7.                     boolean usbMass = intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false);  
  8.                     mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);  
  9.   
  10.                     // start tethering if we have a request pending
      
  11.                     if (usbConnected && mRndisEnabled && mUsbTetherRequested) {  
  12.                         tetherUsb(true);  
  13.                     } else if (!usbConnected ) {  
  14.                         Log.d(TAG, "usb disconnected ,try Tethering down");  
  15.                         tetherUsb(false);  
  16.                     }  
  17.                     mUsbTetherRequested = false;  
  18.                 }  
  19.             } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {  
  20.                 if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");  
  21.                 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);  
  22.             }  
  23.         }  
  24.     }  

据实际分析,在USB DeviceManager发送 ACTION_USB_STATE广播时,将Extra域都置为了true。所以这里mRndisEnabled
= true

代码参考;

  1. private void updateUsbState() {  
  2.     // send a sticky broadcast containing current USB state
      
  3.     Intent intent = new Intent(UsbManager.ACTION_USB_STATE);  
  4.     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);  
  5.     intent.putExtra(UsbManager.USB_CONNECTED, mConnected);  
  6.     intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);  
  7.   
  8.     if (mCurrentFunctions != null) {  
  9.         String[] functions = mCurrentFunctions.split(",");  
  10.         for (int i = 0; i < functions.length; i++) {  
  11.             intent.putExtra(functions[i], true);  
  12.         }  
  13.     }  
  14.   
  15.     mContext.sendStickyBroadcast(intent);  
  16. }  

下面执行到 tetherUsb(true);

 

  1. private void tetherUsb(boolean enable) {  
  2.      if (VDBG) Log.d(TAG, "tetherUsb " + enable);  
  3.   
  4.      String[] ifaces = new String[0];  
  5.      try {  
  6.          ifaces = mNMService.listInterfaces();  
  7.      } catch (Exception e) {  
  8.          Log.e(TAG, "Error listing Interfaces", e);  
  9.          return;  
  10.      }  
  11.      for (String iface : ifaces) {  
  12.          if (VDBG) Log.d(TAG, "iface = " + iface);  
  13.          if (isUsb(iface)) {  
  14.              int result = (enable ? tether(iface) : untether(iface));  
  15.              if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {  
  16.                  return;  
  17.              }  
  18.          }  
  19.      }  
  20.      Log.e(TAG, "unable start or stop USB tethering");  
  21.  }  

ListInterfaces函数会通过socket发送一个 list interface命令给netdnetd收到这个命令后,会扫描sys/class/net目录下的设备,并且报告给java层。这样
ifaces
中就存储了系统所有网络设备。接下来循环通过isUsb判断这个接口是不是USB tether类型。判断方式是通过一个config文件的定义的正则表达式来的。所以在移植tether这部分代码的时候注意关系config.xml中的表达式是否能正确匹配到网络接口设备。

继续执行到 tether函数:

  1. public int tether(String iface) {  
  2.     if (DBG) Log.d(TAG, "Tethering " + iface);  
  3.     TetherInterfaceSM sm = null;  
  4.     synchronized (mPublicSync) {  
  5.         sm = mIfaces.get(iface);  
  6.   
  7.         //add by kondy
      
  8.         if (sm == null) {  
  9.             if (DBG) Log.d(TAG, "try add  " + iface);  
  10.             interfaceAdded(iface);  
  11.             sm = mIfaces.get(iface);  
  12.         }  
  13.   
  14.     }   
  15.     if (sm == null) {  
  16.         Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");  
  17.         return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;  
  18.     }  
  19.     if (!sm.isAvailable() && !sm.isErrored()) {  
  20.         Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");  
  21.         return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;  
  22.     }  
  23.     sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);  
  24.     return ConnectivityManager.TETHER_ERROR_NO_ERROR;  
  25. }  

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的消息处理了:

  1. case CMD_TETHER_REQUESTED:  
  2.     setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);  
  3.     mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,  
  4.             TetherInterfaceSM.this);  
  5.     transitionTo(mStartingState);  
  6.     break;  

上面的代码通过transitionTo函数让当前Tether状态从init转换到starting,android的状态机的实现使能执行该函数时会自动释放前一状态使用的资源,并且执行下一个状态的初始化过程。

MstartingState的定义是一个State变量,但是实际是一个子类对象,让SmHandle通过多态进行管理

  1. mStartingState = new StartingState();  
  2.             addState(mStartingState);  

transitionTo会自动条用 StartingStateenter函数:

            

  1. public void enter() {  
  2.                 setAvailable(false);  
  3.                 if (mUsb) {  
  4.                     if (!Tethering.this.configureUsbIface(true)) {  
  5.                         mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,  
  6.                                 TetherInterfaceSM.this);  
  7.                         setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);  
  8.   
  9.                         transitionTo(mInitialState);  
  10.                         return;  
  11.                     }  
  12.                 }  
  13.                 sendTetherStateChangedBroadcast();  
  14.   
  15.                 // Skipping StartingState
      
  16.                 transitionTo(mTetheredState);  
  17.             }  

enter中通过函数 configureUsbIface的作用是将上层的配置发送到netd,使上下配置同步。继续往下走,将当前状态由Starting,改为TetheredMTetheredState是一个
TetheredState 类型的状态机变量。TetheredStateenter函数定义如下:

 

  1. public void enter() {  
  2.      try {  
  3.          mNMService.tetherInterface(mIfaceName);  
  4.      } catch (Exception e) {  
  5.          Log.e(TAG, "Error Tethering: " + e.toString());  
  6.          setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);  
  7.   
  8.          transitionTo(mInitialState);  
  9.          return;  
  10.      }  
  11.      if (DBG) Log.d(TAG, "Tethered " + mIfaceName);  
  12.      setAvailable(false);  
  13.      setTethered(true);  
  14.      sendTetherStateChangedBroadcast();  
  15.  }  

其中调用了tetherInterface便是真正执行tether操作的函数了。我们去networkManagerService.java中看看这个函数:

  

果然!通过发送命令 tether interface add usb0netd程序完成与Native的通信。

netdCommandListener中会处理这个消息。

CommandListenner.c TetherCmd::runCommand函数中有如下定义:

  1. else if (!strcmp(argv[1], "interface")) {  
  2.             if (!strcmp(argv[2], "add")) {  
  3.                 rc = sTetherCtrl->tetherInterface(argv[3]);  
  4.             } else if (!strcmp(argv[2], "remove")) {  
  5.                 rc = sTetherCtrl->untetherInterface(argv[3]);  
  6.             } else if (!strcmp(argv[2], "list")) {  
  7.                 InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();  
  8.                 InterfaceCollection::iterator it;  
  9.   
  10.                 for (it = ilist->begin(); it != ilist->end(); ++it) {  
  11.                     cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);  
  12.                 }  
  13.             } else {  
  14.                 cli->sendMsg(ResponseCode::CommandParameterError,  
  15.                              "Unknown tether interface operation"false);  
  16.                 return 0;  
  17.             }  
  18.         }   

如果命令是add,则会执行TetherController中的 tetherInterface。我们一起去看看这个函数:

  1. int TetherController::tetherInterface(const char *interface) {  
  2.     LOGD("tetherInterface [%s]", interface);  
  3.       
  4.     //add by kondy   
  5.     if (!strcmp(interface, USB_TETHER_INTERFACE)) {  
  6.         enableRNDIS(true);  
  7.     }  
  8.   
  9.     mInterfaces->push_back(strdup(interface));  
  10.     return 0;  
  11. }  

该函数将参数表示的接口添加进一个队列。注意移植本程序时需要在这个函数中真正开启Tether功能。至于开启的方法则与驱动有关。此处通过调用 enableRNDIS会像USB0驱动程序暴露的一个enable文件写1来使能驱动程序。如果是动态insmod的驱动,可能需要手动加载驱动。

至于驱动程序,应该将device模拟成一个USB网卡。网上应该有相关源码,ubuntu可以自动加载驱动,erwindows需要下载一个inf文件手动加载驱动。

至此,从app-> framework ->Native ->驱动接口流程便走通了,至于tether的其他操作莫不遵循此条主线。

             By
k
uangkondy@gmail.com

              2012 0223

settings app中点击使能Tether的开关进入到如下函数:

TetherSettings.java

  1. private void setUsbTethering(boolean enabled) {  
  2.     ConnectivityManager cm =  
  3.         (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);  
  4.     if (cm.setUsbTethering(enabled) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {  
  5.         mUsbTether.setChecked(false);  
  6.         mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);  
  7.         return;  
  8.     }  
  9.     mUsbTether.setSummary("");  
  10. }  

ConnectivityManager cm远程调用  ConnectivityService中的函数:

  1. public int setUsbTethering(boolean enable) {  
  2.     enforceTetherAccessPermission();  
  3.     if (isTetheringSupported()) {  
  4.         return mTethering.setUsbTethering(enable);  
  5.     } else {  
  6.         return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;  
  7.     }  
  8. }  

其中mTethering是一个Tethering对象。

--Tethering.java

  1. public int setUsbTethering(boolean enable) {  
  2.     if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");  
  3.     UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);  
  4.   
  5.     synchronized (mPublicSync) {  
  6.         if (enable) {  
  7.             if (mRndisEnabled) {  
  8.                 tetherUsb(true);  
  9.             } else {  
  10.                 mUsbTetherRequested = true;  
  11.                 usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);  
  12.             }  
  13.         } else {  
  14.             tetherUsb(false);  
  15.             if (mRndisEnabled) {  
  16.                 usbManager.setCurrentFunction(nullfalse);  
  17.             }  
  18.             mUsbTetherRequested = false;  
  19.         }  
  20.     }  
  21.     return ConnectivityManager.TETHER_ERROR_NO_ERROR;  
  22. }  

mRndisEnabled表示驱动中USB Tether设备是否成功加载。该变量在以下函数中更新:

    

  1. private class StateReceiver extends BroadcastReceiver {  
  2.         public void onReceive(Context content, Intent intent) {  
  3.             String action = intent.getAction();  
  4.             if (action.equals(UsbManager.ACTION_USB_STATE)) {  
  5.                 synchronized (Tethering.this.mPublicSync) {  
  6.                     boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);  
  7.                     boolean usbMass = intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false);  
  8.                     mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);  
  9.   
  10.                     // start tethering if we have a request pending
      
  11.                     if (usbConnected && mRndisEnabled && mUsbTetherRequested) {  
  12.                         tetherUsb(true);  
  13.                     } else if (!usbConnected ) {  
  14.                         Log.d(TAG, "usb disconnected ,try Tethering down");  
  15.                         tetherUsb(false);  
  16.                     }  
  17.                     mUsbTetherRequested = false;  
  18.                 }  
  19.             } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {  
  20.                 if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");  
  21.                 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);  
  22.             }  
  23.         }  
  24.     }  

据实际分析,在USB DeviceManager发送 ACTION_USB_STATE广播时,将Extra域都置为了true。所以这里mRndisEnabled
= true

代码参考;

[java]

抱歉!评论已关闭.