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

TetherSettings.java

    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中的函数:

    public int setUsbTethering(boolean enable) {        enforceTetherAccessPermission();        if (isTetheringSupported()) {            return mTethering.setUsbTethering(enable);        } else {            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;        }    }


其中mTethering是一个Tethering对象。

--Tethering.java

    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设备是否成功加载。该变量在以下函数中更新:

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

代码参考;

        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);

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

继续执行到 tether函数:

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

                    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通过多态进行管理

mStartingState = new StartingState();            addState(mStartingState);

transitionTo会自动条用 StartingStateenter函数:


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,改为TetheredMTetheredState是一个 TetheredState 类型的状态机变量。TetheredStateenter函数定义如下:

           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 usb0netd程序完成与Native的通信。

netdCommandListener中会处理这个消息。

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

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 。我们一起去看看这个函数:

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



更多相关文章

  1. IOS/Android 读取蓝牙设备电量信息
  2. Android 设备的位数
  3. 获取android设备的IP地址
  4. Android中调用系统函数查找联系人
  5. Android getActionBar() 函数总是返回 null 的解决
  6. 【Android】简单的接口回调
  7. android如何判断两台设备在同一个局域网内

随机推荐

  1. [置顶] Android获取存储卡路径的
  2. 关于Android Studio 3.1.3
  3. Android公钥私钥及代码详细解读
  4. 关于Android的阅读界面设计问题
  5. android 中的 odex 文件
  6. Android实现非本地图片的点击效果
  7. [置顶] Android开发的一些小技巧
  8. 【Based Android】android通过criteria选
  9. Android Gallery滑动太快的问题
  10. android-弹出窗口的使用(1)