5.2.3 WifiStateMachine介绍

首先来看WifiStateMachine的构造函数,其内容较多,我们分两段来介绍。

1.WifiStateMachine构造函数分析之一

[—>WifiStateMachine.java::WifiStateMachine构造函数代码段一]

  1. public WifiStateMachine(Context context, String wlanInterface) {
  2. super(TAG);
  3. mContext = context;
  4. mInterfaceName = wlanInterface;
  5.  
  6. // 创建一个NetworkInfo,它实际上代表一个网络设备的状态信息(status of a network interface)
  7. mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI,
  8. 0, NETWORKTYPE, "");
  9.  
  10. // 和BatteryStatsService交互,BSS注册的服务名叫“batteryinfo”
  11. mBatteryStats = IBatteryStats.Stub.asInterface
  12. (ServiceManager.getService("batteryinfo"));
  13.  
  14. // 创建和NewtorkManagmentService交互的Binder客户端
  15. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
  16. mNwService = INetworkManagementService.Stub.asInterface(b);
  17. /*
  18. 判断系统是否支持Wi-Fi Display功能。本书不讨论WFD,感兴趣的读者可阅读笔者的一篇博文
  19. http:// blog.csdn.net/innost/article/details/8474683
  20. " Android Wi-Fi Display(Miracast)介绍"。
  21. */
  22. mP2pSupported = mContext.getPackageManager().hasSystemFeature(
  23. PackageManager.FEATURE_WIFI_DIRECT);
  24.  
  25. /*
  26. WifiNative:用于和wpa_supplicant交互。它和4.2.3节中控制API知识相关。
  27. WifiMonitor:内部将创建一个线程,并借助WifiNative去接收并处理来自WPAS的信息。
  28. WifiConfigStore:它对应一个配置文件,位置为/data/misc/wifi/ifconfig.txt。
  29. 该文件用于存储每个无线网络的配置项。例如代理地址、静态IP地址等。读者可在Settings
  30. 中选择某个无线网络,长按以弹出修改对话框,然后选择“高级选项”即可设置这些信息。
  31. */
  32. mWifiNative = new WifiNative(mInterfaceName);
  33. mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
  34. mWifiMonitor = new WifiMonitor(this, mWifiNative);
  35.  
  36. // 用于保存DHCP的一些信息
  37. mDhcpInfoInternal = new DhcpInfoInternal();
  38. // WifiInfo用于存储手机当前连接上的无线网络的一些信息,包括IP地址、ssid等内容
  39. mWifiInfo = new WifiInfo();
  40.  
  41. // SupplicantStateTracker用于跟踪WPAS的状态,它也是一个StateMachine
  42. mSupplicantStateTracker = new SupplicantStateTracker
  43. (context, this, mWifiConfigStore,getHandler());
  44. // LinkProperties用于描述网络链接(network link)的一些属性,如IP地址、DNS地址和路由设置
  45. mLinkProperties = new LinkProperties();
  46.  
  47. // WifiApConfigStore和Soft AP模式有关,用于存储Soft AP模式中使用到的一些配置信息
  48. // WifiApConfigStore是一个StateMachine。配置信息存储于/data// misc/wifi/softap.conf中
  49. WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
  50. context, getHandler());
  51. wifiApConfigStore.loadApConfiguration();
  52.  
  53. // mWifiApConfigChannel的类型是AsyncChannel,它将和wifiApConfigStore中的某个Handler通信
  54. mWifiApConfigChannel.connectSync(mContext, getHandler(),
  55. wifiApConfigStore.getMessenger());
  56.  
  57. mNetworkInfo.setIsAvailable(false);
  58. mLinkProperties.clear();
  59. ......
  60. // 设置扫描间隔时间:当驱动不支持Background扫描时,Framework将定时开展扫描工作
  61. // 默认值为300秒
  62. mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
  63. R.integer.config_wifi_framework_scan_interval);
  64. /*
  65. driver stop延迟,默认是120秒。该变量和emergency calls(紧急呼叫)有关。
  66. 处于这种模式下,即使用户选择关闭Wi-Fi,WifiStateMachine也不会立即执行它,而是要
  67. 等待一段时间才真正去关闭Wi-Fi。
  68. */
  69. mDriverStopDelayMs = mContext.getResources().getInteger(
  70. R.integer.config_wifi_driver_stop_delay);
  71.  
  72. // 是否支持Background扫描
  73. mBackgroundScanSupported = mContext.getResources().getBoolean(
  74. R.bool.config_wifi_background_scan_support);
  75.  
  76. // 和P2P有关。以后再介绍
  77. mPrimaryDeviceType = mContext.getResources().getString(
  78. R.string.config_wifi_p2p_device_type);
  79.  
  80. // WIFI_SUSPEND_OPTIMIZATIONS_ENABLED变量用于控制手机睡眠期间是否保持Wi-Fi开启
  81. mUserWantsSuspendOpt.set(Settings.Global
  82. .getInt(mContext.getContentResolver(),
  83. Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
  84.  
  85. ......// 处理ACTION_START_SCAN广播事件
  86. ......// 处理ACTION_SCREEN_ON/OFF广播事件
  87. ......// 处理ACTION_DELAYED_DRIVER_STOP广播事件
  88. ......// 监视ContentProvider中WIFI_SUSPEND_OPTIMIZATIONS_ENABLED设置的变化
  89. // mScanResultCache用于保存扫描结果
  90. mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
  91. ......// 申请WakeLock

重点介绍其中的三个对象,分别是WifiNative、WifiMonitor以及SupplicantStateTracker。

(1)WifiNative

根据上文描述,WifiNative用于和WPAS通信,其内部定义了较多的native方法(对应的JNI模块是android_net_wifi_Wifi)。本节介绍其中最重要的两个方法。

第一个方法是startSupplicant,用于启动WPAS。startSupplicant是一个native函数,其JNI函数为android_net_wifi_startSupplicant,代码如下所示。

[—>android_net_wifi_Wifi.c::android_net_wifi_startSupplicant]

  1. static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject,
  2. jboolean p2pSupported)
  3. {
  4. return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0);
  5. }

