android 上层wifi模块调用分析

本公司 wifi 模块文档

1. 文件路径

这些路径下的文件是不分平台及Android大版本的

packages/../framework/src/com/../framework/wifi/LocalWifiSetting.java
packages/../framework/src/com/../framework/wifi/WifiAccessPoint.java
packages/../framework/src/com/../framework/wifi/WifiDevInfo.java

由于android 大版本不同,差异化的东西放到了framework/android/对应大版本/wifi 中

2. 代码详细介绍

packages/../framework/src/com/../framework/wifi/LocalWifiSetting.java上层通过LocalWifiSetting.getInstance(mContext)获取单例对象,构造函数中注册wifi相关的广播代码如下:

public static LocalWifiSetting getInstance(Context context) {
    return (LocalWifiSetting) Context.getInstance(context).getSystemService(Context.WIFI_SETTING_SERVICE);
}

public LocalWifiSetting (Context context) {
    mWifiManager =(WifiManager)context.getSystemService(Context.WIFI_SERVICE);
    mContext=context;
    mScanner = new Scanner();
    mFilter = new IntentFilter();
    mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
    mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
    mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
    mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
    mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
    mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
    mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            handleEvent(context, intent);
        }   
    };  
    mContext.registerReceiver(mReceiver, mFilter);
} 

1、WIFI_STATE_CHANGED_ACTION:WIFI模块硬件状态改变的广播,看到的直观表征有, WIFI开启, WIFI关闭; 而在实际的过程中, WIFI 从开启到关闭, 或是从关闭到开启, 需要经历三个状态, 以开启WIFI为例, 其要经过的状态分别为: 已关闭, 开启中, 已开启. 关闭WIFI则相反, 分为为: 已开启, 关闭中, 关闭. 接收到这个广播后, 你可以从INTENT中取出当前WIFI硬件的变化状态, 可以使用 INT 值来区别; 这个KEY是: EXTRA_WIFI_STATE, 可能得到的值为:0, 1, 2, 3, 4; 当然除了这种获取方式, 也可以通过WIFIMANAGER对象GETWIFISTATE() 获取这个值. 也可以从 INTENT 中取出另外一个值, 表示之前WIFI模块的状态,对应的KEY, 就是: EXTRA_PREVIOUS_WIFI_STATE;

2、WifiManager.SCAN_RESULTS_AVAILABLE_ACTION: 扫描到一个热点, 并且此热点达到可用状态 会触发此广播; 此时, 你可以通过 wifiManager.getScanResult() 来取出当前所扫描到的 ScanResult; 同时, 你可以从intent中取出一个boolean值; 如果此值为true, 代表着扫描热点已完全成功; 为false, 代表此次扫描不成功, ScanResult 距离上次扫描并未得到更新;

3、WifiManager.NETWORK_IDS_CHANGED_ACTION: 在网络配置, 保存, 添加, 连接, 断开, 忘记的操作过后, 均会对 WIFI 热点配置形成影响, 在shell下, 如果有root权限, 可以在执行上述动作前后, 分别浏览 /data/misc/wifi/wpa_supplicant.conf 应该是有本质的变化, 此时会收到此广播.

4、WifiManager.SUPPLICANT_STATE_CHANGED_ACTION: 建立连接的热点正在发生变化. 象征变化的相关类为: SupplicantState, 你可以在接收到此广播时, 观察到已经建立连接的热点的整个连接过程, 包含可能会出现连接错误的错误码.

5、WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION: 官方的注释是这么说的, 广播已配置的网络发生变化, 可由添加, 修改, 删除网络的触发. 当从 intent 中取出key值为 EXTRA_MULTIPLE_NETWORKS_CHANGED, 其值为 true 时, 那么字段 EXTRA_WIFI_CONFIGURATION 中取出来的配置已经过时, 不是最新配置了。

6、WifiManager.LINK_CONFIGURATION_CHANGED_ACTION: WIFI 连接配置发生改变的广播. 此时, 网路连接功能封装 LinkProperties 和 NetworkCapabilities 可能发生变化.

7、WifiManager.NETWORK_STATE_CHANGED_ACTION: WIFI 连接状态发生改变的广播. 可以从 intent 中取得 NetworkInfo, 此时 NetworkInfo 中提供了连接的新状态, 如果连接成功, 可以获取当前连接网络的 BSSID, 和 WifiInfo.

8、WifiManager.RSSI_CHANGED_ACTION: WIFI 热点信号强度发生变化的广播. 可以获取当前变化热点的最新的信号强度.

接收到广播之后就会handleEvent:

