Android(N) Wifi模块分析

这里先说一下读wifi模块的一个步骤,我是先从理解Settings模块的设计开始的,刚开始以为settings模块只是一个listview进行显示,但android的设计让我出乎意料,特别是android7.0在Settings模块中还加入了抽屉,让实现流程更加复杂。之后大致看了下WifiSettings这个fragment,这里主要是界面的设计,当阅读到WifiService中时,发现到处都是StateMachine这个东西,没办法,只能先去学习什么是StateMachine,这里还要从java的State设计模式开始学起,然后再学习StateMachine对State模式的实现方式。这里看的差不多了,才开始读里面的逻辑。

除了看源码外,我结合博文和书籍一起理解,这里推荐几篇博文和一本书:

http://blog.csdn.net/u013467735/article/details/42487537

http://blog.csdn.net/u013467735/article/details/42493665

http://blog.csdn.net/u013467735/article/details/42525387

http://blog.csdn.net/eastmoon502136/article/details/8721510

书籍是邓凡平的深入理解Android(Wi-Fi、NFC和GPS卷)

这篇博文也引用了以上资料中的一些表述,引用之处没有一一指出,请原作者谅解。

          


Android在wifi模块的设计上,frameworks层以上涉及的类主要有WifiSettings、WifiMaganer、WifiService、WifiServiceImpl、WifiStateMachine、WifiController等。

他们的主要关系如下图:

  

上图中几个重要的类的作用及其在android中的代码位置如下:

WifiManager:WifiService的客户端,是App层与Framework层之间的桥梁。

(代码位置:frameworks/base/wifi/java/android/net/wifi/WifiManager.java)

WifiService:是Framework层负责wifi功能的核心服务,是系统进程。

(代码位置:frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java)

WifiStateMachine:wifi状态机,WifiService的核心。

(代码位置:frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java)

WifiMonitor:一个线程,用来接收来自WPAS的消息。

(代码位置:frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java)

WifiNative:用于和WPAS通信,内部定义许多native方法,对应的JNI模块是android_net_wifi_Wifi。