wifi_start_supplicant代码如下所示。

[—>wifi.c::wifi_start_supplicant]

  1. int wifi_start_supplicant(int p2p_supported)
  2. {
  3. char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
  4. int count = 200;
  5. // 该宏在build/core/combo/include/arch/linux-arm/AndroidConfig.h中被定义为1
  6. #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
  7. const prop_info *pi;
  8. unsigned serial = 0, i;
  9. #endif
  10. // 和P2P有关
  11. if (p2p_supported) {// P2P_SUPPLICANT_NAME值为“p2p_supplicant”
  12. strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
  13. // P2P _PROP_NAME值为“init.svc.p2p_supplicant”
  14. strcpy(supplicant_prop_name, P2P_PROP_NAME);
  15. /*
  16. P2P_CONFIG_FILE的值为“/data/misc/wifi/p2p_supplicant.conf”。下面这个函数将把
  17. /system/etc/wifi/wpa_supplicant.conf的内容复制到P2P_CONFIG_FILE中。
  18. */
  19. if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) return -1;
  20. } else {
  21. strcpy(supplicant_name, SUPPLICANT_NAME);// SUPPLICANT_NAME值为“wpa_supplicant”
  22. // SUPP_PROP_NAME值为“init.svc.wpa_supplicant”
  23. strcpy(supplicant_prop_name, SUPP_PROP_NAME);
  24. }
  25. // 如果WPAS已经启动,则直接返回
  26. if (property_get(supplicant_name, supp_status, NULL)
  27. && strcmp(supp_status, "running") == 0) return 0;
  28. // SUPP_CONFIG_FILE的值为“/data/misc/wifi/wpa_supplicant.conf”
  29. if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) return -1;
  30. // entropy文件,用于增加随机数生成的随机性
  31. if (ensure_entropy_file_exists() < 0)
  32. ALOGE("Wi-Fi entropy file was not created");
  33. // 关闭之前创建的wpa_ctrl对象
  34. wifi_wpa_ctrl_cleanup();
  35.  
  36. for (i=0; i&lt;MAX_CONNS; i++)
  37. exit_sockets[i][0] = exit_sockets[i][1] = -1;
  38.  
  39. #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
  40. // supplicant_prop_name值为“init.svc.wpa_supplicant”
  41. pi = __system_property_find(supplicant_prop_name);
  42. ......
  43. #endif
  44.  
  45. property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
  46. /*
  47. 通过设置“ctrl.start”属性来启动wpa_supplicant服务。该属性将触发init fork一个子
  48. 进程用于运行wpa_supplicant。同时,init还会添加一个新的属性
  49. “init.svc.wpa_supplicant”用于跟踪wpa_supplicant的状态。
  50. */
  51. property_set("ctl.start", supplicant_name);
  52. sched_yield();
  53. // 下面这个循环用于查询“init.svc.wpa_supplicant”的属性值
  54. // 如果其值变成“running”,表示wpa_supplicant成功运行
  55. while (count-- > 0) {// count初值为200。while循环最多等待20秒
  56. #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
  57. if (pi == NULL) {
  58. pi = __system_property_find(supplicant_prop_name);
  59. }
  60. if (pi != NULL) {
  61. __system_property_read(pi, NULL, supp_status);
  62. if (strcmp(supp_status, "running") == 0) return 0;
  63. else if (pi->serial != serial &&// 如果WPAS已经停止,则直接返回-1
  64. strcmp(supp_status, "stopped") == 0) return -1;
  65. }
  66. #else
  67. ......
  68. #endif
  69. usleep(100000);// 等待wpa_supplicant的状态
  70. }
  71. return -1;
  72. }