private void handleEvent(Context context, Intent intent) {
    String action = intent.getAction();
    if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
        updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                WifiManager.WIFI_STATE_UNKNOWN));
    }else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
            updateWifiAccessPoints();
    } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
            WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
            WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
            updateWifiAccessPoints();
    } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
         SupplicantState state = (SupplicantState) intent.getParcelableExtra(
                    WifiManager.EXTRA_NEW_STATE);
            if (!mConnected.get() && SupplicantState.isHandshakeState(state)) {
                 updateConnectionState(WifiInfo.getDetailedStateOf(state));
             } else {
                 updateConnectionState(null);
             }

             int authState = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1);
             if ( authState == WifiManager.ERROR_AUTHENTICATING ) {
                 updateWifiAccessPoints();
             }
             DetailedState detailedState = WifiInfo.getDetailedStateOf(state);
             Log.i(TAG, "action: " + action + "state:" + detailedState + "authState:" + authState);
    } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
        NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
                WifiManager.EXTRA_NETWORK_INFO);
        mConnected.set(info.isConnected());
        updateWifiAccessPoints();
        updateConnectionState(info.getDetailedState());
    } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
        updateConnectionState(null);
    }
}

我司电视设置,wifi状态开机都是打开的,如果开机为wifi网络连接的话,就会接受到收到WIFI_STATE_CHANGED_ACTION,CONFIGURED_NETWORKS_CHANGED_ACTION,NETWORK_STATE_CHANGED_ACTION,SUPPLICANT_STATE_CHANGED_ACTION,这个状态是从开机到wifi认证的过程,接着我们分别看下我们的代码流程。
WIFI_STATE_CHANGED_ACTION里面实现updateWifiState

private void updateWifiState(int state) {
    dispatchWifiStateChanged(state);
    switch (state) {
        case WifiManager.WIFI_STATE_ENABLED:
            //mScanner.resume();
            return;
        case WifiManager.WIFI_STATE_ENABLING:
            break;
        case WifiManager.WIFI_STATE_DISABLED:
            break;
    }   

    mLastWifiInfo = null;
    mLastState = null;
    mScanner.pause();

}  

这里其实并没有做什么,只是清空全局变量的一些记录。然后CONFIGURED_NETWORKS_CHANGED_ACTION:

public void updateWifiAccessPoints() {
final int wifiState = mWifiManager.getWifiState();

switch (wifiState) {
    case WifiManager.WIFI_STATE_ENABLED:
        mWifiAccessPoints = constructWifiAccessPoints();
        break;
    case WifiManager.WIFI_STATE_ENABLING:
        break;
    case WifiManager.WIFI_STATE_DISABLING:
        break;
    case WifiManager.WIFI_STATE_DISABLED:
        break;
}
dispatchWifiStateChanged(wifiState);

/* 
 * mWifiAccessPoints is null when wifi is disabled,which will throw NullPointerException
 */
List<WifiAccessPoint> tmpList;
if (mWifiAccessPoints == null) {
    tmpList = new ArrayList<WifiAccessPoint>();
} else {
    tmpList = new ArrayList<WifiAccessPoint>(mWifiAccessPoints);
}
dispatchWifiAccessPointsChanged(tmpList);
}

到这个时候,wifiManger的状态就是WIFI_STATE_ENABLED。(如果想要了解开机如何自动连接上次wifi及判断之前有没有连接过wifi。请自己阅读源码,在此不做交流)接着就是我们比较重要的constructWifiAccessPoints()这个函数:

  private List<WifiAccessPoint> constructWifiAccessPoints() {
    Log.v(TAG, "constructWifiAccessPoints");
    ArrayList<WifiAccessPoint> accessPoints = new ArrayList<WifiAccessPoint>();
    /** Lookup table to more quickly update WifiAccessPoints by only considering objects with the
     * correct SSID.  Maps SSID -> List of WifiAccessPoints with the given SSID. 
     * 获取保存过的wifi信息
     * 
     */
    Multimap<String, WifiAccessPoint> apMap = new Multimap<String, WifiAccessPoint>();

    final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
    if (configs != null) {
        Log.v(TAG, "configs size = " + configs.size());
        for (WifiConfiguration config : configs) {
            WifiAccessPoint accessPoint = new WifiAccessPoint(mContext, config);
            if (mLastWifiInfo != null && mLastState != null)
                accessPoint.update(mLastWifiInfo, mLastState);
            accessPoints.add(accessPoint);
            apMap.put(accessPoint.ssid, accessPoint);
        }
    }

    //获取扫描到但未保存过的wifi
    final List<ScanResult> results = mWifiManager.getScanResults();
    if (results != null) {
        for (ScanResult result : results) {
            // Ignore hidden and ad-hoc networks.
            if (result.SSID == null || result.SSID.length() == 0 ||
                    result.capabilities.contains("[IBSS]")) {
                continue;
            }

            boolean found = false;
            for (WifiAccessPoint accessPoint : apMap.getAll(result.SSID)) {
                if (accessPoint.update(result))
                    found = true;
            }
            if (!found) {
                WifiAccessPoint accessPoint = new WifiAccessPoint(mContext, result);
                if (mLastWifiInfo != null && mLastState != null)
                    accessPoint.update(mLastWifiInfo, mLastState);
                accessPoints.add(accessPoint);
                apMap.put(accessPoint.ssid, accessPoint);
            }
        }
    }

    // Pre-sort accessPoints to speed preference insertion
    Collections.sort(accessPoints);
    return accessPoints;
}