(代码位置:frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

分析方式:流程图+具体代码实现。

(一)Wifi开启与关闭流程分析




根据以上流程图,以开启wifi为例,分析代码中的实现:

用户在打开wifi开关后,WifiEnabler里的onSwitchChanged()将被调用,输入参数为true,并调用mWifiManager.setWifiEnabled(true)

public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

WifiService没有自己定义这些方法,而是通过WifiServiceImpl对象定义的。


public synchronized boolean setWifiEnabled(boolean enable) {
        //代码省略
        mWifiController.obtainMessage(CMD_WIFI_TOGGLED, mWifiIpoOff ? 1 : 0,
                Binder.getCallingUid()).sendToTarget();
        return true;
    }

这里通过WifiController发送消息CMD_WIFI_TOGGLED,该消息在WifiControllerApStaDisabledState中处理并跳转到StaEnabledState,查看其enter方法:

@Override
        public void enter() {
            if (DBG) Slog.d(TAG, getName() + "\n");
            mWifiStateMachine.setSupplicantRunning(true);
        }

此处调用WifiStateMachinesetSupplicantRunning(true)


public void setSupplicantRunning(boolean enable) {
        if (enable) {
            sendMessage(CMD_START_SUPPLICANT);
        } else {
            sendMessage(CMD_STOP_SUPPLICANT);
        }
}

setSupplicantRunning()中向WifiStateMachine发送CMD_START_SUPPLICANT消息,它由InitialState处理:

@Override
    public boolean processMessage(Message message) {
        logStateAndMessage(message, this);
        switch (message.what) {
            case CMD_START_SUPPLICANT:
                if (mWifiNative.loadDriver()) {
                   //代码省略
                }
                if (mWifiNative.startSupplicant(mP2pSupported)) {
                   //代码省略
                   transitionTo(mSupplicantStartingState);
                 } 
            return HANDLED;
        }
}

这里主要调用WifiNativeloadDriverstartSupplicant两个函数去加载wifidriver和启动wpa_supplicant。至此,wifi开启流程基本结束。Wifi关闭流程类似。



Wifi扫描流程



当wifi开启之后,会发送WIFI_STATE_CHANGED_ACTION广播,WifiTracker注册监听该广播,收到该广播后,调用mScanner.resume()启动扫描,该方法中调用mWifiManage.startScan()发起扫描。再通过WifiService的startScan( )触发WifiMachine的startScan()方法

public void startScan(int callingUid, int scanCounter,
                          ScanSettings settings, WorkSource workSource) {
        Bundle bundle = new Bundle();
        bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
        bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
        bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
        sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
    }
@Override
        public boolean processMessage(Message message) {
            logStateAndMessage(message, this);
            switch(message.what) {
                case CMD_START_SCAN:
                    handleScanRequest(message);
                    break;
                //代码省略
            return HANDLED;
}
}
private void handleScanRequest(Message message) {
      	//代码省略
        // call wifi native to start the scan
        if (startScanNative(freqs, hiddenNetworkIds, workSource)) {
            // a full scan covers everything, clearing scan request buffer
            if (freqs == null)
                mBufferedScanMsg.clear();
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
            if (workSource != null) {
                // External worksource was passed along the scan request,
                // hence always send a broadcast
                mSendScanResultsBroadcast = true;
            }
            return;
        }
//代码省略
    }

    handleScanRequest(message)调用startScanNative向wpa_supplicant发送SCAN的命令,当wpa_suppliant执行完SCAN并成功找到一些AP后,就会给WifiMonitor发送CTRL-EVENT-SCAN-RESULTS的event,WifiMonitor会parse出这个event,并向WifiStateMachine发送SCAN_RESULTS_EVENT消息,WifiStateMachine的SupplicantStartedState会处理这个消息,如下:



@Override
        public boolean processMessage(Message message) {
            logStateAndMessage(message, this);
            switch(message.what) {
                case WifiMonitor.SCAN_RESULTS_EVENT:
                case WifiMonitor.SCAN_FAILED_EVENT:
                   //代码省略
                   setScanResults();
                   if (mIsFullScanOngoing || mSendScanResultsBroadcast || mWifiOnScanCount < 2) {
                       loge("mWifiOnScanCount: " + mWifiOnScanCount);
                       /* Just updated results from full scan, let apps know about this */
                       boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
                       sendScanResultsAvailableBroadcast(scanSucceeded);
                    }
//代码省略
                    break;                
//代码省略
            return HANDLED;
}
      这里主要做了两件事,一是去获取scanResults,保存到mScanResults和mScanResultCache中,另外会发送一个广播信息出去,WifiSettings监听到这个广播的后,就去获取scanResults并显示。
扫描流程至此结束。




.Wifi连接流程



连接的过程比较复杂,涉及的状态和消息比较多。
当用户点击已保存的AP或输入密码按确定后,会调用WifiManager的connect函数:


public void connect(WifiConfiguration config, ActionListener listener) {
        Log.d(TAG, "connect, pid:" + Process.myPid() + ", tid:" + Process.myTid() + ", uid:" + 
Process.myUid());
        if (config == null) 
throw new IllegalArgumentException("config cannot be null");
        // Use INVALID_NETWORK_ID for arg1 when passing a config object
        // arg1 is used to pass network id when the network already exists
    	getChannel().sendMessage(
CONNECT_NETWORK,WifiConfiguration.INVALID_NETWORK_ID,
                putListener(listener), config);
}
这里通过getChannel()发送消息CONNECT_NETWORK到WifiService,在ClientHandler中处理:


@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        //代码省略
        case WifiManager.CONNECT_NETWORK:
        case WifiManager.SAVE_NETWORK: {
//代码省略
else if (config == null && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
                 if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
                        mWifiStateMachine.sendMessage(Message.obtain(msg));
                  } 
//代码省略
                  break;
             }
         }
    }
}

        这里将CONNECT_NETWORK消息转发给WifiStateMachine,由ConnectModeState处理该消息,处理函数的code非常多,有三个重要函数:
mWifiConfigStore.saveNetwork()
mWifiConfigStore.selectNetwork()
mWifiNative.reconnect()
        通过mWifiNative.reconnect()发起重新连接的请求给wpa_supplicant,当wpa_supplicant的状态改变时会发送WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT让WifiStateMachine 转换到DisconnectedState。
       Wifi和AP之间已经连接成功后,就会收到wpa_supplicant发送上来的CTRL-EVENT-CONNECTED这个event,WifiMonitor收到这个消息后,会向WifiStateMachine发送NETWORK_CONNECTION_EVENT表示已经和AP之间成功的连接,WifiStateMachine的ConnectModeState会来处理这个消息




@Override
    public boolean processMessage(Message message) {
        logStateAndMessage(message, this);
            switch(message.what) {
//代码省略
                case WifiMonitor.NETWORK_CONNECTION_EVENT:
                    //代码省略
                    mWifiInfo.setBSSID(mLastBssid);
                    mWifiInfo.setNetworkId(mLastNetworkId);
                    mWifiQualifiedNetworkSelector
                       .enableBssidForQualityNetworkSelection(mLastBssid, true);
                    sendNetworkStateChangeBroadcast(mLastBssid);
                    transitionTo(mObtainingIpState);
                    break;
                //代码省略
            return HANDLED;
}
}
}
处理结束会跳转到ObtainingIpState,其enter函数如下:

@Override
public void enter() {
       //代码省略
       if (!mWifiConfigManager.isUsingStaticIp(mLastNetworkId)) {
            //静态ip模式
//代码省略
        } else {
            StaticIpConfiguration config = mWifiConfigManager.getStaticIpConfiguration(mLastNetworkId);
            if (config.ipAddress == null) {
                logd("Static IP lacks address");
                sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
            } else {
                final IpManager.ProvisioningConfiguration prov;
                ///M: IpReachabilityMonitor Enhancement @{
                if (enableIpReachabilityMonitor()) {
                    prov = mIpManager.buildProvisioningConfiguration()
                            .withStaticConfiguration(config)
                            .withApfCapabilities(mWifiNative.getApfCapabilities())
.build();
                 } else {
              		prov = mIpManager.buildProvisioningConfiguration()
                            .withStaticConfiguration(config)
                            .withApfCapabilities(mWifiNative.getApfCapabilities())
                            .withoutIpReachabilityMonitor()
                            .build();
                 }
           	     try {
                    Thread.sleep(500);
                 } catch (Exception e) {
                 }
                 mIpManager.startProvisioning(prov);
                 }
            }
        }
}
        这里涉及到另外一个状态机IpManager,它还会和另外一个状态机DhcpClient进行交互,通过DHCP服务去获取ip地址。在进行DHCP协议之前,DhcpClient会发送一个消息CMD_PRE_DHCP_ACTION,由WifiStateMachine的L2ConnectedState处理该消息,  调用handlePreDhcpSetup()进行一些初始化设置,处理结束会发送CMD_PRE_DHCP_ACTION_COMOLETE消息,处理该消息时候会调用mIpManager.completedPreDhcpAction()告诉IpManager可以开始DHCP协议了。DHCP发现结束后DhcpClien又会发送消息CMD_POST_DHCP_ACTION,L2ConnectedState调用handlePostDhcpSetup()恢复之前的设置


@Override
public boolean processMessage(Message message) {
    logStateAndMessage(message, this);
        switch (message.what) {
            case DhcpClient.CMD_PRE_DHCP_ACTION:
                handlePreDhcpSetup();
                break;
            case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
                mIpManager.completedPreDhcpAction();
                break;
            case DhcpClient.CMD_POST_DHCP_ACTION:
                handlePostDhcpSetup();
                break;
//代码省略
            return HANDLED;
}
}
        最后通过监听IpManager.CallBack的onProvisioningSuccess,转到ConnectedState,漫长的连接流程至此结束。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值