图5-3显示了wpa_supplicant运行过程中及退出后"init.svc.wpa_supplicant"属性值的变化。

5.2.3 WifiStateMachine介绍 - 图1

图5-3 init.svc.wpa_supplicant属性

提示 对Android属性机制和init工作原理感兴趣的读者不妨阅读《深入理解Android:卷Ⅰ》第3章。

第二个要介绍的函数是connectToSupplicant,它将通过WPAS控制API和WPAS建立交互关系。

[—>WifiNative.java::connectToSupplicant]

  1. public boolean connectToSupplicant() {
  2. // mInterface的值为”wlan0”,由属性“wifi.interface”决定
  3. return connectToSupplicant(mInterface);// 调用native函数
  4. }
  5. private native boolean connectToSupplicant(String iface);

与connectToSupplicant对应的JNI函数是android_net_wifi_connectToSupplicant,其代码如下所示。

[—>android_net_wifi_Wifi.cpp::android_net_wifi_connectToSupplicant]

  1. static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface)
  2. {
  3. ScopedUtfChars ifname(env, jIface);
  4. return (jboolean)(::wifi_connect_to_supplicant(ifname.c_str()) == 0);
  5. }

wifi_connect_to_supplicant的代码如下所示。

[—>wifi.c::wifi_connect_to_supplicant]

  1. int wifi_connect_to_supplicant(const char *ifname)
  2. {
  3. char path[256];
  4. /*
  5. Android 4.2支持STA和P2P设备并发(concurrent)工作,STA用PRIMARY(值为0)来标示,
  6. 而P2P设备用SECONDARY(值为1)代表。is_primary_interface用于判断ifname是否代表STA。
  7. */
  8. if (is_primary_interface(ifname)) {
  9. // IFACE_DIR的值为“/data/system/wpa_supplicant”。笔者测试的几个手机中都没有该文件夹
  10. if (access(IFACE_DIR, F_OK) == 0) {
  11. snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
  12. } else {
  13. strlcpy(path, primary_iface, sizeof(path));
  14. }
  15. return wifi_connect_on_socket_path(PRIMARY, path);// PRIMARY值为0
  16. } else {
  17. sprintf(path, "%s/%s", CONTROL_IFACE_PATH, ifname);
  18. return wifi_connect_on_socket_path(SECONDARY, path);// SECONDARY值为1
  19. }
  20. }

来看wifi_connect_on_socket_path,其代码如下所示。