这个函数的作用主要是用来获取WIfiAccessPoint,这个类主要用来存储wifi的信息。constructWifiAccessPoints这个函数首先通过mWifiManager.getConfiguredNetworks之前有链接过的wifi信息,保存到ApMap,然后再保存扫描到的wifi。接着就是NETWORK_STATE_CHANGED_ACTION。

 private void updateConnectionState(DetailedState state) {
    /* sticky broadcasts can call this when wifi is disabled */
    if (!mWifiManager.isWifiEnabled()) {
        mScanner.pause();
        return;
    }

    if (state == DetailedState.OBTAINING_IPADDR) {
        mScanner.pause();
    } else {
        //mScanner.resume();
    }

    mLastWifiInfo = mWifiManager.getConnectionInfo();
    Log.d(TAG, "updateConnectionState " + state);
    if (state != null) {
        mLastState = state;
    }

    if (mWifiAccessPoints != null) {
        for (WifiAccessPoint accessPoint : mWifiAccessPoints) {
            accessPoint.update(mLastWifiInfo, mLastState);
        }
    }
}

这里主要更新wifi的连接状态,IDLE:空闲 SCANNING:正在扫描 CONNECTING:连接中 AUTHENTICATING:正在进行身份验证...
OBTAINING_IPADDR:正在获取Ip地址 CONNECTED:已连接 SUSPENDED:已暂停 DISCONNECTING:正在断开连接...
DISCONNECTED:已断开 FAILED:失败 BLOCKED:已阻止 VERIFYING_POOR_LINK:暂时关闭(网络状况不佳)
CAPTIVE_PORTAL_CHECK:判断是否需要浏览器二次登录,主要有以上几种状态。当我们收到SUPPLICANT_STATE_CHANGED_ACTION的广播时,在handleEvent中的处理如下:

         SupplicantState state = (SupplicantState) intent.getParcelableExtra(
                    WifiManager.EXTRA_NEW_STATE);
            if (!mConnected.get() && SupplicantState.isHandshakeState(state)) {
                 updateConnectionState(WifiInfo.getDetailedStateOf(state));
             } else {
                 // During a connect, we may have the supplicant
                 // state change affect the detailed network state.
                 // Make sure a lost connection is updated as well.
                 updateConnectionState(null);
             }

             int authState = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1);
             if ( authState == WifiManager.ERROR_AUTHENTICATING ) {
                 updateWifiAccessPoints();
             }

             DetailedState detailedState = WifiInfo.getDetailedStateOf(state);
             Log.i(TAG, "action: " + action + "state:" + detailedState + "authState:" + authState);

这里主要处理wifi认证失败后的处理了。这部分主要是updateWifiAccessPoints(),下面看下packages/../framework/src/com/../framework/wifi/WifiAccessPoint.java,这里主要用于记录每个wifi的详细信息,在每次构建的时候状态更新的时候都会去重新构造每个WifiAccessPoint,然后fresh。
WifiAccessPoint(Context context, WifiConfiguration config) {
loadConfig(config);
refresh();
}

WifiAccessPoint(Context context, ScanResult result) {                                     
    loadResult(result);                                                                   
    refresh();                                                                            
} 

在refresh中主要是更新错误原因:

private void refresh() {
    if (getState() != null) { // This is the active connection
        mDisableReason = -1;
    } else if (getRssiLevel() == Integer.MAX_VALUE) { // Wifi out of range
        mDisableReason = -1;
    } else if (mConfig != null && mConfig.status == WifiConfiguration.Status.DISABLED) {
        switch (mConfig.disableReason) {
            case WifiConfiguration.DISABLED_AUTH_FAILURE:
                mDisableReason = WifiConfiguration.DISABLED_AUTH_FAILURE;
                break;
            case WifiConfiguration.DISABLED_DHCP_FAILURE:
            case WifiConfiguration.DISABLED_DNS_FAILURE:
            case WifiConfiguration.DISABLED_UNKNOWN_REASON:
                mDisableReason = mConfig.disableReason;
                break;
        }
    } else { // In range, not disabled.
        mDisableReason = -1;

    }
}