[—>wifi.c::wifi_connect_on_socket_path]

  1. int wifi_connect_on_socket_path(int index, const char *path)
  2. {
  3. char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
  4.  
  5. // 判断wpa_supplicant进程是否已经启动
  6. if (!property_get(supplicant_prop_name, supp_status, NULL)
  7. || strcmp(supp_status, "running") != 0) return -1;
  8. // 创建第一个wpa_ctrl对象,用于发送命令
  9. ctrl_conn[index] = wpa_ctrl_open(path);
  10. ......
  11. // 创建第二个wpa_ctrl对象,用于接收unsolicited event
  12. monitor_conn[index] = wpa_ctrl_open(path);
  13. ......
  14. // 必须调用wpa_ctrl_attach函数以启用unsolicited event接收功能
  15. if (wpa_ctrl_attach(monitor_conn[index]) != 0) {......}
  16. // 创建一个socketpair,它用于触发WifiNative关闭和WPAS的连接
  17. if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets[index]) == -1) {......}
  18. return 0;
  19. }

由于Android 4.2支持两个并发设备,所以每个并发设备各有两个wpa_ctrl对象。

·ctrl_conn[PRIMARY]、monitor_conn[PRIMARY]:用于STA设备。ctrl_conn用于向WPAS发送命令并接收对应命令的回复,而monitor_conn用于接收来自WPAS的unsolicited event。

·ctrl_conn[SECONDARY]、monitor_conn[SECONDARY]:这两个wpa_ctrl对象用于P2P设备。

另外,exit_sockets保存了socketpair创建的socket句柄,这些句柄用于WifiService通知WifiNative去关闭它和WPAS的连接。

提示 wifi.c中,wifi_send_command会使用ctrl_conn中的wpa_ctrl对象向WPAS发送命令并接收回复,而wifi_recv函数将使用monitor_conn中的wpa_ctrl对象接收来自WPAS的消息。这两个函数比较简单,请读者可自行阅读它。

下面来看WifiMonitor,它将使用monitor_conn中的wpa_ctrl对象。

(2)WifiMonitor

WifiMonitor最重要的内容是其内部的WifiMonitor线程,该线程专门用于接收来自WPAS的消息。代码如下所示。

[—>WifiMonitor.java::MonitorThread]

  1. class MonitorThread extends Thread {
  2. public MonitorThread() {
  3. super("WifiMonitor");
  4. }
  5. public void run() {
  6. if (connectToSupplicant()) {// 连接WPAS, mStateMachine指向WifiStateMachine
  7. // 连接成功后,将向WifiStateMachine发送SUP_CONNECTION_EVENT消息
  8. mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
  9. } else {
  10. mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
  11. return;
  12. }
  13. for (;;) {
  14. // waitForEvent内部会调用wifi.c中的wifi_wait_on_socket函数
  15. String eventStr = mWifiNative.waitForEvent();
  16. // 解析WPAS的消息格式。EVENT_PREFIX_STR的值为“CTRL-EVENT-”
  17. if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
  18. ......// 非“CTRL-EVENT-”消息
  19. continue;
  20. }
  21. // 处理“CTRL-EVENT-”消息
  22. String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
  23. int nameEnd = eventName.indexOf(' ');
  24. if (nameEnd != -1)
  25. eventName = eventName.substring(0, nameEnd);
  26. ......
  27. int event;
  28. if (eventName.equals(CONNECTED_STR))// 对应为“CONNECTED”消息
  29. event = CONNECTED;
  30. ......
  31. else if (eventName.equals(STATE_CHANGE_STR))// 对应为“STATE-CHANGED”
  32. event = STATE_CHANGE;
  33. else if (eventName.equals(SCAN_RESULTS_STR))// 对应为“SCAN-RESULTS”
  34. event = SCAN_RESULTS;
  35. ......
  36. else if (eventName.equals(DRIVER_STATE_STR))// 对应为“DRIVER-STATE”
  37. event = DRIVER_STATE;
  38. else if (eventName.equals(EAP_FAILURE_STR))// 对应为“EAP-FAILURE”
  39. event = EAP_FAILURE;
  40. else
  41. event = UNKNOWN;
  42. /*
  43. 提取消息中的其他信息,以CONNECTED消息为例,其消息全内容为:
  44. CTRL-EVENT-CONNECTED - Connection to xx:xx:xx:xx:xx:xx completed
  45. 其中,xx:xx:xx:xx:xx:xx代表目标AP的BSSID。
  46. */
  47. String eventData = eventStr;
  48. if (event == DRIVER_STATE || event == LINK_SPEED)
  49. eventData = eventData.split(" ")[1];
  50. else if (event == STATE_CHANGE || event == EAP_FAILURE) {
  51. ......
  52. } ......
  53. if (event == STATE_CHANGE) {// WPAS状态发生变化
  54. handleSupplicantStateChange(eventData);
  55. } else if (event == DRIVER_STATE) {
  56. handleDriverEvent(eventData);
  57. }......
  58. else {// 其他事件处理
  59. handleEvent(event, eventData);
  60. }
  61. mRecvErrors = 0;
  62. }
  63. }
  64. ......
  65. }

上述代码中:

·handleSupplicantStateChange用于处理WPAS的状态变化(见下文解释),它将先把这些变化信息交给WifiStateMachine去处理。而WifiStateMachine将根据处理情况再决定是否需要由下一节介绍的SupplicantStateTracker来处理。handleSupplicant StateChange代码比较简单,读者可自行阅读它。

·handleDriverEvent用于处理来Driver的信息

·handleEvent用于处理其他消息事件。详情见下文。

注意 WPAS的状态指的是wpa_sm状态机中的状态,包括WPA_DISCONNECTED、WPA_INTERFACE_DISABLED、WPA_INACTIVE、WPA_SCANNING、WPA_AUTHENTICATING、WPA_ASSOCIATING、WPA_ASSOCIATED、WPA_4WAY_HANDSHAKE、WPA_GROUP_HANDSHAKE、WPA_COMPLETED共10个状态。WifiService定义了SupplicantState类来描述WPAS的状态,包括DISCONNECTED、INTERFACE_DISABLED、INACTIVE、SCANNING、AUTHENTICATING、ASSOCIATING、ASSOCIATED、FOUR_WAY_HANDSHAKE、GROUP_HANDSHAKE、COMPLETED、DORMANT、UNINITIALIZED、INVALID共13个状态。其中最后三个状态是WifiService定义的,但笔者在代码中没有找到使用它们的地方。

下面简单介绍handleEvent,其代码如下所示。

[—>WifiMonitor.java::handleEvent]

  1. void handleEvent(int event, String remainder) {
  2. switch (event) {
  3. case DISCONNECTED:
  4. handleNetworkStateChange(NetworkInfo.DetailedState
  5. .DISCONNECTED, remainder);
  6. break;
  7. case CONNECTED:// 该事件表示WPAS成功加入一个无线网络
  8. handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
  9. break;
  10. case SCAN_RESULTS:// 该事件表示WPAS已经完成扫描,客户端可以来查询扫描结果
  11. mStateMachine.sendMessage(SCAN_RESULTS_EVENT);// 处理扫描结果消息
  12. break;
  13. case UNKNOWN:
  14. break;
  15. }
  16. }

先介绍SupplicantStateTracker。后文再分析CONNECTED和SCAN_RESULTS消息的处理流程。

(3)SupplicantStateTracker

SupplicantStateTracker用于跟踪和处理WPAS的状态变化。根据前面对WPAS中的状态以及WifiService中的状态介绍可知。在WifiService中,WPAS的状态由SupplicantState来表示,而和它相关的状态管理模块就是此处的SupplicantStateTracker。SupplicantStateTracker也从StateMachine派生,并且它还定义了8个状态对象。相关代码如下所示。

[—>SupplicantStateTracker.java::SupplicantStateTracker]

  1. public SupplicantStateTracker(Context c, WifiStateMachine wsm,
  2. WifiConfigStore wcs, Handler t) {
  3. super(TAG, t.getLooper());
  4. mContext = c;
  5. mWifiStateMachine = wsm;
  6. mWifiConfigStore = wcs;
  7. addState(mDefaultState);
  8. addState(mUninitializedState, mDefaultState);
  9. addState(mInactiveState, mDefaultState);
  10. addState(mDisconnectState, mDefaultState);
  11. addState(mScanState, mDefaultState);
  12. addState(mHandshakeState, mDefaultState);
  13. addState(mCompletedState, mDefaultState);
  14. addState(mDormantState, mDefaultState);
  15.  
  16. setInitialState(mUninitializedState);// 初始状态为mUninitializedState
  17. start();// 启动状态机
  18. }