认证连接的就直接更新wifi状态保存就行。那是如何通知上层wifi状态发生改变的呢?这个主要是在packages/../framework/src/com/../framework/wifi/LocalWifiSetting.java中,这里写了个接口,上层通过实现这个接口处理事件。我们在需要的地方触发回调。

public interface WifiStateChangeListerner {
    void onWifiAccessPointsChanage(List<WifiAccessPoint> accessPoints);

    void onWifiStateChanage(int state);
}

private final Collection<WifiStateChangeListerner> mCallbacks = new ArrayList<WifiStateChangeListerner>();

//上层调用这里注册回调
public void registerCallback(WifiStateChangeListerner callback) {
    synchronized (mCallbacks) {
        mCallbacks.add(callback);
    }
}

public void unregisterCallback(WifiStateChangeListerner callback) {
    synchronized (mCallbacks) {
        mCallbacks.remove(callback);
    }
}

//当wifi的状态发生改变的时候适配层触发此函数,回调上层实现
private void dispatchWifiStateChanged(int state) {
    synchronized (mCallbacks) {
        for (WifiStateChangeListerner callback : mCallbacks) {
            callback.onWifiStateChanage(state);
        }
    }
}

//当Wifi信息出现变化的时候适配层触发此函数,回调上层实现
private void dispatchWifiAccessPointsChanged(List<WifiAccessPoint> accessPoints) {
    synchronized (mCallbacks) {
        for (WifiStateChangeListerner callback : mCallbacks) {
            callback.onWifiAccessPointsChanage(accessPoints);
        }
    }
}

到这里适配层wifi比较中要的逻辑基本结束,其他函数看函数名称基本能够了解大致含义:基本上是在packages/../framework/src/com/../framework/wifi/LocalWifiSetting.java中的查找、连接、获取wifi信息、删除保存wifi等等

###ethernet 模块文档
接着介绍一下以太网的流程。文件主要路径:

packages/../framework/src/com/../framework/ethernet/LocalEthCallback.java
packages/../framework/src/com/../framework/ethernet/LocalEthernetDevInfo.java
packages/../framework/src/com/../framework/ethernet/LocalEthManager.java

类似于wifi,主要的类是LocalEthManager,但这个里面基本上是抽象的方法与类,具体的实现如下:这里因为当时4.4的时候以太网放到mstar下,到5.0的时候发现会随大版本的变化而发生改变,这部分的实现是放到了packages/../framework/android/对应的大版本/ehernet/下,可以按照对应的大版本进行分析,我们先以android4.4的来分析。
所以可以有两种实现方式:
./framework/hardware/mstar/tv1/src/ethernet/MstarLocalEthManager.java
./framework/hardware/mtk/tv1/src/ethernet/MtkLocalEthManager.java
./framework/hardware/softwinner/tv1/src/ethernet/SoftwinnerLocalEthManager.java
./framework/hardware/hisilicon/tv1/src/ethernet/HisiLocalEthManager.java
./framework/hardware/amlogic/tv1/src/ethernet/AmlogicLocalEthManager.java
./framework/android/lollipop/src/ethernet/LocalEthManager.java
这些是LocalEthManager.java的具体实现,编译的时候会android大版本优先,如果android大版本下没有存在,就根据配置,走相应的板卡或者芯片厂商下边。

类似与wifi的流程有点类似,上层通过LocalWifiSetting.getInstance(mContext)获取单例对象:
public LocalEthManager(Context context) {
if (DEBUG)
Log.d(TAG, "LocalEthManager construct");
mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);
mConnectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
IntentFilter intentfilter = new IntentFilter();
intentfilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mBroadcastReceiver, intentfilter);
}

其实ethernet的实现方式更简单,主要是监听CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE",接收到广播,触发连接状态回调,给上层使用
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
int type = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE);
if (type == ConnectivityManager.TYPE_ETHERNET) {
NetworkInfo networkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
if (DEBUG)
Log.d(TAG, "Eth state change action");
if (networkInfo != null && networkInfo.isConnected()) {
Log.d(TAG,"LocalEthManager.EVENT_ETH_CONNECTED");
dispatchEthEvent(LocalEthManager.EVENT_ETH_CONNECTED);
} else {
Log.d(TAG,"LocalEthManager.EVENT_ETH_DISCONNECTED");
dispatchEthEvent(LocalEthManager.EVENT_ETH_DISCONNECTED);
}
}
}
};

其他的函数都是给上层获取ethernet相关信息的。
isEthernetAvailable()---------------是否支持以太网
getSavedEthConfig()---------------获取保存的以太网,分静态IP及非静态,构建相应的LocalEthernetDevInfo
updateEthDevInfo()----------------更新以太网相关信息(上层应该未使用)
getDhcpInfo()

android 上层wifi模块调用分析

上一篇:在Android Studio中使用JUNIT测试


下一篇:移动端1px 边框