·SupplicantState中的AUTHENTICATING、ASSOCIATING、ASSOCIATED、FOUR_WAY_HANDSHAKE和GROUP_HANDSHAKE均对应于此处的mHandshakeState。

·SupplicantState中的UNINITIALIZED和INVALID对应于此处的mUnitializedState。

SupplicantStateTracker比较简单,而且它也不影响本章的分析流程。读者可在阅读完本章的基础上,自行对其开展研究。

下面来看WifiStateMachine构造函数的最后一部分。

2.WifiStateMachine构造函数分析之二

[—>WifiStateMachine.java::WifiStateMachine构造函数代码段二]

  1. ......// WifiStateMachine中的状态。说实话,笔者还没见过如此复杂的状态机
  2. addState(mDefaultState);
  3. addState(mInitialState, mDefaultState);
  4. addState(mDriverUnloadingState, mDefaultState);
  5. addState(mDriverUnloadedState, mDefaultState);
  6. addState(mDriverFailedState, mDriverUnloadedState);
  7. ......// WifiStateMachine一共定义了30个状态
  8. addState(mSoftApStoppingState, mDefaultState);
  9.  
  10. setInitialState(mInitialState);// 设置初始状态为mInitialState
  11. ......// 和StateMachine日志记录相关设置
  12. start();// 启动状态机
  13. }

WifiStateMachine共定义30个状态,其种类和层级关系如图5-4所示。

5.2.3 WifiStateMachine介绍 - 图2

图5-4 WifiStateMachine中的状态及层级关系

图5-4中,箭头所指的状态为父状态。本节先介绍和初始状态的相关代码,其他状态的功能等碰到它们时再来分析。

提示 如果算上SupplicantStateTracker中的8个状态以及后续章节将要介绍的P2pStateMachine中的15个状态,Java层中Wi-Fi相关的状态机竟然多达63个状态(还没有计算Wi-Fi模块其他代码中定义的好些个状态机所包含的状态)。笔者很难理解为什么WifiService相关模块会定义如此多的状态。这些状态使得WifiService的分析难度陡增。而且,在整个Wi-Fi模块中,wpa_supplicant作为核心已经完成了绝大部分的工作,为什么WifiService还会如此复杂呢?欢迎读者对此问题和笔者展开讨论。

WifiStateMachine的初始状态是mInitialState,其类型是InitialState。根据前文对HSM的介绍,其enter函数将被调用(由于InitialState的父状态DefaultState并未实现enter函数,故此处略去)。

[—>WifiStateMachine.java::InitialState:enter]

  1. class InitialState extends State {
  2. public void enter() {
  3. // 判断Wlan Driver是否已经加载,其内部实现通过"wlan.driver.status"属性的值来判断
  4. if (mWifiNative.isDriverLoaded())
  5. transitionTo(mDriverLoadedState);
  6. else transitionTo(mDriverUnloadedState);// 假设此时驱动还没有加载,故我们将转入此状态
  7. // 获取和WifiP2pService交互的对象
  8. mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(
  9. Context.WIFI_P2P_SERVICE);
  10. // mWifiP2pChannel用于和WifiP2pService中的某个Handler交互
  11. mWifiP2pChannel.connect(mContext, getHandler(),
  12. mWifiP2pManager.getMessenger());
  13. try {
  14. mNwService.disableIpv6(mInterfaceName);
  15. // 禁止Ipv6,NWService将和Netd交互
  16. } ......
  17. }
  18. }

结合上述代码,当WifiStateMachine开始运行后,其最终将进入DriverUnloadedState。由于DriverUnloadedState的enter函数没有做什么有意义的工作,所以此处不再讨论它。

至此,WifiService第一条分析路线就算结束。虽然WifiService创建工作涉及的流程并不长,但相信读者也会感觉WifiService的代码难度其实并不算小。从下一节开始,读者还将进一步体会到这一点。

 可参考《深入理解Android:卷Ⅰ》第2章JNI相关的重要知识。

 笔者搜索了相关代码,在wlan芯片厂商提供的一些供WPAS使用的动态库中会发送DRIVER-EVENT。相关代码可参考hardware/broadcom/wlan/bcmdhd/wpa_supplicant_8_lib/driver_cmd_nl80211.c