Android9.0 Wifi模块Framework层分析

Android9.0 Wifi Module

一、WifiService的启动

​ Wifi Service是在SystemServer的startOtherServices中启动的。在其构造函数中主要新建了WifiServiceImpl对象,并传入了WifiInjector和WifiAsyncChannel其中WifiInjector创建了很多WiFi service需要用到的类,比如FrameworkFacade,WifiNative,WifiMonitor,WifiController等等,另外创建了四个HandleThread:1.mWifiServiceHandlerThread 2.mWifiStateMachineHandlerThread 3.mWifiAwareHandlerThread 4.mRttHandlerThread

​ 在WifiServiceImpl的构造函数中主要就是获取到WifiInjector的初始化的类。另外传入的WifiAsyncChannel对象则用来创建了WifiStateMachineHandler对象。在WifiStateMachineHandler初始化时调用了WifiAsyncChannel的connect将WifiStateMachineHandler和 mWifiStateMachine联系起来了。

接着当服务都准备好时则调用了WifiServiceImpl的checkAndStartWifi。

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
505      public void checkAndStartWifi() {
506          // First check if we will end up restarting WifiService
             //1. 检查设备是否解密
507          if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) {
508              Log.d(TAG, "Device still encrypted. Need to restart SystemServer.  Do not start wifi.");
509              return;
510          }
511          //2.通过Settings数据库检查是否需要打开wifi
512          // Check if wi-fi needs to be enabled
513          boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
514          Slog.i(TAG, "WifiService starting up with Wi-Fi " +
515                  (wifiEnabled ? "enabled" : "disabled"));
516          //3.注册Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE监听
517          registerForScanModeChange();
             //4.注册广播
518          mContext.registerReceiver(
519                  new BroadcastReceiver() {
520                      @Override
521                      public void onReceive(Context context, Intent intent) {
522                          if (mSettingsStore.handleAirplaneModeToggled()) {
523                              mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
524                          }
525                          if (mSettingsStore.isAirplaneModeOn()) {
526                              Log.d(TAG, "resetting country code because Airplane mode is ON");
527                              mCountryCode.airplaneModeEnabled();
528                          }
529                      }
530                  },
531                  new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
532  
533          mContext.registerReceiver(
534                  new BroadcastReceiver() {
535                      @Override
536                      public void onReceive(Context context, Intent intent) {
537                          String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
538                          if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
539                              Log.d(TAG, "resetting networks because SIM was removed");
540                              mWifiStateMachine.resetSimAuthNetworks(false);
541                          } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
542                              Log.d(TAG, "resetting networks because SIM was loaded");
543                              mWifiStateMachine.resetSimAuthNetworks(true);
544                          }
545                      }
546                  },
547                  new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
548  
549          mContext.registerReceiver(
550                  new BroadcastReceiver() {
551                      @Override
552                      public void onReceive(Context context, Intent intent) {
553                          final int currState = intent.getIntExtra(EXTRA_WIFI_AP_STATE,
554                                                                      WIFI_AP_STATE_DISABLED);
555                          final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE,
556                                                                   WIFI_AP_STATE_DISABLED);
557                          final int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON,
558                                                                   HOTSPOT_NO_ERROR);
559                          final String ifaceName =
560                                  intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
561                          final int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE,
562                                                              WifiManager.IFACE_IP_MODE_UNSPECIFIED);
563                          handleWifiApStateChange(currState, prevState, errorCode, ifaceName, mode);
564                      }
565                  },
566                  new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION));
567  
568          // Adding optimizations of only receiving broadcasts when wifi is enabled
569          // can result in race conditions when apps toggle wifi in the background
570          // without active user involvement. Always receive broadcasts.
571          registerForBroadcasts();
572          mInIdleMode = mPowerManager.isDeviceIdleMode();
573          //5.初始化mWifiStateMachine
574          if (!mWifiStateMachine.syncInitialize(mWifiStateMachineChannel)) {
575              Log.wtf(TAG, "Failed to initialize WifiStateMachine");
576          }
             //6.调用mWifiController.start 启动WiFiService
577          mWifiController.start();
578  
579          // If we are already disabled (could be due to airplane mode), avoid changing persist
580          // state here
581          if (wifiEnabled) {
582              try {
                     //7.如果需要打开WiFi那么直接开启
583                  setWifiEnabled(mContext.getPackageName(), wifiEnabled);
584              } catch (RemoteException e) {
585                  /* ignore - local call */
586              }
587          }
588      }

checkAndStartWifi主要做了以下几件事:

1.判断设备是否解密完成

2.从数据库中查询上一次WiFi的状态

3.注册Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE监听。

4.注册了三个关键广播分别是:Intent.ACTION_AIRPLANE_MODE_CHANGED TelephonyIntents.ACTION_SIM_STATE_CHANGED WifiManager.WIFI_AP_STATE_CHANGED_ACTION

5.注册其他广播

6.同步初始化mWifiStateMachine

7.调用 mWifiController.start

8.如果上次WiFi的状态时开启的,那么就开启WiFi

二、状态机(StateMachine)

在接着分析WiFi service前我们先看一下状态机,这个状态机在Wifi的模块中使用的特别多。

状态机就是一个定义了很多状态的机器,它收到消息后,会根据消息来切换这个机器的状态。状态机中的每一个状态是由State类的实例表示,State实例必须实现processMessage方法用来处理消息。并且可选的实现enter/exit/getName三个方法,enter/exit 等价于类的构造方法和销毁方法。start方法启动状态机。addState方法给状态机添加状态。setInitialState方法初始化初始状态。

执行完了start方法后状态机就可以接收处理消息了。当消息到来以后,当前状态就会调用processMessage来处理消息,如果当前State能够处理消息,那么消息处理过程就结束了,此时会根据具体情况选择切换或者不切换状态机的状态。如果当前State不能处理消息,那么就会递交父State的processMessage来处理,父状态如果还不能处理就继续往上递交。如果一个消息从未被处理,unhandledMessage方法会被调用。

如果要停止状态机,可以调用quitNow或者quit方法。

切换状态时,旧State的exit方法会被调用而新State的enter方法会被调用,同时他们父State也会做相同的事情。但是如果两个状态由相同的父状态,那么这个时候他们父状态就没有必要做任何操作。
StateMachine会在内部维护一个线程和Handler,所以每一个StateMachine都是一个线程。通过调用start来启动状态机,但其实在创建StateMachine对象时,线程就已经启动了,这里的状态机必须时直接创建才会新建一个线程,但是如果在创建状态机时传入了一个已经创建的线程Looper,那么这个状态机就会运行在这个已经创建的线程中。

先看一下状态机的代码例子:

141  class HelloWorld extends StateMachine {
142      HelloWorld(String name) {
143          super(name);
144          addState(mState1);
145          setInitialState(mState1);
146      }
147  
148      public static HelloWorld makeHelloWorld() {
149          HelloWorld hw = new HelloWorld("hw");
150          hw.start();
151          return hw;
152      }
153  
154      class State1 extends State {
155          @Override 
    		public boolean processMessage(Message message) {
156              log("Hello World");
157              return HANDLED;
158          }
159      }
160      State1 mState1 = new State1();
161  }
162  
163  void testHelloWorld() {
164      HelloWorld hw = makeHelloWorld();
165      hw.sendMessage(hw.obtainMessage());
166  }

1.初始化:

/frameworks/base/core/java/com/android/internal/util/StateMachine.java
1293      private void initStateMachine(String name, Looper looper) {
1294          mName = name;
1295          mSmHandler = new SmHandler(looper, this);
1296      }
1297  
1298      /**
1299       * Constructor creates a StateMachine with its own thread.
1300       *
1301       * @param name of the state machine
1302       */
1303      protected StateMachine(String name) {
1304          mSmThread = new HandlerThread(name);
1305          mSmThread.start();
1306          Looper looper = mSmThread.getLooper();
1307  
1308          initStateMachine(name, looper);
1309      }

从初始化就可以知道StateMachine会创建一个HandlerThread和一个SmHandler,SmHandler继承于Handler。

2.addState

addState有两种使用方式,一种是添加单个状态,另一种是添加一个子状态,添加子状态时需要指定父状态,并且父状态需要事先添加进去。

/frameworks/base/core/java/com/android/internal/util/StateMachine.java
1344      /**
1345       * Add a new state to the state machine
1346       * @param state the state to add
1347       * @param parent the parent of state
1348       */
1349      public final void addState(State state, State parent) {
1350          mSmHandler.addState(state, parent);
1351      }
1352  
1353      /**
1354       * Add a new state to the state machine, parent will be null
1355       * @param state to add
1356       */
1357      public final void addState(State state) {
1358          mSmHandler.addState(state, null);
1359      }
/frameworks/base/core/java/com/android/internal/util/StateMachine.java$SmHandler
1163          private final StateInfo addState(State state, State parent) {
1164              if (mDbg) {
1165                  mSm.log("addStateInternal: E state=" + state.getName() + ",parent="
1166                          + ((parent == null) ? "" : parent.getName()));
1167              }
1168              StateInfo parentStateInfo = null;
                  //获取父State的StateInfo
1169              if (parent != null) {
1170                  parentStateInfo = mStateInfo.get(parent);
1171                  if (parentStateInfo == null) {
1172                      // Recursively add our parent as it's not been added yet.
                          //如果父state没有添加,那么现在添加进去
1173                      parentStateInfo = addState(parent, null);
1174                  }
1175              }
                  //获取子State的StateInfo 
1176              StateInfo stateInfo = mStateInfo.get(state);
1177              if (stateInfo == null) {
1178                  stateInfo = new StateInfo();
1179                  mStateInfo.put(state, stateInfo);
1180              }
1181  
1182              // Validate that we aren't adding the same state in two different hierarchies.
1183              if ((stateInfo.parentStateInfo != null)
1184                      && (stateInfo.parentStateInfo != parentStateInfo)) {
1185                  throw new RuntimeException("state already added");
1186              }
1187              stateInfo.state = state;
1188              stateInfo.parentStateInfo = parentStateInfo;
1189              stateInfo.active = false;
1190              if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo);
1191              return stateInfo;
1192          }

从上面的代码中可以知道SmHandler的addState函数就是将State构造成stateInfo并加入到mStateInfo这个以State为key,以StateInfo为Value的HashMap中而StateInfo的结构如下:

725           */
726          private class StateInfo {
727              /** The state */
728              State state;
729  
730              /** The parent of this state, null if there is no parent */
731              StateInfo parentStateInfo;
732  
733              /** True when the state has been entered and on the stack */
734              boolean active;
735  
736              /**
737               * Convert StateInfo to string
738               */
739              @Override
740              public String toString() {
741                  return "state=" + state.getName() + ",active=" + active + ",parent="
742                          + ((parentStateInfo == null) ? "null" : parentStateInfo.state.getName());
743              }
744          }

我们可以通过子State追溯到最早的父State。

3.setInitialState

状态机调用setInitialState来设置初始状态,

 /frameworks/base/core/java/com/android/internal/util/StateMachine.java
1375      public final void setInitialState(State initialState) {
1376          mSmHandler.setInitialState(initialState);
1377      }
/frameworks/base/core/java/com/android/internal/util/StateMachine.java$SmHandler
1229          private final void setInitialState(State initialState) {
1230              if (mDbg) mSm.log("setInitialState: initialState=" + initialState.getName());
1231              mInitialState = initialState;
1232          }

可以看到我们的初始状态被保存在了SmHandler的全局变量mInitialState中。

4.start

 /frameworks/base/core/java/com/android/internal/util/StateMachine.java
2056      public void start() {
2057          // mSmHandler can be null if the state machine has quit.
2058          SmHandler smh = mSmHandler;
2059          if (smh == null) return;
2060  
2061          /** Send the complete construction message */
2062          smh.completeConstruction();
2063      }

如果StateMachine已经退出了并且mSmHandler被销毁,那么mSmHandler为null,这时调用start就直接返回,正常启动则是会调用到SmHandler的

completeConstruction函数。

/frameworks/base/core/java/com/android/internal/util/StateMachine.java$SmHandler
948          private final void completeConstruction() {
949              if (mDbg) mSm.log("completeConstruction: E");
950  
951              /**
952               * Determine the maximum depth of the state hierarchy
953               * so we can allocate the state stacks.
954               */
                 //这里遍历mStateInfo这个HashMap存储的每一个State确定父子状态的最大深度
955              int maxDepth = 0;
956              for (StateInfo si : mStateInfo.values()) {
957                  int depth = 0;
958                  for (StateInfo i = si; i != null; depth++) {
959                      i = i.parentStateInfo;
960                  }
961                  if (maxDepth < depth) {
962                      maxDepth = depth;
963                  }
964              }
965              if (mDbg) mSm.log("completeConstruction: maxDepth=" + maxDepth);
966              //根据最大深度创建两个StateInfo数组
967              mStateStack = new StateInfo[maxDepth];
968              mTempStateStack = new StateInfo[maxDepth];
                 //setupInitialStateStack则是将初始状态的族谱放到了mStateStack中并且是以父到子的关系存储,即初始状态被放在数组尾部
969              setupInitialStateStack();
970  
971              /** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
972              sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
973  
974              if (mDbg) mSm.log("completeConstruction: X");
975          }
1123          private final void setupInitialStateStack() {
1124              if (mDbg) {
1125                  mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName());
1126              }
1127              //通过StateInfo获取到所有的State的族谱并放到mTempStateStack数组中
1128              StateInfo curStateInfo = mStateInfo.get(mInitialState);
1129              for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
1130                  mTempStateStack[mTempStateStackCount] = curStateInfo;
1131                  curStateInfo = curStateInfo.parentStateInfo;
1132              }
1133  
1134              // Empty the StateStack
1135              mStateStackTopIndex = -1;
1136  
1137              moveTempStateStackToStateStack();
1138          }
1068          private final int moveTempStateStackToStateStack() {
                  //这里的startingIndex 是0
1069              int startingIndex = mStateStackTopIndex + 1;
1070              int i = mTempStateStackCount - 1;
1071              int j = startingIndex;
                  //这里将mTempStateStack颠倒后放到mStateStack中
1072              while (i >= 0) {
1073                  if (mDbg) mSm.log("moveTempStackToStateStack: i=" + i + ",j=" + j);
1074                  mStateStack[j] = mTempStateStack[i];
1075                  j += 1;
1076                  i -= 1;
1077              }
1078              //mStateStackTopIndex 则是初始状态在mStateStack数组的index
1079              mStateStackTopIndex = j - 1;
1080              if (mDbg) {
1081                  mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex
1082                          + ",startingIndex=" + startingIndex + ",Top="
1083                          + mStateStack[mStateStackTopIndex].state.getName());
1084              }
1085              return startingIndex;
1086          }

completeConstruction函数则是将初始状态的族谱放到了mStateStack数组中,接着发送了一个SM_INIT_CMD message

/frameworks/base/core/java/com/android/internal/util/StateMachine.java
1863      protected final void sendMessageAtFrontOfQueue(int what) {
1864          // mSmHandler can be null if the state machine has quit.
1865          SmHandler smh = mSmHandler;
1866          if (smh == null) return;
1867  
1868          smh.sendMessageAtFrontOfQueue(obtainMessage(what));
1869      }

sendMessageAtFrontOfQueue则是将消息发送给SmHandler去处理,看一下SmHandler是如何处理的:

/frameworks/base/core/java/com/android/internal/util/StateMachine.java$SmHandler
794          public final void handleMessage(Message msg) {
795              if (!mHasQuit) {
796                  if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
797                      mSm.onPreHandleMessage(msg);
798                  }
799  
800                  if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
801  
802                  /** Save the current message */
803                  mMsg = msg;
804  
805                  /** State that processed the message */
806                  State msgProcessedState = null;
807                  if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
808                      /** Normal path */
809                      msgProcessedState = processMsg(msg);
810                  } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
811                          && (mMsg.obj == mSmHandlerObj)) {
812                      /** Initial one time path. */
                         //第一次走这里调用invokeEnterMethods传入的是0
813                      mIsConstructionCompleted = true;
814                      invokeEnterMethods(0);
815                  } else {
816                      throw new RuntimeException("StateMachine.handleMessage: "
817                              + "The start method not called, received msg: " + msg);
818                  }
                     //切换至下一个状态
819                  performTransitions(msgProcessedState, msg);
820  
821                  // We need to check if mSm == null here as we could be quitting.
822                  if (mDbg && mSm != null) mSm.log("handleMessage: X");
824                  if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
825                      mSm.onPostHandleMessage(msg);
826                  }
827              }
828          }

1030          private final void invokeEnterMethods(int stateStackEnteringIndex) {
                  //初始化的时候这里的stateStackEnteringIndex传入的是0 可以看到这里会把初始状态的族谱的enter都执行一遍
1031              for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
1032                  if (stateStackEnteringIndex == mStateStackTopIndex) {
1033                      // Last enter state for transition
1034                      mTransitionInProgress = false;
1035                  }
1036                  if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());
1037                  mStateStack[i].state.enter();
1038                  mStateStack[i].active = true;
1039              }
1040              mTransitionInProgress = false; // ensure flag set to false if no methods called
1041          }

5.sendMessage

这里的sendMessage主要是向StateMachine内部的SmHandler发送消息并且发送的消息是我们自定义的message处理也仍然是SmHandler的handleMessage

/frameworks/base/core/java/com/android/internal/util/StateMachine.java
1770      public void sendMessage(Message msg) {
1771          // mSmHandler can be null if the state machine has quit.
1772          SmHandler smh = mSmHandler;
1773          if (smh == null) return;
1774  
1775          smh.sendMessage(msg);
1776      }
/frameworks/base/core/java/com/android/internal/util/StateMachine.java$SmHandler
794          public final void handleMessage(Message msg) {
795              if (!mHasQuit) {
796                  if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
797                      mSm.onPreHandleMessage(msg);
798                  }
799  
800                  if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
801  
802                  /** Save the current message */
803                  mMsg = msg;
804                 
805                  /** State that processed the message */
806                  State msgProcessedState = null;
807                  if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
808                      /** Normal path */
    					 //如果是我们自己定义的Message,那么就走processMsg
809                      msgProcessedState = processMsg(msg);
810                  } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
811                          && (mMsg.obj == mSmHandlerObj)) {
812                      /** Initial one time path. */
                         //第一次初始化走这里调用invokeEnterMethods传入的是0
813                      mIsConstructionCompleted = true;
814                      invokeEnterMethods(0);
815                  } else {
816                      throw new RuntimeException("StateMachine.handleMessage: "
817                              + "The start method not called, received msg: " + msg);
818                  }
                     //切换至下一个状态
819                  performTransitions(msgProcessedState, msg);
820  
821                  // We need to check if mSm == null here as we could be quitting.
822                  if (mDbg && mSm != null) mSm.log("handleMessage: X");
824                  if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
825                      mSm.onPostHandleMessage(msg);
826                  }
827              }
828          }

所以我们是自定义的Message的话会走processMsg

/frameworks/base/core/java/com/android/internal/util/StateMachine.java$SmHandler
983          private final State processMsg(Message msg) {
984              StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
985              if (mDbg) {
986                  mSm.log("processMsg: " + curStateInfo.state.getName());
987              }
988              //如果退出的msg那就切换到退出的状态
989              if (isQuit(msg)) {
990                  transitionTo(mQuittingState);
991              } else {
                     //我们自定义的msg主要调用当前State的processMessage来处理信息
992                  while (!curStateInfo.state.processMessage(msg)) {
993                      /**
994                       * Not processed
995                       */
                         //如果当前的State没法处理,那么就交给父State处理
996                      curStateInfo = curStateInfo.parentStateInfo;
997                      if (curStateInfo == null) {
998                          /**
999                           * No parents left so it's not handled
1000                           */
                              //如果一直没有State能处理那么就调用unhandledMessage
1001                          mSm.unhandledMessage(msg);
1002                          break;
1003                      }
1004                      if (mDbg) {
1005                          mSm.log("processMsg: " + curStateInfo.state.getName());
1006                      }
1007                  }
1008              }
                  //这里会返回处理msg的State对应的StateInfo
1009              return (curStateInfo != null) ? curStateInfo.state : null;
1010          }

6.切换状态transitionTo

/frameworks/base/core/java/com/android/internal/util/StateMachine.java
1413      public final void transitionTo(IState destState) {
1414          mSmHandler.transitionTo(destState);
1415      }
/frameworks/base/core/java/com/android/internal/util/StateMachine.java$SmHandler
1234          /** @see StateMachine#transitionTo(IState) */
1235          private final void transitionTo(IState destState) {
1236              if (mTransitionInProgress) {
1237                  Log.wtf(mSm.mName, "transitionTo called while transition already in progress to " +
1238                          mDestState + ", new target state=" + destState);
1239              }
1240              mDestState = (State) destState;
1241              if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName());
1242          }

可以看到transitionTo只是将下一个状态放到了SmHandler的mDestState全局变量

那么我们的状态切换是在哪里进行的呢?一般我们切换状态只能在某个State的processMessage中,所以只有当接受到消息后处理消息的过程中设置了下一个状态才会进行消息的切换。状态的切换是SmHandler的handleMessage中的 performTransitions函数:

834          private void performTransitions(State msgProcessedState, Message msg) {
                  //这里的msgProcessedState是处理msg的State
835              /**
836               * If transitionTo has been called, exit and then enter
837               * the appropriate states. We loop on this to allow
838               * enter and exit methods to use transitionTo.
839               */
840              State orgState = mStateStack[mStateStackTopIndex].state;
841  
842              /**
843               * Record whether message needs to be logged before we transition and
844               * and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
845               * always set msg.obj to the handler.
846               */
847              boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj != mSmHandlerObj);
848  
849              if (mLogRecords.logOnlyTransitions()) {
850                  /** Record only if there is a transition */
851                  if (mDestState != null) {
852                      mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
853                              orgState, mDestState);
854                  }
855              } else if (recordLogMsg) {
856                  /** Record message */
857                  mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState, orgState,
858                          mDestState);
859              }
860              //在上面我们设置了mDestState 也就是下一个State
861              State destState = mDestState;
862              if (destState != null) {
863                  /**
864                   * Process the transitions including transitions in the enter/exit methods
865                   */
866                  while (true) {
867                      if (mDbg) mSm.log("handleMessage: new destination call exit/enter");
868  
869                      /**
870                       * Determine the states to exit and enter and return the
871                       * common ancestor state of the enter/exit states. Then
872                       * invoke the exit methods then the enter methods.
873                       */
                         //将我们需要切换的目标State设置到mTempStateStack中
    					 //这里返回的是切换的目标State的第一个祖先
874                      StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
875                      // flag is cleared in invokeEnterMethods before entering the target state
876                      mTransitionInProgress = true;
                         //mStateStack中不是切换目标状态的祖先的State都调用exit
877                      invokeExitMethods(commonStateInfo);
                         //将mTempStateStack颠倒后放到mStateStack中
878                      int stateStackEnteringIndex = moveTempStateStackToStateStack();
                         //调用所有族谱成员State的enter
879                      invokeEnterMethods(stateStackEnteringIndex);
880  
881                      /**
882                       * Since we have transitioned to a new state we need to have
883                       * any deferred messages moved to the front of the message queue
884                       * so they will be processed before any other messages in the
885                       * message queue.
886                       */
                         //这里主要是将上一个状态处理时调用 deferMessage存下的Message放到要切换的状态中执行
887                      moveDeferredMessageAtFrontOfQueue();
888                      //这时有新的状态需要切换的话
889                      if (destState != mDestState) {
890                          // A new mDestState so continue looping
891                          destState = mDestState;
892                      } else {
893                          // No change in mDestState so we're done
                             //这里跳出while 循环
894                          break;
895                      }
896                  }
897                  mDestState = null;
898              }
899  
900              /**
901               * After processing all transitions check and
902               * see if the last transition was to quit or halt.
903               */
904              if (destState != null) {
905                  if (destState == mQuittingState) {
906                      /**
907                       * Call onQuitting to let subclasses cleanup.
908                       */
909                      mSm.onQuitting();
910                      cleanupAfterQuitting();
911                  } else if (destState == mHaltingState) {
912                      /**
913                       * Call onHalting() if we've transitioned to the halting
914                       * state. All subsequent messages will be processed in
915                       * in the halting state which invokes haltedProcessMessage(msg);
916                       */
917                      mSm.onHalting();
918                  }
919              }
920          }

从上面代码来看可以知道切换状态只能在State的processMessage中设置下一个状态,并且会调用当前State的父State的exit并调用目标所有状态的父State的enter,同时在切换到下一个状态时会执行上一次调用deferMessage存下的所有消息。

了解了上面的StateMachine后我们再来看Wifi相关的操作,

一般Wifi相关的操作主要有三种:1 .打开/关闭WiFi 2.扫描WiFi 3.连接WiFi

另外还有热点开关下面我们分章节分别介绍这些操作

三、打开WiFi

3.1 WifiManager

打开关闭WiFi主要调用的是WifiManager的setWifiEnabled,通过传入一个boolean值来开启和关闭Wifi true代表开启,false代表关闭

/frameworks/base/wifi/java/android/net/wifi/WifiManager.java
1802      public boolean setWifiEnabled(boolean enabled) {
1803          try {
                  //这里的mService是WifiServiceImpl
1804              return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
1805          } catch (RemoteException e) {
1806              throw e.rethrowFromSystemServer();
1807          }
1808      }

所有WifiManager中调用到mService的接口都会通过Binder调用到WifiServiceImpl中的对应接口,所以这里调用到WifiServiceImpl的setWifiEnabled

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
806      @Override
807      public synchronized boolean setWifiEnabled(String packageName, boolean enable)
808              throws RemoteException {
             //1.检查权限
809          if (enforceChangePermission(packageName) != MODE_ALLOWED) {
810              return false;
811          }
812  
813          Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
814                      + ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
815          mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
816                  .c(Binder.getCallingUid()).c(enable).flush();
817          
818          boolean isFromSettings = checkNetworkSettingsPermission(
819                  Binder.getCallingPid(), Binder.getCallingUid());
820          //如果飞行模式开启并且没有android.Manifest.permission.NETWORK_SETTINGS权限直接返回
821          // If Airplane mode is enabled, only Settings is allowed to toggle Wifi
822          if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
823              mLog.info("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
824              return false;
825          }
826          //如果热点是开启的状态并且没有NETWORK_SETTINGS权限,禁止操作WiFi
827          // If SoftAp is enabled, only Settings is allowed to toggle wifi
828          boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED;
829  
830          if (apEnabled && !isFromSettings) {
831              mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
832              return false;
833          }
834  
835          /*
836          * Caller might not have WRITE_SECURE_SETTINGS,
837          * only CHANGE_WIFI_STATE is enforced
838          */
839          long ident = Binder.clearCallingIdentity();
840          try {
841              if (! mSettingsStore.handleWifiToggled(enable)) {
842                  // Nothing to do if wifi cannot be toggled
843                  return true;
844              }
845          } finally {
846              Binder.restoreCallingIdentity(ident);
847          }
848  
849          //mPermissionReviewRequired 主要是由ro.permission_review_required属性和config_permissionReviewRequired共同控制
850          if (mPermissionReviewRequired) {
                 //跳转到权限申请界面 具体是/packages/apps/Settings/src/com/android/settings/wifi/RequestToggleWiFiActivity.java
851              final int wiFiEnabledState = getWifiEnabledState();
852              if (enable) {
853                  if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
854                          || wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {
855                      if (startConsentUi(packageName, Binder.getCallingUid(),
856                              WifiManager.ACTION_REQUEST_ENABLE)) {
857                          return true;
858                      }
859                  }
860              } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
861                      || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
862                  if (startConsentUi(packageName, Binder.getCallingUid(),
863                          WifiManager.ACTION_REQUEST_DISABLE)) {
864                      return true;
865                  }
866              }
867          }
868          //向mWifiController发送CMD_WIFI_TOGGLED消息
869          mWifiController.sendMessage(CMD_WIFI_TOGGLED);
870          return true;
871      }

WifiServiceImpl的setWifiEnabled主要是检查权限,具体的WiFi操作交给了mWifiController去执行。

3.2 WifiControler

WifiControler继承于StateMachine说明它是一个状态机。它的状态如下:
WifiControlerState.png
可以看到初始化的状态是StaDisabledState当WifiController这个状态机启动时会分别调用DefaultState和StaDisabledState的enter函数

当我们接受到CMD_WIFI_TOGGLED消息后就会在StaDisabledState这个状态的processMessage处理,处理过程如下:

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java$StaDisabledState
353                  case CMD_WIFI_TOGGLED:
354                      if (mSettingsStore.isWifiToggleEnabled()) {
                             //这里主要将msg暂存下来切换到DeviceActiveState
355                          if (doDeferEnable(msg)) {
356                              if (mHaveDeferredEnable) {
357                                  //  have 2 toggles now, inc serial number and ignore both
358                                  mDeferredEnableSerialNumber++;
359                              }
360                              mHaveDeferredEnable = !mHaveDeferredEnable;
361                              break;
362                          }
363                          transitionTo(mDeviceActiveState);
364                      } else if (checkScanOnlyModeAvailable()) {
365                          // only go to scan mode if we aren't in airplane mode
366                          if (mSettingsStore.isAirplaneModeOn()) {
367                              transitionTo(mStaDisabledWithScanState);
368                          }
369                      }
370                      break;

可以看到StaDisabledState对CMD_WIFI_TOGGLED的处理主要是暂存然后切换到下一个状态DeviceActiveState,当切换到DeviceActiveState时会调用DeviceActiveState的enter函数:

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java$DeviceActiveState
677          public void enter() {
678              mWifiStateMachinePrime.enterClientMode();
679              mWifiStateMachine.setHighPerfModeEnabled(false);
680          }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java
154      public void enterClientMode() {
155          changeMode(ModeStateMachine.CMD_START_CLIENT_MODE);
156      }
241      private void changeMode(int newMode) {
242          mModeStateMachine.sendMessage(newMode);
243      }

打开WiFi的重点流程就在enterClientMode的调用中enterClientMode主要是调用了changeMode向mModeStateMachine发送了一条CMD_START_CLIENT_MODE的消息。

3.3 WifiStateMachinePrime

而mModeStateMachine也是一个简单的状态机,如下:

 ModeStateMachine.png

所以CMD_START_CLIENT_MODE这条消息会在WifiDisabledState的processMessage中处理,

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java$ModeStateMachine$WifiDisabledState
338              public boolean processMessage(Message message) {
339                  Log.d(TAG, "received a message in WifiDisabledState: " + message);
340                  if (checkForAndHandleModeChange(message)) {
341                      return HANDLED;
342                  }
343                  return NOT_HANDLED;
344              }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java$ModeStateMachine
287          private boolean checkForAndHandleModeChange(Message message) {
288              switch(message.what) {
289                  case ModeStateMachine.CMD_START_CLIENT_MODE:
290                      Log.d(TAG, "Switching from " + getCurrentMode() + " to ClientMode");
291                      mModeStateMachine.transitionTo(mClientModeActiveState);
292                      break;
293                  case ModeStateMachine.CMD_START_SCAN_ONLY_MODE:
294                      Log.d(TAG, "Switching from " + getCurrentMode() + " to ScanOnlyMode");
295                      mModeStateMachine.transitionTo(mScanOnlyModeActiveState);
296                      break;
297                  case ModeStateMachine.CMD_DISABLE_WIFI:
298                      Log.d(TAG, "Switching from " + getCurrentMode() + " to WifiDisabled");
299                      mModeStateMachine.transitionTo(mWifiDisabledState);
300                      break;
301                  default:
302                      return NOT_HANDLED;
303              }
304              return HANDLED;
305          }

接着WifiDisabledState则调用了ModeStateMachine的checkForAndHandleModeChange切换状态机到ClientModeActiveState状态。当切换到ClientModeActiveState状态时,会先调用ClientModeActiveState的enter函数:

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java$ModeStateMachine$ClientModeActiveState
381              @Override
382              public void enter() {
383                  Log.d(TAG, "Entering ClientModeActiveState");
384  
385                  mListener = new ClientListener();
386                  mManager = mWifiInjector.makeClientModeManager(mListener);
387                  mManager.start();
388                  mActiveModeManagers.add(mManager);
389  
390                  updateBatteryStatsWifiState(true);
391              }

3.4 ClientModeManager

这里将会调用ClientModeManager的start函数向ClientModeStateMachine中发送一条CMD_START消息。这里的ClientModeManager在初始化时创建了一个ClientModeStateMachine,运行在WifiStateMachine这个线程上。ClientModeStateMachine如下:

ClientModeStateMachine.png

CMD_START这条消息则会在 IdleState中处理

     /frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java$ClientModeStateMachine$IdleState
219              @Override
220              public boolean processMessage(Message message) {
221                  switch (message.what) {
222                      case CMD_START:
223                          updateWifiState(WifiManager.WIFI_STATE_ENABLING,
224                                          WifiManager.WIFI_STATE_DISABLED);
225  
226                          mClientInterfaceName = mWifiNative.setupInterfaceForClientMode(
227                                  false /* not low priority */, mWifiNativeInterfaceCallback);
228                          if (TextUtils.isEmpty(mClientInterfaceName)) {
229                              Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
230                              updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
231                                              WifiManager.WIFI_STATE_ENABLING);
232                              updateWifiState(WifiManager.WIFI_STATE_DISABLED,
233                                              WifiManager.WIFI_STATE_UNKNOWN);
234                              break;
235                          }
                             //发送广播WIFI_SCAN_AVAILABLE 放入EXTRA_SCAN_AVAILABLE的是WIFI_STATE_DISABLED
236                          sendScanAvailableBroadcast(false);
237                          mScanRequestProxy.enableScanningForHiddenNetworks(false);
238                          mScanRequestProxy.clearScanResults();
                             //开启扫描流程
239                          transitionTo(mStartedState);
240                          break;
241                      default:
242                          Log.d(TAG, "received an invalid message: " + message);
243                          return NOT_HANDLED;
244                  }
245                  return HANDLED;
246              }

在CMD_START这条消息的处理中首先调用WifiNative的setupInterfaceForClientMode配置WiFi并获取到ClientInterfaceName,接着发送WIFI_SCAN_AVAILABLE的广播,最后切换到StartedState中,这里我们先关注setupInterfaceForClientMode

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
847     public String setupInterfaceForClientMode(boolean lowPrioritySta,
848             @NonNull InterfaceCallback interfaceCallback) {
849         synchronized (mLock) {
                //启动HAL
850             if (!startHal()) {
851                 Log.e(TAG, "Failed to start Hal");
852                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
853                 return null;
854             }
                //启动supplicant
855             if (!startSupplicant()) {
856                 Log.e(TAG, "Failed to start supplicant");
857                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
858                 return null;
859             }
                //创建一个 Iface 类型是STA(Station) 无线客户端
860             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA);
861             if (iface == null) {
862                 Log.e(TAG, "Failed to allocate new STA iface");
863                 return null;
864             }
865             iface.externalListener = interfaceCallback;
                //调用createStaIface 设置WiFichip并获取客户端的name
866             iface.name = createStaIface(iface, lowPrioritySta);
867             if (TextUtils.isEmpty(iface.name)) {
868                 Log.e(TAG, "Failed to create STA iface in vendor HAL");
869                 mIfaceMgr.removeIface(iface.id);
870                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
871                 return null;
872             }
                //WificondControl设置STA客户端模式
873             if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {
874                 Log.e(TAG, "Failed to setup iface in wificond on " + iface);
875                 teardownInterface(iface.name);
876                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
877                 return null;
878             }
                //设置向HAL层设置WIFI
879             if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
880                 Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
881                 teardownInterface(iface.name);
882                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
883                 return null;
884             }
                //向NetworkManagerService注册监听
885             iface.networkObserver = new NetworkObserverInternal(iface.id);
886             if (!registerNetworkObserver(iface.networkObserver)) {
887                 Log.e(TAG, "Failed to register network observer on " + iface);
888                 teardownInterface(iface.name);
889                 return null;
890             }
                //调用WiFiMonitor来监听来自底层的消息
891             mWifiMonitor.startMonitoring(iface.name);
892             // Just to avoid any race conditions with interface state change callbacks,
893             // update the interface state before we exit.
894             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
895             initializeNwParamsForClientInterface(iface.name);
896             Log.i(TAG, "Successfully setup " + iface);
897             return iface.name;
898         }
899     }

在WifiNative的setupInterfaceForClientMode主要有做了以下工作:

1.启动HAL,startHal

2.启动supplicant,startSupplicant

3.创建一个 Iface 类型是STA(Station) 无线客户端

4.调用createStaIface 设置WiFichip并获取客户端的name

5.WificondControl设置STA客户端模式

6.设置向HAL层设置WIFI

7.向NetworkManagerService注册监听

8.调用WiFiMonitor来监听来自底层的消息

下面我们分别看如何实现的

3.5 startHal

 /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
273      private boolean startHal() {
274          synchronized (mLock) {
                 //如果已经设置过Iface那么就证明hal已经启动不需要再次启动
275              if (!mIfaceMgr.hasAnyIface()) {
276                  if (mWifiVendorHal.isVendorHalSupported()) {
                         //调用startVendorHal启动HAL service
277                      if (!mWifiVendorHal.startVendorHal()) {
278                          Log.e(TAG, "Failed to start vendor HAL");
279                          return false;
280                      }
281                  } else {
282                      Log.i(TAG, "Vendor Hal not supported, ignoring start.");
283                  }
284              }
285              return true;
286          }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java     
369      public boolean startVendorHal() {
370          synchronized (sLock) {
371              if (!mHalDeviceManager.start()) {
372                  mLog.err("Failed to start vendor HAL").flush();
373                  return false;
374              }
375              mLog.info("Vendor Hal started successfully").flush();
376              return true;
377          }
378      }

WifiVendorHal的startVendorHal调用了mHalDeviceManager的start

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/HalDeviceManager.java	
165      public boolean start() {
166          return startWifi();
167      }
1155      private boolean startWifi() {
1156          if (VDBG) Log.d(TAG, "startWifi");
1157  
1158          synchronized (mLock) {
1159              try {
1160                  if (mWifi == null) {
1161                      Log.w(TAG, "startWifi called but mWifi is null!?");
1162                      return false;
1163                  } else {
1164                      int triedCount = 0;
                          //重试次数为3
1165                      while (triedCount <= START_HAL_RETRY_TIMES) {
                              // mWifi是IWifi接口和底层的WIFI HAL Service通过HWBinder进行通信
1166                          WifiStatus status = mWifi.start();
                             ... //一些返回状态的处理
						}
1193                  }
1194              } catch (RemoteException e) {
1195                  Log.e(TAG, "startWifi exception: " + e);
1196                  return false;
1197              }
1198          }
1199      }

HalDeviceManager最终通过IWifi接口调用到了WIFI的HAL Service。

3.6 startSupplicant

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
340      /** Helper method invoked to start supplicant if there were no STA ifaces */
341      private boolean startSupplicant() {
342          synchronized (mLock) {
343              if (!mIfaceMgr.hasAnyStaIface()) {
                     //调用了WificondControl.enableSupplicant来启动Supplicant
344                  if (!mWificondControl.enableSupplicant()) {
345                      Log.e(TAG, "Failed to enable supplicant");
346                      return false;
347                  }
348                  if (!waitForSupplicantConnection()) {
349                      Log.e(TAG, "Failed to connect to supplicant");
350                      return false;
351                  }
352                  if (!mSupplicantStaIfaceHal.registerDeathHandler(
353                          new SupplicantDeathHandlerInternal())) {
354                      Log.e(TAG, "Failed to register supplicant death handler");
355                      return false;
356                  }
357              }
358              return true;
359          }
360      }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
476      public boolean enableSupplicant() {
             //如果mWificond为null 获取Wificond
477          if (!retrieveWificondAndRegisterForDeath()) {
478              return false;
479          }
480          try {
481              return mWificond.enableSupplicant();
482          } catch (RemoteException e) {
483              Log.e(TAG, "Failed to enable supplicant due to remote exception");
484          }
485          return false;
486      }

wpa_supplicant 的启动调用到是WificondControl.enableSupplicant最终通过IWificond的binder调用到wificond进程的enableSupplicant

/system/connectivity/wificond/server.cpp
189  Status Server::enableSupplicant(bool* success) {
190    *success = supplicant_manager_->StartSupplicant();
191    return Status::ok();
192  }
/frameworks/opt/net/wifi/libwifi_system/supplicant_manager.cpp
43  bool SupplicantManager::StartSupplicant() {
44    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
45    int count = 200; /* wait at most 20 seconds for completion */
46    const prop_info* pi;
47    unsigned serial = 0;
48  
49    if (wifi_start_fstman(0)) {
50      return -1;
51    }
52  
53    /* Check whether already running */
54    if (property_get(kSupplicantInitProperty, supp_status, NULL) &&
55        strcmp(supp_status, "running") == 0) {
56      return true;
57    }
58  
59    /*
60     * Get a reference to the status property, so we can distinguish
61     * the case where it goes stopped => running => stopped (i.e.,
62     * it start up, but fails right away) from the case in which
63     * it starts in the stopped state and never manages to start
64     * running at all.
65     */
66    pi = __system_property_find(kSupplicantInitProperty);
67    if (pi != NULL) {
68      serial = __system_property_serial(pi);
69    }
70  
71    property_set("ctl.start", kMigrationServiceName);
72    property_set("ctl.start", kSupplicantServiceName);
73    sched_yield();
74  
75    while (count-- > 0) {
76      if (pi == NULL) {
77        pi = __system_property_find(kSupplicantInitProperty);
78      }
79      if (pi != NULL) {
80        /*
81         * property serial updated means that init process is scheduled
82         * after we sched_yield, further property status checking is based on this
83         */
84        if (__system_property_serial(pi) != serial) {
85          __system_property_read(pi, NULL, supp_status);
86          if (strcmp(supp_status, "running") == 0) {
87            return true;
88          } else if (strcmp(supp_status, "stopped") == 0) {
89            wifi_stop_fstman(0);
90            return false;
91          }
92        }
93      }
94      usleep(100000);
95    }
96    wifi_stop_fstman(0);
97    return false;
98  }

supplicant_manager的StartSupplicant主要是调用ctl.start 去启动bin文件,创建进程同时还启动了vendor.move_wifi_data

3.7 setupInterfaceForClientMode

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
236      public IClientInterface setupInterfaceForClientMode(@NonNull String ifaceName) {
237          Log.d(TAG, "Setting up interface for client mode");
238          if (!retrieveWificondAndRegisterForDeath()) {
239              return null;
240          }
241  
242          IClientInterface clientInterface = null;
243          try {
                 //调用到Wificond中创建一个clientInterface
244              clientInterface = mWificond.createClientInterface(ifaceName);
245          } catch (RemoteException e1) {
246              Log.e(TAG, "Failed to get IClientInterface due to remote exception");
247              return null;
248          }
249  
250          if (clientInterface == null) {
251              Log.e(TAG, "Could not get IClientInterface instance from wificond");
252              return null;
253          }
254          Binder.allowBlocking(clientInterface.asBinder());
255  
256          // Refresh Handlers
257          mClientInterfaces.put(ifaceName, clientInterface);
258          try {   
                 //这里的IWifiScannerImpl的服务端是/system/connectivity/wificond/scanning/scanner_impl.cpp 
259              IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
260              if (wificondScanner == null) {
261                  Log.e(TAG, "Failed to get WificondScannerImpl");
262                  return null;
263              }                 
264              mWificondScanners.put(ifaceName, wificondScanner);
265              Binder.allowBlocking(wificondScanner.asBinder());
    			//注册扫描事件的监听
266              ScanEventHandler scanEventHandler = new ScanEventHandler(ifaceName);
267              mScanEventHandlers.put(ifaceName,  scanEventHandler);
268              wificondScanner.subscribeScanEvents(scanEventHandler);
269              PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(ifaceName);
270              mPnoScanEventHandlers.put(ifaceName,  pnoScanEventHandler);
271              wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
272          } catch (RemoteException e) {
273              Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
274          }
276          return clientInterface;
277      }

WificondControl的setupInterfaceForClientMode主要是创建一个clientInterface(主要负责设置获取MAC地址)并注册扫描事件的监听

3.8 setupIface

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
367      public boolean setupIface(@NonNull String ifaceName) {
368          synchronized (mLock) {
369              final String methodStr = "setupIface";
370              if (checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr) != null) return false;
371              if (!checkSupplicantAndLogFailure(methodStr)) return false;
372              ISupplicantIface ifaceHwBinder;
373  
374              if (isV1_1()) {
375                  ifaceHwBinder = addIfaceV1_1(ifaceName);
376              } else {
377                  ifaceHwBinder = getIfaceV1_0(ifaceName);
378              }
379              if (ifaceHwBinder == null) {
380                  Log.e(TAG, "setupIface got null iface");
381                  return false;
382              }
383              SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
384  
385              if (isV1_1()) {
386                  android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface =
387                      getStaIfaceMockableV1_1(ifaceHwBinder);
388                  SupplicantStaIfaceHalCallbackV1_1 callbackV1_1 =
389                      new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback);
390  
391                  if (!registerCallbackV1_1(iface, callbackV1_1)) {
392                      return false;
393                  }
394                  mISupplicantStaIfaces.put(ifaceName, iface);
395                  mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV1_1);
396              } else {
397                  ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder);
398  
399                  if (!registerCallback(iface, callback)) {
400                      return false;
401                  }
402                  mISupplicantStaIfaces.put(ifaceName, iface);
403                  mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
404              }
405              /** creation vendor sta iface binder */
406              if (!vendor_setupIface(ifaceName, callback))
407                  Log.e(TAG, "Failed to create vendor setupiface");
408  
409              return true;
410          }
411      }

SupplicantStaIfaceHal.setupIface主要就是向wpa_supplicant注册一个回调,回调结果在SupplicantStaIfaceHalCallback

3.9 startMonitoring

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
196      public synchronized void startMonitoring(String iface) {
197          if (mVerboseLoggingEnabled) Log.d(TAG, "startMonitoring(" + iface + ")");
             //将mMonitoringMap iface对应的value置为ture 接着发送SUP_CONNECTION_EVENT消息
198          setMonitoring(iface, true);
199          broadcastSupplicantConnectionEvent(iface);
200      }

WifiMonitor的startMonitoring主要就是将map中的值置为true,接着发送SUP_CONNECTION_EVENT消息,这里的发送是通过handler发送的,在创建时会通过registerHandler为每一条消息注册对应的handler。搜索代码库知道SUP_CONNECTION_EVENT没有注册,所以这条消息不会做任何处理。

总结一下打开WiFi所作的工作:

1.连接上WIFI HAL Service

2.启动wpa_supplicant

3.创建iface并注册一系列回调

四、WiFi扫描过程

4.1 ClientModeManager

WiFi扫描过程的触发是在上面3.4小节ClientModeManager向ClientModeStateMachine发送CMD_START处理的,CMD_START这条消息则会在 IdleState中处理时首先调用了WifiNative.setupInterfaceForClientMode开启WiFi,接着调用了transitionTo(mStartedState);将ClientModeStateMachine切换到了StartedState

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java$ClientModeStateMachine$StartedState
277              @Override
278              public void enter() {
279                  Log.d(TAG, "entering StartedState");
280                  mIfaceIsUp = false;
281                  onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName));
282                  mScanRequestProxy.enableScanningForHiddenNetworks(true);
283              }

切换到StartedState后会首先执行enter函数,在enter函数中主要是调用了onUpChanged

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java$ClientModeStateMachine$StartedState
251              private void onUpChanged(boolean isUp) {
252                  if (isUp == mIfaceIsUp) {
253                      return;  // no change
254                  }
255                  mIfaceIsUp = isUp;
                     //这里up代表打开,down代表关闭 所以走if分支
256                  if (isUp) {
257                      Log.d(TAG, "Wifi is ready to use for client mode");
                         //发送WIFI_SCAN_AVAILABLE的广播放入EXTRA_SCAN_AVAILABLE的是WIFI_STATE_ENABLED
258                      sendScanAvailableBroadcast(true);
                         //调用WifiStateMachine.setOperationalMode改变WifiStateMachine的状态
259                      mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE,
260                                                           mClientInterfaceName);
                         //更新WIFI的状态从ENABLING到ENABLED
261                      updateWifiState(WifiManager.WIFI_STATE_ENABLED,
262                                      WifiManager.WIFI_STATE_ENABLING);
263                  } else {
264                      if (mWifiStateMachine.isConnectedMacRandomizationEnabled()) {
265                          // Handle the error case where our underlying interface went down if we
266                          // do not have mac randomization enabled (b/72459123).
267                          return;
268                      }
269                      // if the interface goes down we should exit and go back to idle state.
270                      Log.d(TAG, "interface down!");
271                      updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
272                                      WifiManager.WIFI_STATE_ENABLED);
273                      mStateMachine.sendMessage(CMD_INTERFACE_DOWN);
274                  }
275              }

onUpChanged先发送了一个WIFI_SCAN_AVAILABLE的广播,接收者是WifiScanningServiceImpl,WifiScanningServiceImpl接收到广播的处理主要是告知其中的状态机驱动已经加载。接着调用WifiStateMachine.setOperationalMode改变WifiStateMachine的状态(这里和我们后面WiFi连接的过程有关),最后调用updateWifiState更新WIFI的状态从ENABLING到ENABLED,

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
132      private void updateWifiState(int newState, int currentState) {
133          if (!mExpectedStop) {
134              mListener.onStateChanged(newState);
135          } else {
136              Log.d(TAG, "expected stop, not triggering callbacks: newState = " + newState);
137          }
138  
139          // Once we report the mode has stopped/failed any other stop signals are redundant
140          // note: this can happen in failure modes where we get multiple callbacks as underlying
141          // components/interface stops or the underlying interface is destroyed in cleanup
142          if (newState == WifiManager.WIFI_STATE_UNKNOWN
143                  || newState == WifiManager.WIFI_STATE_DISABLED) {
144              mExpectedStop = true;
145          }
146  
147          if (newState == WifiManager.WIFI_STATE_UNKNOWN) {
148              // do not need to broadcast failure to system
149              return;
150          }
151          //设置WifiStateMachine为新状态这里是enabled
152          mWifiStateMachine.setWifiStateForApiCalls(newState);
153  		 //发送WIFI_STATE_CHANGED_ACTION广播
154          final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
155          intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
156          intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState);
157          intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, currentState);
158          mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
159      }

updateWifiState更新状态后发送WIFI_STATE_CHANGED_ACTION静态广播,触发扫描的接收者是WifiTracker

4.2 WifiTracker

/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
797      final BroadcastReceiver mReceiver = new BroadcastReceiver() {
798          @Override
799          public void onReceive(Context context, Intent intent) {
800              String action = intent.getAction();
801              sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
802  
803              if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
804                  updateWifiState(
805                          intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
806                                  WifiManager.WIFI_STATE_UNKNOWN));
807              } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
808                ...
825          }
826      };

WifiTracker接受到广播后调用updateWifiState更新状态到enabled

/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
834      private void updateWifiState(int state) {
835          if (state == WifiManager.WIFI_STATE_ENABLED) {
836              if (mScanner != null) {
837                  // We only need to resume if mScanner isn't null because
838                  // that means we want to be scanning.
839                  mScanner.resume();
840              }
841          } else {
842              clearAccessPointsAndConditionallyUpdate();
843              mLastInfo = null;
844              mLastNetworkInfo = null;
845              if (mScanner != null) {
846                  mScanner.pause();
847              }
848              mStaleScanResults = true;
849          }
850          mListener.onWifiStateChanged(state);
851      }

updateWifiState在更新到WIFI_STATE_ENABLED时会调用 mScanner.resume(),mScanner是一个handler主要工作就是每隔10s触发一次扫描的操作,主要调用mWifiManager.startScan()开启扫描。

4.3 startScan

/frameworks/base/wifi/java/android/net/wifi/WifiManager.java
1734      @Deprecated
1735      public boolean startScan() {
1736          return startScan(null);
1737      }
1738  
1739      /** @hide */
1740      @SystemApi
1741      @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
1742      public boolean startScan(WorkSource workSource) {
1743          try {
1744              String packageName = mContext.getOpPackageName();
1745              return mService.startScan(packageName);
1746          } catch (RemoteException e) {
1747              throw e.rethrowFromSystemServer();
1748          }
1749      }

接着通过Binder调用到WifiServiceImpl的startScan

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
677      public boolean startScan(String packageName) {
             ...//一些权限的检查和校验
699          try {
700              mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid);
701              Mutable<Boolean> scanSuccess = new Mutable<>();
                 //在WifiStateMachine的线程中执行ScanRequestProxy.startScan
702              boolean runWithScissorsSuccess = mWifiInjector.getWifiStateMachineHandler()
703                      .runWithScissors(() -> {
704                          scanSuccess.value = mScanRequestProxy.startScan(callingUid, packageName);
705                      }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
706              if (!runWithScissorsSuccess) {
707                  Log.e(TAG, "Failed to post runnable to start scan");
708                  sendFailedScanBroadcast();
709                  return false;
710              }
711              if (!scanSuccess.value) {
712                  Log.e(TAG, "Failed to start scan");
713                  return false;
714              }
715          } catch (SecurityException e) {
716              return false;
717          } finally {
718              Binder.restoreCallingIdentity(ident);
719          }
720          return true;
721      }

WifiServiceImpl的startScan则是通过WifiStateMachineHandler post了一个runable去执行ScanRequestProxy.startScan。

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
355      public boolean startScan(int callingUid, String packageName) {
             ...
             //继续调用WifiScanner.startScan 并传进去一个ScanRequestProxyScanListener用来接受回调信息
391          mWifiScanner.startScan(settings, new ScanRequestProxyScanListener(), workSource);
392          mIsScanProcessingComplete = false;
393          return true;
394      }
 /frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
836      @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
837      public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
838          Preconditions.checkNotNull(listener, "listener cannot be null");
839          int key = addListener(listener);
840          if (key == INVALID_KEY) return;
841          validateChannel();
842          Bundle scanParams = new Bundle();
843          scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
844          scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
845          mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
846      }

WifiScanner的startScan则是通过mAsyncChannel发送CMD_START_SINGLE_SCAN,至于消息的接收者是谁需要看一下AsyncChannel

/frameworks/base/core/java/com/android/internal/util/AsyncChannel.java
478      public void sendMessage(Message msg) {
479          msg.replyTo = mSrcMessenger;
480          try {
                 //调用mDstMessenger.send去发送消息
481              mDstMessenger.send(msg);
482          } catch (RemoteException e) {
483              replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
484          }
485      }

mDstMessenger在哪里赋值的呢?搜索AsyncChannel.java可以知道mDstMessenger有两处赋值,第一处是

395      public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
396          if (DBG) log("connected srcHandler to the dstMessenger  E");
397  
398          // Initialize source fields
399          mSrcContext = srcContext;
400          mSrcHandler = srcHandler;
401          mSrcMessenger = new Messenger(mSrcHandler);
402  
403          // Initialize destination fields
404          mDstMessenger = dstMessenger;
405          if (DBG) log("connected srcHandler to the dstMessenger X");
406      }

第二处是AsyncChannelConnection的回调。

/frameworks/base/core/java/com/android/internal/util/AsyncChannel.java
897      class AsyncChannelConnection implements ServiceConnection {
898          AsyncChannelConnection() {
899          }
900  
901          @Override
902          public void onServiceConnected(ComponentName className, IBinder service) {
903              mDstMessenger = new Messenger(service);
904              replyHalfConnected(STATUS_SUCCESSFUL);
905          }
906  
907          @Override
908          public void onServiceDisconnected(ComponentName className) {
909              replyDisconnected(STATUS_SUCCESSFUL);
910          }
911      }

那么主要是那处呢?回到WifiScanner的构造函数中可以看到他调用的是connectSync直接传入AsyncChannel中的

/frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
1190      public WifiScanner(Context context, IWifiScanner service, Looper looper) {
1191          mContext = context;
1192          mService = service;
1193  
1194          Messenger messenger = null;
1195          try {
1196              messenger = mService.getMessenger();
1197          } catch (RemoteException e) {
1198              throw e.rethrowFromSystemServer();
1199          }
1200  
1201          if (messenger == null) {
1202              throw new IllegalStateException("getMessenger() returned null!  This is invalid.");
1203          }
1204  
1205          mAsyncChannel = new AsyncChannel();
1206  
1207          mInternalHandler = new ServiceHandler(looper);
1208          mAsyncChannel.connectSync(mContext, mInternalHandler, messenger);
1209          // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
1210          // synchronously, which causes WifiScanningService to receive the wrong replyTo value.
1211          mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
1212      }

AsyncChannel.connectSync则会调用到第一处的connect,这里我们主要关注传入的messenger他是mService.getMessenger获取的,mService是一个

IWifiScanner接口,他的服务端是WifiScanningServiceImpl,所以获取的Messenger也是WifiScanningServiceImpl的messager。同时还发送了一条CMD_CHANNEL_FULL_CONNECTION消息,这条消息也是在WifiScanningServiceImpl,主要是将客户端的消息保存在WifiScanningServiceImpl的mClients中

4.4 WifiScanningServiceImpl

WifiScanningServiceImpl的messager是包装的ClientHandler,所以调用AsyncChannel.sendMessage发送的CMD_START_SINGLE_SCAN就是在 ClientHandler中处理的

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
133      private class ClientHandler extends WifiHandler {
134  
135          ClientHandler(String tag, Looper looper) {
136              super(tag, looper);
137          }
138  
139          @Override
140          public void handleMessage(Message msg) {
141              super.handleMessage(msg);
142              switch (msg.what) {
                     ...
224                  case WifiScanner.CMD_START_SINGLE_SCAN:
225                  case WifiScanner.CMD_STOP_SINGLE_SCAN:
226                      mSingleScanStateMachine.sendMessage(Message.obtain(msg));

WifiScanningServiceImpl的ClientHandler接收到CMD_START_SINGLE_SCAN后则转发给了SingleScanStateMachine,SingleScanStateMachine是一个状态机

WifiSingleScanStateMachine.png

可以看到初始状态为DefaultState,在4.1小节我们提到过onUpChanged发送了一个WIFI_SCAN_AVAILABLE的广播,接收者是WifiScanningServiceImpl,WifiScanningServiceImpl接收到广播的处理主要是告知其中的状态机驱动已经加载。

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
public void startService() {
298          mContext.registerReceiver(
299                  new BroadcastReceiver() {
300                      @Override
301                      public void onReceive(Context context, Intent intent) {
302                          int state = intent.getIntExtra(
303                                  WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED);
304                          if (DBG) localLog("SCAN_AVAILABLE : " + state);
305                          if (state == WifiManager.WIFI_STATE_ENABLED) {
306                              mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
                                 //向SingleScanStateMachine发送CMD_DRIVER_LOADED消息
307                              mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
308                              mPnoScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
309                          } else if (state == WifiManager.WIFI_STATE_DISABLED) {
310                              mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
311                              mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
312                              mPnoScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
313                          }
314                      }
315                  }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE));
}

其中SingleScanStateMachine接收到消息后会切换到IdleState

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java$WifiSingleScanStateMachine
519          class DefaultState extends State {
520              @Override
521              public void enter() {
522                  mActiveScans.clear();
523                  mPendingScans.clear();
524              }
525              @Override
526              public boolean processMessage(Message msg) {
527                  switch (msg.what) {
528                      case CMD_DRIVER_LOADED:
529                          if (mScannerImpl == null) {
530                              loge("Failed to start single scan state machine because scanner impl"
531                                      + " is null");
532                              return HANDLED;
533                          }
534                          transitionTo(mIdleState);
535                          return HANDLED;
	}

由于IdleState的父State是DriverStartedState所以IdleState和DriverStartedState的enter都会调用,在IdleState的enter函数中会调用 tryToStartNewScan函数。这时第一次扫描,也就是说当开启WiFi时就已经触发了一次扫描了。下面我们看CMD_START_SINGLE_SCAN是怎么处理的。由于当前的状态IdleState没有对CMD_START_SINGLE_SCAN消息的处理,所以会转交给他的父State DriverStartedState去处理。

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java$WifiSingleScanStateMachine
           class DriverStartedState extends State {
583              @Override
584              public void exit() {
594  
595              @Override
596              public boolean processMessage(Message msg) {
597                  ClientInfo ci = mClients.get(msg.replyTo);
598  
599                  switch (msg.what) {
600                      case CMD_DRIVER_LOADED:
601                          // Ignore if we're already in driver loaded state.
602                          return HANDLED;
603                      case WifiScanner.CMD_START_SINGLE_SCAN:
604                          mWifiMetrics.incrementOneshotScanCount();
605                          int handler = msg.arg2;
606                          Bundle scanParams = (Bundle) msg.obj;
607                          if (scanParams == null) {
608                              logCallback("singleScanInvalidRequest",  ci, handler, "null params");
609                              replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null");
610                              return HANDLED;
611                          }
612                          scanParams.setDefusable(true);
613                          ScanSettings scanSettings =
614                                  scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
615                          WorkSource workSource =
616                                  scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
617                          if (validateScanRequest(ci, handler, scanSettings)) {
618                              logScanRequest("addSingleScanRequest", ci, handler, workSource,
619                                      scanSettings, null);
620                              replySucceeded(msg);
621  
622                              // If there is an active scan that will fulfill the scan request then
623                              // mark this request as an active scan, otherwise mark it pending.
624                              // If were not currently scanning then try to start a scan. Otherwise
625                              // this scan will be scheduled when transitioning back to IdleState
626                              // after finishing the current scan.
                                 //由于我们这里是IdleState,所以走else分支最终也是调用到了tryToStartNewScan
627                              if (getCurrentState() == mScanningState) {
628                                  if (activeScanSatisfies(scanSettings)) {
629                                      mActiveScans.addRequest(ci, handler, workSource, scanSettings);
630                                  } else {
631                                      mPendingScans.addRequest(ci, handler, workSource, scanSettings);
632                                  }
633                              } else {
634                                  mPendingScans.addRequest(ci, handler, workSource, scanSettings);
635                                  tryToStartNewScan();
636                              }
637                          } else {
638                              logCallback("singleScanInvalidRequest",  ci, handler, "bad request");
639                              replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
640                              mWifiMetrics.incrementScanReturnEntry(
641                                      WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
642                          }
643                          return HANDLED;

DriverStartedState对于消息CMD_START_SINGLE_SCAN主要就是加入到mPendingScans这个ArrayList中接着调用tryToStartNewScan发起扫描

4.5 tryToStartNewScan

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
870          void tryToStartNewScan() {
871              if (mPendingScans.size() == 0) { // no pending requests
872                  return;
873              }
874              ...//构建扫描settings
                 //调用startSingleScan开始扫描
912              if (mScannerImpl.startSingleScan(settings, this)) {
                     //这里交换了mActiveScans和mPendingScans
913                  // store the active scan settings
914                  mActiveScanSettings = settings;
915                  // swap pending and active scan requests
916                  RequestList<ScanSettings> tmp = mActiveScans;
917                  mActiveScans = mPendingScans;
918                  mPendingScans = tmp;
919                  // make sure that the pending list is clear
920                  mPendingScans.clear();
921                  transitionTo(mScanningState);
922              } else {
923                  mWifiMetrics.incrementScanReturnEntry(
924                          WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size());
925                  // notify and cancel failed scans
926                  sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
927                          "Failed to start single scan");
928              }
929          }

tryToStartNewScan也是接着调用mScannerImpl.startSingleScan去扫描。这里的mScannerImpl是一个接口,实例是接收到CMD_DRIVER_LOADED消息后WifiBackgroundScanStateMachine通过 WifiScannerImpl.WifiScannerImplFactory创建的。创建的ScannerImpl对象有两种,一种是HalWifiScannerImpl,一种是WificondScannerImpl,但是最终其实都是调用的WificondScannerImpl的startSingleScan,接着交换了mActiveScans和mPendingScans主要是为了后面的扫描结果上报,最终切换到了ScanningState

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
152      @Override
153      public boolean startSingleScan(WifiNative.ScanSettings settings,
154              WifiNative.ScanEventHandler eventHandler) {
189  
190              boolean success = false;
191              Set<Integer> freqs;
192              if (!allFreqs.isEmpty()) {
193                  freqs = allFreqs.getScanFreqs();
                     //调用WifiNative.scan去扫描
194                  success = mWifiNative.scan(
195                          mIfaceName, settings.scanType, freqs, hiddenNetworkSSIDSet);
196                  if (!success) {
197                      Log.e(TAG, "Failed to start scan, freqs=" + freqs);
198                  }
199              } else {
200                  // There is a scan request but no available channels could be scanned for.
201                  // We regard it as a scan failure in this case.
202                  Log.e(TAG, "Failed to start scan because there is no available channel to scan");
203              }
204              if (success) {
205                  if (DBG) {
206                      Log.d(TAG, "Starting wifi scan for freqs=" + freqs);
207                  }
208  
209                  mScanTimeoutListener = new AlarmManager.OnAlarmListener() {
210                      @Override public void onAlarm() {
211                          handleScanTimeout();
212                      }
213                  };
214  
215                  mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
216                          mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
217                          TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
218              } else {
219                  // indicate scan failure async
220                  mEventHandler.post(new Runnable() {
221                          @Override public void run() {
222                              reportScanFailure();
223                          }
224                      });
225              }
226  
227              return true;
228          }
229      }

WificondScannerImpl则是调用WifiNative.scan去触发扫描,而WifiNative.scan又转交给mWificondControl.scan

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
1318      public boolean scan(
1319              @NonNull String ifaceName, int scanType, Set<Integer> freqs,
1320              Set<String> hiddenNetworkSSIDs) {
1321          return mWificondControl.scan(ifaceName, scanType, freqs, hiddenNetworkSSIDs);
1322      }
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
662      public boolean scan(@NonNull String ifaceName,
663                          int scanType,
664                          Set<Integer> freqs,
665                          Set<String> hiddenNetworkSSIDs) {
666          IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
667          if (scannerImpl == null) {
668              Log.e(TAG, "No valid wificond scanner interface handler");
669              return false;
670          }
             //构建SingleScanSettings
671          SingleScanSettings settings = new SingleScanSettings();
672          try {
673              settings.scanType = getScanType(scanType);
674          } catch (IllegalArgumentException e) {
675              Log.e(TAG, "Invalid scan type ", e);
676              return false;
677          }
678          settings.channelSettings  = new ArrayList<>();
679          settings.hiddenNetworks  = new ArrayList<>();
680  
681          if (freqs != null) {
682              for (Integer freq : freqs) {
683                  ChannelSettings channel = new ChannelSettings();
684                  channel.frequency = freq;
685                  settings.channelSettings.add(channel);
686              }
687          }
688          if (hiddenNetworkSSIDs != null) {
689              for (String ssid : hiddenNetworkSSIDs) {
690                  HiddenNetwork network = new HiddenNetwork();
691                  try {
692                      network.ssid = WifiGbk.getRandUtfOrGbkBytes(ssid); // wifigbk++
693                  } catch (IllegalArgumentException e) {
694                      Log.e(TAG, "Illegal argument " + ssid, e);
695                      continue;
696                  }
697                  if (network.ssid.length > MAX_SSID_LEN) {
698                      Log.e(TAG, "SSID is too long after conversion, skipping this ssid! SSID = " +
699                                  network.ssid + " , network.ssid.size = " + network.ssid.length);
700                      continue;
701                  }
702                  settings.hiddenNetworks.add(network);
703              }
704          }
705          //调用IWifiScannerImpl.scan去扫描
706          try {
707              return scannerImpl.scan(settings);
708          } catch (RemoteException e1) {
709              Log.e(TAG, "Failed to request scan due to remote exception");
710          }
711          return false;
712      }

WificondControl.scan则是通过binder将扫描请求转发给了wificond进程的scanner_impl

/system/connectivity/wificond/scanning/scanner_impl.cpp
150  Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
151                           bool* out_success) {
       ...
188  
189    int error_code = 0;
       //调用scan_utils_ -> scan
190    if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type,
191                           ssids, freqs, &error_code)) {
192      CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
193      *out_success = false;
194      return Status::ok();
195    }
196    scan_started_ = true;
197    *out_success = true;
198    return Status::ok();
199  }
/system/connectivity/wificond/scanning/scan_utils.cpp
275  bool ScanUtils::Scan(uint32_t interface_index,
276                       bool request_random_mac,
277                       int scan_type,
278                       const vector<vector<uint8_t>>& ssids,
279                       const vector<uint32_t>& freqs,
280                       int* error_code) {
281    NL80211Packet trigger_scan(
282        netlink_manager_->GetFamilyId(),
283        NL80211_CMD_TRIGGER_SCAN,
284        netlink_manager_->GetSequenceNumber(),
285        getpid());
       ...//trigger_scan add各种属性
336    // We are receiving an ERROR/ACK message instead of the actual
337    // scan results here, so it is OK to expect a timely response because
338    // kernel is supposed to send the ERROR/ACK back before the scan starts.
339    vector<unique_ptr<const NL80211Packet>> response;
       //调用发送消息给netlink_manager_ 
340    if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
341                                                       error_code)) {
342      // Logging is done inside |SendMessageAndGetAckOrError|.
343      return false;
344    }
345    if (*error_code != 0) {
346      LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);
347      return false;
348    }
349    return true;
350  }

最终是netlink_manager_通过Socket发送消息发起扫描。

五、获取WiFi扫描结果

WiFi扫描结果的回调主要有两处,第一处是WiFi打开时向WificondControl设置ClientMode,即3.7小节setupInterfaceForClientMode时调用 wificondScanner.subscribeScanEvents注册了扫描事件的监听,当有扫描结果时就会回调ScanEventHandler的OnScanResultReady。

第二处就是发起扫描时 4.3小节ScanRequestProxy的 startScan函数中在调用 mWifiScanner.startScan传入了ScanRequestProxyScanListener,当有扫描结果时会回调到ScanRequestProxyScanListener的onResults。

下面我们分别看一下这两个流程。

5.1ScanEventHandler.OnScanResultReady

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
84      private class ScanEventHandler extends IScanEvent.Stub {
85          private String mIfaceName;
86  
87          ScanEventHandler(@NonNull String ifaceName) {
88              mIfaceName = ifaceName;
89          }
90  
91          @Override
92          public void OnScanResultReady() {
93              Log.d(TAG, "Scan result ready event");
94              mWifiMonitor.broadcastScanResultEvent(mIfaceName);
95          }
96  
97          @Override
98          public void OnScanFailed() {
99              Log.d(TAG, "Scan failed event");
100              mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
101          }
102      }

ScanEventHandler.OnScanResultReady通过mWifiMonitor.broadcastScanResultEvent发送了一条SCAN_RESULTS_EVENT消息,这个消息时谁处理呢?需要看谁注册的,搜索发现是WificondScannerImpl.java注册的,所以是WificondScannerImpl去处理。

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
266      @Override
267      public boolean handleMessage(Message msg) {
268          switch(msg.what) {
269              case WifiMonitor.SCAN_FAILED_EVENT:
270                  Log.w(TAG, "Scan failed");
271                  cancelScanTimeout();
272                  reportScanFailure();
273                  break;
274              case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
275                  pollLatestScanDataForPno();
276                  break;
277              case WifiMonitor.SCAN_RESULTS_EVENT:
                     //取消扫描超时的倒计时
278                  cancelScanTimeout();
                     //导出扫描数据
279                  pollLatestScanData();
280                  break;
281              default:
282                  // ignore unknown event
283          }
284          return true;
285      }

重点是pollLatestScanData导出扫描数据

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java 
363      private void pollLatestScanData() {
364          synchronized (mSettingsLock) {
365              if (mLastScanSettings == null) {
366                   // got a scan before we started scanning or after scan was canceled
367                  return;
368              }
369              //从WifiNative获取扫描的结果
370              mNativeScanResults = mWifiNative.getScanResults(mIfaceName);
371              List<ScanResult> singleScanResults = new ArrayList<>();
372              int numFilteredScanResults = 0;
                 //判断扫描获取的时间,如果时间大于最后扫描的时间才会加入到singleScanResults中
373              for (int i = 0; i < mNativeScanResults.size(); ++i) {
374                  ScanResult result = mNativeScanResults.get(i).getScanResult();
375                  WifiGbk.processScanResult(result); // wifigbk++
376                  long timestamp_ms = result.timestamp / 1000; // convert us -> ms
377                  if (timestamp_ms > mLastScanSettings.startTime) {
378                      if (mLastScanSettings.singleScanFreqs.containsChannel(
379                                      result.frequency)) {
380                          singleScanResults.add(result);
381                      }
382                  } else {
383                      numFilteredScanResults++;
384                  }
385              }
386              if (numFilteredScanResults != 0) {
387                  Log.d(TAG, "Filtering out " + numFilteredScanResults + " scan results.");
388              }
389              WifiGbk.ageBssCache(); // wifigbk++
390              //这里的mLastScanSettings是在4.5小节的WificondScannerImpl调用startSingleScan创建的
391              if (mLastScanSettings.singleScanEventHandler != null) {
392                  if (mLastScanSettings.reportSingleScanFullResults) {
393                      for (ScanResult scanResult : singleScanResults) {
394                          // ignore buckets scanned since there is only one bucket for a single scan
                             //回调到WifiScanningServiceImpl的onFullScanResult
395                          mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult,
396                                  /* bucketsScanned */ 0);
397                      }
398                  }
399                  Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
                     //更新最新的扫描结果并回调到WifiScanningServiceImpl的onScanStatus
400                  mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, 0,
401                          isAllChannelsScanned(mLastScanSettings.singleScanFreqs),
402                          singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
403                  mLastScanSettings.singleScanEventHandler
404                          .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
405              }
406  
407              mLastScanSettings = null;
408          }
409      }

pollLatestScanData 主要是从WifiNative从获取扫描结果接着筛选出新增的扫描结果,最后向WifiScanningServiceImpl做各种回调比如onFullScanResult

和onScanStatus.而WifiNative获取扫描结果则是转发给了WificondControl去获取。

5.2WificondControl.getScanResults

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
1330      public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
1331          return mWificondControl.getScanResults(
1332                  ifaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
1333      }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
560      public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
561          ArrayList<ScanDetail> results = new ArrayList<>();
             //获取WifiScannerImpl的代理接口
562          IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
563          if (scannerImpl == null) {
564              Log.e(TAG, "No valid wificond scanner interface handler");
565              return results;
566          }
567          try {
568              NativeScanResult[] nativeResults;
    		     //由传入的参数可以知道是走if分支
569              if (scanType == SCAN_TYPE_SINGLE_SCAN) {
570                  nativeResults = scannerImpl.getScanResults();
571              } else {
572                  nativeResults = scannerImpl.getPnoScanResults();
573              }
574              for (NativeScanResult result : nativeResults) {
575                  WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
576                  String bssid;
577                  try {
578                      bssid = NativeUtil.macAddressFromByteArray(result.bssid);
579                  } catch (IllegalArgumentException e) {
580                      Log.e(TAG, "Illegal argument " + result.bssid, e);
581                      continue;
582                  }
583                  if (bssid == null) {
584                      Log.e(TAG, "Illegal null bssid");
585                      continue;
586                  }
587                  ScanResult.InformationElement[] ies =
588                          InformationElementUtil.parseInformationElements(result.infoElement);
589                  InformationElementUtil.Capabilities capabilities =
590                          new InformationElementUtil.Capabilities();
591                  capabilities.from(ies, result.capability);
592                  String flags = capabilities.generateCapabilitiesString();
593                  NetworkDetail networkDetail;
594                  try {
595                      networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
596                  } catch (IllegalArgumentException e) {
597                      Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
598                      continue;
599                  }
600                  //对每一个扫描的结果封装成ScanDetail加入到results中返回
601                  ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
602                          result.signalMbm / 100, result.frequency, result.tsf, ies, null);
603                  ScanResult scanResult = scanDetail.getScanResult();
604                  // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi
605                  // network and it uses EAP.
606                  ...
626                  results.add(scanDetail);
627              }
628          } catch (RemoteException e1) {
629              Log.e(TAG, "Failed to create ScanDetail ArrayList");
630          }
631          if (mVerboseLoggingEnabled) {
632              Log.d(TAG, "get " + results.size() + " scan results from wificond");
633          }
634  
635          return results;
636      }     

WificondControl.getScanResults最终通过binder调用到wificond进程的scanner_impl的getScanResults中。

5.3 IWifiScannerImpl.getScanResults

/system/connectivity/wificond/scanning/scanner_impl.cpp
123  Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
124    if (!CheckIsValid()) {
125      return Status::ok();
126    }
127    if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
128      LOG(ERROR) << "Failed to get scan results via NL80211";
129    }
130    return Status::ok();
131  }
/system/connectivity/wificond/scanning/scan_utils.cpp
77  bool ScanUtils::GetScanResult(uint32_t interface_index,
78                                vector<NativeScanResult>* out_scan_results) {
79    NL80211Packet get_scan(
80        netlink_manager_->GetFamilyId(),
81        NL80211_CMD_GET_SCAN,
82        netlink_manager_->GetSequenceNumber(),
83        getpid());
84    get_scan.AddFlag(NLM_F_DUMP);
85    NL80211Attr<uint32_t> ifindex(NL80211_ATTR_IFINDEX, interface_index);
86    get_scan.AddAttribute(ifindex);
87    //通过socket发送获取扫描结果的消息
88    vector<unique_ptr<const NL80211Packet>> response;
89    if (!netlink_manager_->SendMessageAndGetResponses(get_scan, &response))  {
90      LOG(ERROR) << "NL80211_CMD_GET_SCAN dump failed";
91      return false;
92    }
93    if (response.empty()) {
94      LOG(INFO) << "Unexpected empty scan result!";
95      return true;
96    }
97    //对回复进行解析 并最终将结果放到scan_result
98    for (auto& packet : response) {
99      if (packet->GetMessageType() == NLMSG_ERROR) {
100        LOG(ERROR) << "Receive ERROR message: "
101                   << strerror(packet->GetErrorCode());
102        continue;
103      }
104      if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
105        LOG(ERROR) << "Wrong message type: "
106                   << packet->GetMessageType();
107        continue;
108      }
109      uint32_t if_index;
110      if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
111        LOG(ERROR) << "No interface index in scan result.";
112        continue;
113      }
114      if (if_index != interface_index) {
115        LOG(WARNING) << "Uninteresting scan result for interface: " << if_index;
116        continue;
117      }
118  
119      NativeScanResult scan_result;
120      if (!ParseScanResult(std::move(packet), &scan_result)) {
121        LOG(DEBUG) << "Ignore invalid scan result";
122        continue;
123      }
124      out_scan_results->push_back(std::move(scan_result));
125    }
126    return true;
127  }

可以看到最终获取到的扫描结果是netlink_manager_通过socket发送get_scan消息获取到的回复,接着解析回复得到的。现在我们知道了获取扫描结果的过程,那么回到开头,回调是在哪里触发的呢?这就需要我们看一下ScanEventHandler是如何注册的了。

5.4 ScanEventHandler的回调时机

ScanEventHandler是在WificondControl的setupInterfaceForClientMode函数中调用 wificondScanner.subscribeScanEvents(scanEventHandler)进行注册的

这里的wificondScanner是IWifiScannerImpl接口最终通过binder调用到了wificond进程的scanner_impl中的subscribeScanEvents

371  Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
372    if (!CheckIsValid()) {
373      return Status::ok();
374    }
375  
376    if (scan_event_handler_ != nullptr) {
377      LOG(ERROR) << "Found existing scan events subscriber."
378                 << " This subscription request will unsubscribe it";
379    }
380    scan_event_handler_ = handler;
381    return Status::ok();
382  }

可以看到就是将ScanEventHandler的代理接口赋值给了scan_event_handler_,接着搜索OnScanResultReady

/system/connectivity/wificond/scanning/scanner_impl.cpp
408  void ScannerImpl::OnScanResultsReady(uint32_t interface_index, bool aborted,
409                                       vector<vector<uint8_t>>& ssids,
410                                       vector<uint32_t>& frequencies) {
411    if (!scan_started_) {
412      LOG(INFO) << "Received external scan result notification from kernel.";
413    }
414    scan_started_ = false;
415    if (scan_event_handler_ != nullptr) {
416      // TODO: Pass other parameters back once we find framework needs them.
         //这里会回调相应的接口到Framework
417      if (aborted) {
418        LOG(WARNING) << "Scan aborted";
419        scan_event_handler_->OnScanFailed();
420      } else {
421        scan_event_handler_->OnScanResultReady();
422      }
423    } else {
424      LOG(WARNING) << "No scan event handler found.";
425    }
426  }

最终是在netlink_manager发送消息接收到回复时通过以下调用链回调的ScannerImpl::OnScanResultsReady的

NetlinkManager::SendMessageAndGetResponses
->接收到回复NetlinkManager::ReceivePacketAndRunHandler
—> NetlinkManager::BroadcastHandler
-> NetlinkManager::OnSchedScanResultsReady
-> ScannerImpl::OnScanResultsReady

至此流程就回到5.1的OnScanResultReady了。

5.5 ScanRequestProxyScanListener.onResults

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
102      private class ScanRequestProxyScanListener implements WifiScanner.ScanListener {
103          @Override
104          public void onSuccess() {
105              // Scan request succeeded, wait for results to report to external clients.
106              if (mVerboseLoggingEnabled) {
107                  Log.d(TAG, "Scan request succeeded");
108              }
109          }
110  
111          @Override
112          public void onFailure(int reason, String description) {
113              Log.e(TAG, "Scan failure received. reason: " + reason + ",description: " + description);
114              sendScanResultBroadcastIfScanProcessingNotComplete(false);
115          }
116  
117          @Override
118          public void onResults(WifiScanner.ScanData[] scanDatas) {
119              ... 
                 //从回调的WifiScanner.ScanData获取到ScanResult数组并加入到mLastScanResults
128              WifiScanner.ScanData scanData = scanDatas[0];
129              ScanResult[] scanResults = scanData.getResults();
130              if (mVerboseLoggingEnabled) {
131                  Log.d(TAG, "Received " + scanResults.length + " scan results");
132              }
133              // Store the last scan results & send out the scan completion broadcast.
134              mLastScanResults.clear();
135              mLastScanResults.addAll(Arrays.asList(scanResults));
                 //发送广播
136              sendScanResultBroadcastIfScanProcessingNotComplete(true);
137          }
138  
139          @Override
140          public void onFullResult(ScanResult fullScanResult) {
141              // Ignore for single scans.
142          }
143  
144          @Override
145          public void onPeriodChanged(int periodInMs) {
146              // Ignore for single scans.
147          }
148      };
194       */
195      private void sendScanResultBroadcastIfScanProcessingNotComplete(boolean scanSucceeded) {
196          if (mIsScanProcessingComplete) {
197              Log.i(TAG, "No ongoing scan request. Don't send scan broadcast.");
198              return;
199          }
200          sendScanResultBroadcast(scanSucceeded);
201          mIsScanProcessingComplete = true;
202      }
203  
204      /**
205       * Helper method to send the scan request status broadcast.
206       */
207      private void sendScanResultBroadcast(boolean scanSucceeded) {
208          // clear calling identity to send broadcast
209          long callingIdentity = Binder.clearCallingIdentity();
210          try {
211              Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
212              intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
213              intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, scanSucceeded);
214              mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
215          } finally {
216              // restore calling identity
217              Binder.restoreCallingIdentity(callingIdentity);
218          }
219      }

ScanRequestProxyScanListener.onResults主要就是从回调的WifiScanner.ScanData获取到ScanResult数组并加入到mLastScanResults。接着发送SCAN_RESULTS_AVAILABLE_ACTION的广播。我们平时写WiFi扫描的代码一般也是监听这个广播,后获取扫描信息。

5.6 WifiTracker

在setting的蓝牙部分主要是WifiTracker注册了监听SCAN_RESULTS_AVAILABLE_ACTION的广播,下面看一下当收到这个广播后是如何处理的。

/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
797      final BroadcastReceiver mReceiver = new BroadcastReceiver() {
798          @Override
799          public void onReceive(Context context, Intent intent) {
800              String action = intent.getAction();
801              sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
802  
803              if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
804                  updateWifiState(
805                          intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
806                                  WifiManager.WIFI_STATE_UNKNOWN));
807              } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
808                  mStaleScanResults = false;
809  				 //获取扫描结果并设置更新WiFi扫描结果
810                  fetchScansAndConfigsAndUpdateAccessPoints();
811              } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
812                      || WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
813                  fetchScansAndConfigsAndUpdateAccessPoints();
814              } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
815                  // TODO(sghuman): Refactor these methods so they cannot result in duplicate
816                  // onAccessPointsChanged updates being called from this intent.
817                  NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
818                  updateNetworkInfo(info);
819                  fetchScansAndConfigsAndUpdateAccessPoints();
820              } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
821                  NetworkInfo info =
822                          mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
823                  updateNetworkInfo(info);
824              }
825          }
826      };
558      private void fetchScansAndConfigsAndUpdateAccessPoints() {
559          List<ScanResult> newScanResults = mWifiManager.getScanResults();
560  
561          // Filter all unsupported networks from the scan result list
562          final List<ScanResult> filteredScanResults =
563                  filterScanResultsByCapabilities(newScanResults);
564  
565          if (isVerboseLoggingEnabled()) {
566              Log.i(TAG, "Fetched scan results: " + filteredScanResults);
567          }
568  
569          List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
570          updateAccessPoints(filteredScanResults, configs);
571      }

从上面的代码可以看出SCAN_RESULTS_AVAILABLE_ACTION这个广播只是一个通知,扫描结果还是要通过WiFiManager自己去获取,获取到扫描结果后要先过滤一次,接着获取到已经设置过的WifiConfiguration列表,最后调用updateAccessPoints更新到Settings的应用中。

5.7 getScanResults

接着我们看一下WifiManager的getScanResults,我们知道WifiManager的大部分接口都会调用到WifiServiceImpl

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java 
2181      public List<ScanResult> getScanResults(String callingPackage) {
2182          enforceAccessPermission();
2183          int uid = Binder.getCallingUid();
2184          long ident = Binder.clearCallingIdentity();
2185          if (mVerboseLoggingEnabled) {
2186              mLog.info("getScanResults uid=%").c(uid).flush();
2187          }
2188          try {
2189              mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid);
2190              final List<ScanResult> scanResults = new ArrayList<>();
2191              boolean success = mWifiInjector.getWifiStateMachineHandler().runWithScissors(() -> {
                      //在WifiStateMachine的线程中执行了mScanRequestProxy.getScanResults()
2192                  scanResults.addAll(mScanRequestProxy.getScanResults());
2193              }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
2194              if (!success) {
2195                  Log.e(TAG, "Failed to post runnable to fetch scan results");
2196              }
2197              return scanResults;
2198          } catch (SecurityException e) {
2199              return new ArrayList<ScanResult>();
2200          } finally {
2201              Binder.restoreCallingIdentity(ident);
2202          }
2203      }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
401      public List<ScanResult> getScanResults() {
402          return mLastScanResults;
403      }

WifiServiceImpl的getScanResults和startScan是一样的,都是将调用mScanRequestProxy对应的接口且都在WifiStateMachine线程中执行。可以看到

ScanRequestProxy的getScanResults返回的是mLastScanResults,这里的mLastScanResults是在5.5小节ScanRequestProxyScanListener.onResults回调时放入的ScanResult数据。

5.8 updateAccessPoints

上面5.7小节的WifiTracker在最后会调用

/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java 
573      /** Update the internal list of access points. */
574      private void updateAccessPoints(final List<ScanResult> newScanResults,
575              List<WifiConfiguration> configs) {
576  
577          // Map configs and scan results necessary to make AccessPoints
578          final Map<String, WifiConfiguration> configsByKey = new ArrayMap(configs.size());
579          if (configs != null) {
580              for (WifiConfiguration config : configs) {
581                  configsByKey.put(AccessPoint.getKey(config), config);
582              }
583          }
             //更新扫描结果的缓存
584          ArrayMap<String, List<ScanResult>> scanResultsByApKey =
585                  updateScanResultCache(newScanResults);
586  
587          WifiConfiguration connectionConfig = null;
588          if (mLastInfo != null) {
589              connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs);
590          }
591  
592          // Rather than dropping and reacquiring the lock multiple times in this method, we lock
593          // once for efficiency of lock acquisition time and readability
594          synchronized (mLock) {
595              // Swap the current access points into a cached list for maintaining AP listeners
596              List<AccessPoint> cachedAccessPoints;
597              cachedAccessPoints = new ArrayList<>(mInternalAccessPoints);
598  
599              ArrayList<AccessPoint> accessPoints = new ArrayList<>();
600  
601              final List<NetworkKey> scoresToRequest = new ArrayList<>();
602  
603              for (Map.Entry<String, List<ScanResult>> entry : scanResultsByApKey.entrySet()) {
604                  WifiConfiguration passpointConfig = null;
605                  for (ScanResult result : entry.getValue()) {
606                      NetworkKey key = NetworkKey.createFromScanResult(result);
607                      if (key != null && !mRequestedScores.contains(key)) {
608                          scoresToRequest.add(key);
609                      }
610                      if (passpointConfig == null && result.isPasspointNetwork()) {
611                          try {
612                              passpointConfig = mWifiManager.getMatchingWifiConfig(result);
613                          } catch (UnsupportedOperationException e) {
614                              // Passpoint not supported on the device.
615                          }
616                      }
617                  }
618                  //将scanresult包装成AccessPoint
619                  AccessPoint accessPoint =
620                          getCachedOrCreate(entry.getValue(), cachedAccessPoints);
621                  if (mLastInfo != null && mLastNetworkInfo != null) {
622                      accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
623                  }
624  
625                  // Update the matching config if there is one, to populate saved network info
626                  accessPoint.update(configsByKey.get(entry.getKey()));
627  
628                  // For passpoint network
629                  if (passpointConfig != null) {
630                      accessPoint.update(passpointConfig);
631                  }
632  
633                  accessPoints.add(accessPoint);
634              }
                //将accessPoints更新到mInternalAccessPoints中
674  
675              mInternalAccessPoints.clear();
676              mInternalAccessPoints.addAll(accessPoints);
677          }
678          //通知APP获取accessPoints
679          conditionallyNotifyListeners();
680      }
1003      private void conditionallyNotifyListeners() {
1004          if (mStaleScanResults) {
1005              return;
1006          }
1007          //通过WifiTracker.WifiListener接口回调给WifiSettings
1008          mListener.onAccessPointsChanged();
1009      }

updateAccessPoints函数主要是更新扫描结果的缓存并将扫描结果包装成AccessPoint接着通过WifiTracker.WifiListener的onAccessPointsChanged接口将扫描完成消息通知给了WifiSettings

/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java
636      @Override
637      public void onAccessPointsChanged() {
638          Log.d(TAG, "onAccessPointsChanged (WifiTracker) callback initiated");
639          updateAccessPointsDelayed();
640      }
646      private void updateAccessPointsDelayed() {
647          // Safeguard from some delayed event handling
648          if (getActivity() != null && !mIsRestricted && mWifiManager.isWifiEnabled()) {
649              final View view = getView();
650              final Handler handler = view.getHandler();
651              if (handler != null && handler.hasCallbacks(mUpdateAccessPointsRunnable)) {
652                  return;
653              }
                 //扫描进度条显示
654              setProgressBarVisible(true);
655              view.postDelayed(mUpdateAccessPointsRunnable, 300 /* delay milliseconds */);
656          }
657      }
115      private final Runnable mUpdateAccessPointsRunnable = () -> {
             //更新UI
116          updateAccessPointPreferences();
117      };

到这里WiFi的扫描结果就显示在了设置页面了

5.9 ScanRequestProxyScanListener的回调时机

首先看ScanRequestProxyScanListener注册到哪里去了,在4.3小节startScan的过程中我们知道ScanRequestProxy的startScan会调用WifiScanner.startScan并传入一个ScanRequestProxyScanListener对象,接下来的流程我们主要关注ScanRequestProxyScanListener的是如何回调的

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
355      public boolean startScan(int callingUid, String packageName) {
             ...
             //继续调用WifiScanner.startScan 并传进去一个ScanRequestProxyScanListener用来接受回调信息
391          mWifiScanner.startScan(settings, new ScanRequestProxyScanListener(), workSource);
392          mIsScanProcessingComplete = false;
393          return true;
394      }
/frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
837      public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
838          Preconditions.checkNotNull(listener, "listener cannot be null");
             //这里将listener加入了mListenerMap
839          int key = addListener(listener);
840          if (key == INVALID_KEY) return;
841          validateChannel();
842          Bundle scanParams = new Bundle();
843          scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
844          scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
845          mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
846      }

上面可以知道WifiScanner的startScan调用了addListener这里的addListener主要就是将ScanRequestProxyScanListener加入到了mListenerMap,而且listener也没有往下传递,那么这个listener就是在WifiScanner回调的,那么到底在哪里回调呢?我们在WifiScanner这个类中搜索onResults可以知道它会在ServiceHandler在接收到 CMD_SCAN_RESULT消息后调用ScanRequestProxyScanListener的onResults回调。那么会在哪里发送这个消息呢?这个答案需要知道这个hander被传递到哪里了。我们首先看wifiScanner的构造函数,

frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
1190      public WifiScanner(Context context, IWifiScanner service, Looper looper) {
1191          mContext = context;
1192          mService = service;
1193  
1194          Messenger messenger = null;
1195          try {
1196              messenger = mService.getMessenger();
1197          } catch (RemoteException e) {
1198              throw e.rethrowFromSystemServer();
1199          }
1200  
1201          if (messenger == null) {
1202              throw new IllegalStateException("getMessenger() returned null!  This is invalid.");
1203          }
1204  
1205          mAsyncChannel = new AsyncChannel();
1206  
1207          mInternalHandler = new ServiceHandler(looper);
1208          mAsyncChannel.connectSync(mContext, mInternalHandler, messenger);
1209          // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
1210          // synchronously, which causes WifiScanningService to receive the wrong replyTo value.
1211          mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
1212      }

这里构造了一个ServiceHandlerbong传递到了AsyncChannel接着AsyncChannel发送了一条CMD_CHANNEL_FULL_CONNECTION消息。

5.10 AsyncChannel

首先我们先看一下ServiceHandler怎么样了

/frameworks/base/core/java/com/android/internal/util/AsyncChannel.java
258      public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
259          if (DBG) log("halfConnectSync srcHandler to the dstMessenger  E");
260  
261          // We are connected
262          connected(srcContext, srcHandler, dstMessenger);
263  
264          if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
265          return STATUS_SUCCESSFUL;
266      }
395      public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
396          if (DBG) log("connected srcHandler to the dstMessenger  E");
397  
398          // Initialize source fields
399          mSrcContext = srcContext;
400          mSrcHandler = srcHandler;
401          mSrcMessenger = new Messenger(mSrcHandler);
402  
403          // Initialize destination fields
404          mDstMessenger = dstMessenger;
405          if (DBG) log("connected srcHandler to the dstMessenger X");
406      }

到这里我们知道了ServiceHandler被包装成了一个mSrcMessenger,而mDstMessenger则是WifiScanningServiceImpl中的ClientHandler

接着我们看AsyncChannel的sendMessage发送CMD_CHANNEL_FULL_CONNECTION

/frameworks/base/core/java/com/android/internal/util/AsyncChannel.java
478      public void sendMessage(Message msg) {
479          msg.replyTo = mSrcMessenger;
480          try {
481              mDstMessenger.send(msg);
482          } catch (RemoteException e) {
483              replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
484          }
485      }

无论msg携带多少参数那么最终都会调用到上面这个sendMessage中,在上面的代码中我们看到最终msg都会将mSrcMessenger(ServiceHandler的包装)赋值给Message的成员变量replyTo 发送给WifiScanningServiceImpl。

WifiScanningServiceImpl的ClientHandler处理CMD_CHANNEL_FULL_CONNECTION。

133      private class ClientHandler extends WifiHandler {
134  
135          ClientHandler(String tag, Looper looper) {
136              super(tag, looper);
137          }
138  
139          @Override
140          public void handleMessage(Message msg) {
141              super.handleMessage(msg);
142              switch (msg.what) {
143                  case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                       //msg.replyTo 指的就是mSrcMessenger (WiFiScanner的ServiceHandler的包装)
144                      if (msg.replyTo == null) {
145                          logw("msg.replyTo is null");
146                          return;
147                      }
148                      ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
149                      if (client != null) {
150                          logw("duplicate client connection: " + msg.sendingUid + ", messenger="
151                                  + msg.replyTo);
152                          client.mChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
153                                  AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
154                          return;
155                      }
156                      //这里建立了从WifiScanningServiceImpl到WifiScanner的通道
157                      AsyncChannel ac = mFrameworkFacade.makeWifiAsyncChannel(TAG);
158                      ac.connected(mContext, this, msg.replyTo);
159                      //从WifiScanner传来的ServiceHandler又被包装成了ExternalClientInfo放到了mClients这个map
160                      client = new ExternalClientInfo(msg.sendingUid, msg.replyTo, ac);
161                      client.register();
162                      //这里是WifiScanningServiceImpl向WiFiScanner发送了CMD_CHANNEL_FULLY_CONNECTED消息
163                      ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
164                              AsyncChannel.STATUS_SUCCESSFUL);
165                      localLog("client connected: " + client);
166                      return;
167                  }

这里的ClientHandler会创建一条从WifiScanningServiceImpl到WifiScanner的AsyncChannel通道,并将传过来的WiFiScanner的ServiceHandler和这条通道一起包装成一个ExternalClientInfo放到了mClients这个以ServiceHandler为key,以ExternalClientInfo为value的Map中,后面想回复消息给WifiScanner就可以通过ExternalClientInfo的成员变量mChannel拿到 AsyncChannel通道来回复消息了。

现在WifiScanningServiceImpl和WiFiScanner也有通信的手段了,那么发送一个CMD_SCAN_RESULT给WiFiScanner那就也是可以实现的了。在WifiScanningServiceImpl中搜索CMD_SCAN_RESULT可以看到只有在下面这个函数中才会出现

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
955          void reportScanResults(ScanData results) {
956              if (results != null && results.getResults() != null) {
957                  if (results.getResults().length > 0) {
958                      mWifiMetrics.incrementNonEmptyScanResultCount();
959                  } else {
960                      mWifiMetrics.incrementEmptyScanResultCount();
961                  }
962              }
963              ScanData[] allResults = new ScanData[] {results};
                 //这边通过for循环去除mActiveScans中的RequestInfo调用reportEvent发送CMD_SCAN_RESULT消息
964              for (RequestInfo<ScanSettings> entry : mActiveScans) {
965                  ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings(
966                          mChannelHelper, allResults, entry.settings, -1);
967                  WifiScanner.ParcelableScanData parcelableResultsToDeliver =
968                          new WifiScanner.ParcelableScanData(resultsToDeliver);
969                  logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
970                          describeForLog(resultsToDeliver));
                     //上报扫描数据给上层
971                  entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver);
972                  // make sure the handler is removed
973                  entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null);
974              }
975  
976              WifiScanner.ParcelableScanData parcelableAllResults =
977                      new WifiScanner.ParcelableScanData(allResults);
978              for (RequestInfo<Void> entry : mSingleScanListeners) {
979                  logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
980                          describeForLog(allResults));
981                  entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults);
982              }
983  
984              if (results.isAllChannelsScanned()) {
985                  mCachedScanResults.clear();
986                  mCachedScanResults.addAll(Arrays.asList(results.getResults()));
987              }
988          }

reportScanResults会通过for循环取出mActiveScans中的RequestInfo调用reportEvent发送CMD_SCAN_RESULT消息这里的mActiveScans是在哪里入的呢?我们在4.4小节介绍WifiScanningServiceImpl处理扫描流程时知道扫描请求会在WifiSingleScanStateMachine的DriverStartedState中处理,这时调用 mPendingScans.addRequest添加一个RequestInfo到mPendingScans中去,但是在下面调用tryToStartNewScan时,调用了mScannerImpl.startSingleScan后还会进行一次list的交换,交换了mPendingScans和mActiveScans,我们添加的RequestInfo现在是在mActiveScans中。另外在调用mScannerImpl.startSingleScan时也将WifiSingleScanStateMachine作为一个WifiNative.ScanEventHandler接口传给了WificondScannerImpl,扫描的状态就会通过这个接口回调给WifiSingleScanStateMachine。

我们这里主要分两条线继续分析,第一条向上上报状态,第二条是如何接收底层的扫描状态。

5.11 向上层上报状态

上面我们知道了reportScanResults会调用RequestInfo.reportEvent发送CMD_SCAN_RESULT消息,并携带扫描数据parcelableResultsToDeliver

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java$RequestInfo<T>
368          void reportEvent(int what, int arg1, Object obj) {
369              clientInfo.reportEvent(what, arg1, handlerId, obj);
370          }

这里的clientInfo就是在上面添加RequestInfo给mPendingScans(交换后成了mActiveScans)时从mClients中根据 传过来的ServiceHandler为key查找的ExternalClientInfo所以会调用到ExternalClientInfo的reportEvent

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java$ExternalClientInfo
1925          public void reportEvent(int what, int arg1, int arg2, Object obj) {
1926              if (!mDisconnected) {
1927                  mChannel.sendMessage(what, arg1, arg2, obj);
1928              }
1929          }

这里的mChannel就是我们上面说的建立WifiScanningServiceImpl和WifiScanner的AsyncChannel通道。

5.12 从下层接收状态

在5.9小节的最后我们说到向上上报状态是从WifiScanningServiceImpl的reportScanResults上报的,那么底层是如何调用到reportScanResults呢?在WifiScanningServiceImpl.java的WifiSingleScanStateMachine中搜索这个函数(注意区分入参)可以看到是ScanningState接收到CMD_SCAN_RESULTS_AVAILABLE消息时会调用reportScanResults

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java$WifiSingleScanStateMachine$ ScanningState 
695              @Override
696              public boolean processMessage(Message msg) {
697                  switch (msg.what) {
698                      case CMD_SCAN_RESULTS_AVAILABLE:
699                          mWifiMetrics.incrementScanReturnEntry(
700                                  WifiMetricsProto.WifiLog.SCAN_SUCCESS,
701                                  mActiveScans.size());
702                          reportScanResults(mScannerImpl.getLatestSingleScanResults());
703                          mActiveScans.clear();
704                          transitionTo(mIdleState);
705                          return HANDLED;
706                      case CMD_FULL_SCAN_RESULTS:
707                          reportFullScanResult((ScanResult) msg.obj, /* bucketsScanned */ msg.arg2);
708                          return HANDLED;
709                      case CMD_SCAN_FAILED:
710                          mWifiMetrics.incrementScanReturnEntry(
711                                  WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mActiveScans.size());
712                          sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED,
713                                  "Scan failed");
714                          transitionTo(mIdleState);
715                          return HANDLED;
716                      default:
717                          return NOT_HANDLED;
718                  }
719              }
720          }

这个状态是上面4.5小节 在tryToStartNewScan函数中交换mActiveScans和mPendingScans后切换到了ScanningState。接着就变成了CMD_SCAN_RESULTS_AVAILABLE这条消息是谁发出来的,接着在WifiSingleScanStateMachine中搜索发现是onScanStatus接收到WIFI_SCAN_RESULTS_AVAILABLE或者WIFI_SCAN_THRESHOLD_NUM_SCANS或者WIFI_SCAN_THRESHOLD_PERCENT都会发送这个CMD_SCAN_RESULTS_AVAILABLE消息。onScanStatus是WifiNative.ScanEventHandler的接口而在上面4.5

小节tryToStartNewScan函数中调用mScannerImpl.startSingleScan(settings, this)把WifiSingleScanStateMachine当作WifiNative.ScanEventHandler接口传递给了mScannerImpl。所以onScanStatus是mScannerImpl回调上来的,mScannerImpl是一个WifiScannerImpl对象,从上面4.5小知道startSingleScan最终都会调用到WificondScannerImpl的startSingleScan中我们的WifiSingleScanStateMachine则是作为WifiNative.ScanEventHandler被保存在了 mLastScanSettings中,接着搜索onScanStatus可以看到只有两个地方会回调,一个是reportScanFailure一个是pollLatestScanData

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
296      private void reportScanFailure() {
297          synchronized (mSettingsLock) {
298              if (mLastScanSettings != null) {
299                  if (mLastScanSettings.singleScanEventHandler != null) {
300                      mLastScanSettings.singleScanEventHandler
301                              .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
302                  }
303                  mLastScanSettings = null;
304              }
305          }
306      }
363      private void pollLatestScanData() {
          ....
390  
391              if (mLastScanSettings.singleScanEventHandler != null) {
392                  if (mLastScanSettings.reportSingleScanFullResults) {
393                      for (ScanResult scanResult : singleScanResults) {
394                          // ignore buckets scanned since there is only one bucket for a single scan
395                          mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult,
396                                  /* bucketsScanned */ 0);
397                      }
398                  }
399                  Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
400                  mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, 0,
401                          isAllChannelsScanned(mLastScanSettings.singleScanFreqs),
402                          singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
403                  mLastScanSettings.singleScanEventHandler
404                          .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
405              }
406  
407              mLastScanSettings = null;
408          }
409      }

而只有在pollLatestScanData中是通知扫描结果,而pollLatestScanData我们已经在上面的5.1小节OnScanResultReady中调用的。到这里我们的扫描结果就通知到了上层。

5.13 小结

这里我们梳理一下整个流程,

1.当我们打开WiFi时会在启动hal和supplicant后会在WificondControl的setupInterfaceForClientMode函数中调用 wificondScanner.subscribeScanEvents注册一个ScanEventHandler给wificond进程的scanner_impl。

2,接着走扫描流程,在调用到ScanRequestProxy的startScan后会传入一个ScanRequestProxyScanListener接收底层状态,接着startScan一路调用至wificond进程的scanner_impl中通过socket发送消息并接收回复,并将回复通过第一步注册的ScanEventHandler回调给了WificondControl。

3.WificondControl接收到 OnScanResultReady后调用 mWifiMonitor.broadcastScanResultEvent将消息传递给了WificondScannerImpl,WificondScannerImpl接收到消息后调用pollLatestScanData将扫描结果从wificond进程的scanner_impl获取到,接着通过WifiNative.ScanEventHandler接口回调给了WifiSingleScanStateMachine。

4.WifiSingleScanStateMachine接收到回调后通过AsyncChannel将消息发送给了WifiScanner,接着WifiScanner在通过ScanRequestProxyScanListener接口回调到ScanRequestProxy。ScanRequestProxy接收到结果后发送SCAN_RESULTS_AVAILABLE_ACTION广播通知WifiTracker,WiFiTracker则从WiFiManager中获取扫描结果后更新缓存,并将扫描结果包装成accessPoints,最终通过WifiTracker.WifiListener接口回调给WiFiSettings。WiFisetting更新UI。

六、WiFi的连接过程

我们在设置界面连接WiFi的过程一般都是点击一个连接,然后弹出一个对话框去输入密码,接着点击连接这一系列过程。当我们点击需要连接的WiFi的时候就会执行WifiSettings的onPreferenceTreeClick

6.1 onPreferenceTreeClick

/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java 
518      @Override
519      public boolean onPreferenceTreeClick(Preference preference) {
520          // If the preference has a fragment set, open that
521          if (preference.getFragment() != null) {
522              preference.setOnPreferenceClickListener(null);
523              return super.onPreferenceTreeClick(preference);
524          }
525  
526          if (preference instanceof LongPressAccessPointPreference) {
527              mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
528              if (mSelectedAccessPoint == null) {
529                  return false;
530              }
531              if (mSelectedAccessPoint.isActive()) {
532                  return super.onPreferenceTreeClick(preference);
533              }
534              /**
535               * Bypass dialog and connect to unsecured networks, or previously connected saved
536               * networks, or Passpoint provided networks.
537               */
538              WifiConfiguration config = mSelectedAccessPoint.getConfig();
                 //如果当前的WiFi没有密码直接连接
539              if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
540                  mSelectedAccessPoint.generateOpenNetworkConfig();
541                  connect(mSelectedAccessPoint.getConfig(), mSelectedAccessPoint.isSaved());
542              } else if (mSelectedAccessPoint.isSaved() && config != null
543                      && config.getNetworkSelectionStatus() != null
544                      && config.getNetworkSelectionStatus().getHasEverConnected()) {
                     //WiFi已经保存过,直接连接
545                  connect(config, true /* isSavedNetwork */);
546              } else if (mSelectedAccessPoint.isPasspoint()) {
547                  // Access point provided by an installed Passpoint provider, connect using
548                  // the associated config.
                     //设备有相应的密码证书,直接连接
549                  connect(config, true /* isSavedNetwork */);
550              } else {
                     //弹出对话框要求输入密码
551                  showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
552              }
553          } else if (preference == mAddPreference) {
554              onAddNetworkPressed();
555          } else {
556              return super.onPreferenceTreeClick(preference);
557          }
558          return true;
559      }
561      private void showDialog(AccessPoint accessPoint, int dialogMode) {
562          if (accessPoint != null) {
563              WifiConfiguration config = accessPoint.getConfig();
564              if (WifiUtils.isNetworkLockedDown(getActivity(), config) && accessPoint.isActive()) {
565                  RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
566                          RestrictedLockUtils.getDeviceOwner(getActivity()));
567                  return;
568              }
569          }
570  
571          if (mDialog != null) {
572              removeDialog(WIFI_DIALOG_ID);
573              mDialog = null;
574          }
575  
576          // Save the access point and edit mode
577          mDlgAccessPoint = accessPoint;
578          mDialogMode = dialogMode;
579  
580          showDialog(WIFI_DIALOG_ID);
581      }

showDialog最终会调用到onCreateDialog来创建一个对话框

/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java
583      @Override
584      public Dialog onCreateDialog(int dialogId) {
585          switch (dialogId) {
586              case WIFI_DIALOG_ID:
587                  if (mDlgAccessPoint == null && mAccessPointSavedState == null) {
588                      // add new network
589                      mDialog = WifiDialog
590                              .createFullscreen(getActivity(), this, mDlgAccessPoint, mDialogMode);
591                  } else {
592                      // modify network
593                      if (mDlgAccessPoint == null) {
594                          // restore AP from save state
595                          mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
596                          // Reset the saved access point data
597                          mAccessPointSavedState = null;
598                      }
599                      mDialog = WifiDialog
600                              .createModal(getActivity(), this, mDlgAccessPoint, mDialogMode);
601                  }
602  
603                  mSelectedAccessPoint = mDlgAccessPoint;
604                  return mDialog;

创建对话框调用的是WifiDialog.createModal,我们的WiFi的信息保存在mDlgAccessPoint中,传给WifiDialog后保存在mAccessPoint中当输入密码后点击连接时则调用到了WifiDialog的onClick

/packages/apps/Settings/src/com/android/settings/wifi/WifiDialog.java
114      @Override
115      public void onClick(DialogInterface dialogInterface, int id) {
116          if (mListener != null) {
117              switch (id) {
118                  case BUTTON_SUBMIT:
                         //开始连接WiFi,这里的mListener指的是WiFiSettings对象
119                      mListener.onSubmit(this);
120                      break;
131      }
/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java    
1013      @Override
1014      public void onSubmit(WifiDialog dialog) {
1015          if (mDialog != null) {
1016              submit(mDialog.getController());
1017          }
1018      }
1020      /* package */ void submit(WifiConfigController configController) {
1021  
1022          final WifiConfiguration config = configController.getConfig();
1023  
1024          if (config == null) {
1025              if (mSelectedAccessPoint != null
1026                      && mSelectedAccessPoint.isSaved()) {
1027                  connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
1028              }
1029          } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
1030              mWifiManager.save(config, mSaveListener);
1031          } else {
                  //把当前的WiFi信息保存起来
1032              mWifiManager.save(config, mSaveListener);
1033              if (mSelectedAccessPoint != null) { // Not an "Add network"
                      //开始连接
1034                  connect(config, false /* isSavedNetwork */);
1035              }
1036          }
1037  
1038          mWifiTracker.resumeScanning();
1039      }
1066      protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
1067          // Log subtype if configuration is a saved network.
1068          mMetricsFeatureProvider.action(getVisibilityLogger(), MetricsEvent.ACTION_WIFI_CONNECT,
1069                  isSavedNetwork);
1070          mWifiManager.connect(config, mConnectListener);
1071          mClickedConnect = true;
1072      }

可以看到连接WiFi的流程主要分两步:1.将WiFi信息保存2.调用WifiManager.connect开始连接

6.2 WifiManager.save

在调用WifiManager.save时会传入一个ActionListener来接受事件的回调

3160      public void save(WifiConfiguration config, ActionListener listener) {
3161          if (config == null) throw new IllegalArgumentException("config cannot be null");
              //发送消息SAVE_NETWORK给WifiSerivceimpl中的ClientHander
3162          getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
3163      }

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java$ClientHandler
264          public void handleMessage(Message msg) {
                     ...
317                  case WifiManager.SAVE_NETWORK: {
318                      if (checkChangePermissionAndReplyIfNotAuthorized(
319                              msg, WifiManager.SAVE_NETWORK_FAILED)) {
320                          WifiConfiguration config = (WifiConfiguration) msg.obj;
321                          int networkId = msg.arg1;
322                          Slog.d(TAG, "SAVE"
323                                  + " nid=" + Integer.toString(networkId)
324                                  + " config=" + config
325                                  + " uid=" + msg.sendingUid
326                                  + " name="
327                                  + mContext.getPackageManager().getNameForUid(msg.sendingUid));
328                          if (config != null) {
329                              /* Command is forwarded to state machine */
                                 //将消息转发给了WifiStateMachine
330                              mWifiStateMachine.sendMessage(Message.obtain(msg));
331                          } else {
332                              Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
333                              replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
334                                      WifiManager.INVALID_ARGS);
335                          }
336                      }
337                      break;
338                  }

getChannel获取的是AsyncChannel,在5.10小节也是用过这种通道,这里发送的消息会由WifiServiceImpl的ClientHandler处理。而ClientHandler又将消息发送给了WifiStateMachine状态机。

6.3 WifiStateMachine

在继续往下追代码之前,我们先看一下WifiStateMachine都有哪些状态,如下:

WifiStateMachine.png

可以看到初始状态是DefaultState那么SAVE_NETWORK的消息是那个状态处理的呢?这里我们需要先回到上面4.1小节,在开启扫描时会调用到ClientModeManager的状态机ClientModeStateMachine的StartedState的onUpChanged函数,

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java$ClientModeStateMachine$StartedState
251              private void onUpChanged(boolean isUp) {
252                  if (isUp == mIfaceIsUp) {
253                      return;  // no change
254                  }
255                  mIfaceIsUp = isUp;
                     //这里up代表打开,down代表关闭 所以走if分支
256                  if (isUp) {
257                      Log.d(TAG, "Wifi is ready to use for client mode");
                         //发送WIFI_SCAN_AVAILABLE的广播放入EXTRA_SCAN_AVAILABLE的是WIFI_STATE_ENABLED
258                      sendScanAvailableBroadcast(true);
                         //调用WifiStateMachine.setOperationalMode改变WifiStateMachine的状态
259                      mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE,
260                                                           mClientInterfaceName);
                         //更新WIFI的状态从ENABLING到ENABLED
261                      updateWifiState(WifiManager.WIFI_STATE_ENABLED,
262                                      WifiManager.WIFI_STATE_ENABLING);
263                  } else {
264                      if (mWifiStateMachine.isConnectedMacRandomizationEnabled()) {
265                          // Handle the error case where our underlying interface went down if we
266                          // do not have mac randomization enabled (b/72459123).
267                          return;
268                      }
269                      // if the interface goes down we should exit and go back to idle state.
270                      Log.d(TAG, "interface down!");
271                      updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
272                                      WifiManager.WIFI_STATE_ENABLED);
273                      mStateMachine.sendMessage(CMD_INTERFACE_DOWN);
274                  }
275              }

上面函数中有调用WifiStateMachine.setOperationalMode设置操作模式并传了一个1进去。

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
1543      public void setOperationalMode(int mode, String ifaceName) {
1544          if (mVerboseLoggingEnabled) {
1545              log("setting operational mode to " + String.valueOf(mode) + " for iface: " + ifaceName);
1546          }
1547          mModeChange = true;
              //这里mode传递的是WifiStateMachine.CONNECT_MODE 当前的ifaceName 为wlan0
1548          if (mode != CONNECT_MODE) {
1549              // we are disabling client mode...   need to exit connect mode now
1550              transitionTo(mDefaultState);
1551          } else {
1552              // do a quick sanity check on the iface name, make sure it isn't null
1553              if (ifaceName != null) {
1554                  mInterfaceName = ifaceName;
                      //切换状态到DisconnectedState
1555                  transitionTo(mDisconnectedState);
1556              } else {
1557                  Log.e(TAG, "supposed to enter connect mode, but iface is null -> DefaultState");
1558                  transitionTo(mDefaultState);
1559              }
1560          }
1561          // use the CMD_SET_OPERATIONAL_MODE to force the transitions before other messages are
1562          // handled.
1563          sendMessageAtFrontOfQueue(CMD_SET_OPERATIONAL_MODE);
1564      }

根据上面的代码可以知道最终切换到了DisconnectedState,所以我们的SAVE_NETWORK消息就是DisconnectedState去处理的。但是搜索发现DisconnectedState并没有对SAVE_NETWORK消息的相关处理,所以会被移交给它的父State ConnectModeState去处理。处理代码如下:

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java$ConnectModeState
4447                  case WifiManager.SAVE_NETWORK:
                          //保存网络
4448                      result = saveNetworkConfigAndSendReply(message);
4449                      netId = result.getNetworkId();
4450                      if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
4451                          if (result.hasCredentialChanged()) {
4452                              config = (WifiConfiguration) message.obj;
4453                              // The network credentials changed and we're connected to this network,
4454                              // start a new connection with the updated credentials. 
4455                              logi("SAVE_NETWORK credential changed for config=" + config.configKey()
4456                                      + ", Reconnecting.");
                                  //开始连接网络
4457                              startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
4458                          } else {
4459                              ...
4482                      }
4483                      break;
6219      private NetworkUpdateResult saveNetworkConfigAndSendReply(Message message) {
6220          WifiConfiguration config = (WifiConfiguration) message.obj;
6221          if (config == null) {
6222              loge("SAVE_NETWORK with null configuration "
6223                      + mSupplicantStateTracker.getSupplicantStateName()
6224                      + " my state " + getCurrentState().getName());
6225              messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6226              replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
6227              return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
6228          }
              //调用WifiConfigManager.addOrUpdateNetwork去保存网络到WifiConfigManager中的mConfiguredNetworks
6229          NetworkUpdateResult result =
6230                  mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
6231          if (!result.isSuccess()) {
6232              loge("SAVE_NETWORK adding/updating config=" + config + " failed");
6233              messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6234              replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
6235              return result;
6236          }
6237          if (!mWifiConfigManager.enableNetwork(
6238                  result.getNetworkId(), false, message.sendingUid)) {
6239              loge("SAVE_NETWORK enabling config=" + config + " failed");
6240              messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6241              replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
6242              return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
6243          }
              //发送WIFI_CREDENTIAL_SAVED发广播
6244          broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
6245          replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
6246          return result;
6247      }

ConnectModeState对于SAVE_NETWORK消息的处理包括了保存网络和连接网络,保存网络主要是调用WifiConfigManager.addOrUpdateNetwork将网络保存到到WifiConfigManager中的mConfiguredNetworks中,连接网络则是调用startConnectToNetwork发送CMD_START_CONNECT开始连接网络。

6.3 startConnectToNetwork

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java 
6126      public void startConnectToNetwork(int networkId, int uid, String bssid) {
6127          sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
6128      }

startConnectToNetwork主要是发送CMD_START_CONNECT消息,由于上面的过程并未切换WifiStateMachine的状态,所以这里仍然是DisconnectedState,但是DisconnectedState无法处理CMD_START_CONNECT消息,所以会转发给ConnectModeState去处理。

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java$ConnectModeState
4322                  case CMD_START_CONNECT:
4323                      mIsFilsConnection = false;
4324                      /* connect command coming from auto-join */
4325                      netId = message.arg1;
4326                      int uid = message.arg2;
4327                      bssid = (String) message.obj;
4328  
4329                      synchronized (mWifiReqCountLock) {
4330                          if (!hasConnectionRequests()) {
4331                              if (mNetworkAgent == null) {
4332                                  loge("CMD_START_CONNECT but no requests and not connected,"
4333                                          + " bailing");
4334                                  break;
4335                              } else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4336                                  loge("CMD_START_CONNECT but no requests and connected, but app "
4337                                          + "does not have sufficient permissions, bailing");
4338                                  break;
4339                              }
4340                          }
4341                      }
4342  
4343                      config = mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);
4344                      logd("CMD_START_CONNECT sup state "
4345                              + mSupplicantStateTracker.getSupplicantStateName()
4346                              + " my state " + getCurrentState().getName()
4347                              + " nid=" + Integer.toString(netId)
4348                              + " roam=" + Boolean.toString(mIsAutoRoaming));
4349                      if (config == null) {
4350                          loge("CMD_START_CONNECT and no config, bail out...");
4351                          break;
4352                      }
4353                      mTargetNetworkId = netId;
4354                      setTargetBssid(config, bssid);
4355  
4356                      if (mEnableConnectedMacRandomization.get()) {
4357                          configureRandomizedMacAddress(config);
4358                      }
4359                      //获取当前WIFI的mac地址
4360                      String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName);
4361                      mWifiInfo.setMacAddress(currentMacAddress);
4362                      Log.i(TAG, "Connecting with " + currentMacAddress + " as the mac address");
4363  
4364                      if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256) ||
4365                           config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA384)) {
4366                          /*
4367                           * Config object is required in Fils state to issue
4368                           * conenction to supplicant, hence saving in global
4369                           * variable.
4370                           */
4371                          mFilsConfig = config;
4372                          transitionTo(mFilsState);
4373                          break;
4374                      }
4375                      reportConnectionAttemptStart(config, mTargetRoamBSSID,
4376                              WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
                          //调用WifiNative.connectToNetwork连接网络
4377                      if (mWifiNative.connectToNetwork(mInterfaceName, config)) {
4378                          mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);
4379                          lastConnectAttemptTimestamp = mClock.getWallClockMillis();
4380                          targetWificonfiguration = config;
4381                          mIsAutoRoaming = false;
4382                          if (getCurrentState() != mDisconnectedState) {
4383                              transitionTo(mDisconnectingState);
4384                          }
4385                      } else {
4386                          loge("CMD_START_CONNECT Failed to start connection to network " + config);
4387                          reportConnectionAttemptEnd(
4388                                  WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
4389                                  WifiMetricsProto.ConnectionEvent.HLF_NONE);
4390                          replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
4391                                  WifiManager.ERROR);
4392                          break;
4393                      }
4394                      break;

WifiStateMachine对于CMD_START_CONNECT消息的处理主要是两步,1.获取mac地址2.调用WifiNative.connectToNetwork连接网络

6.4 WifiNative.getMacAddress

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
1559      public String getMacAddress(@NonNull String ifaceName) {
1560          return mSupplicantStaIfaceHal.getMacAddress(ifaceName);
1561      }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java 
1940      public String getMacAddress(@NonNull String ifaceName) {
1941          synchronized (mLock) {
1942              final String methodStr = "getMacAddress";
1943              ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
1944              if (iface == null) return null;
1945              Mutable<String> gotMac = new Mutable<>();
1946              try {
1947                  iface.getMacAddress((SupplicantStatus status,
1948                          byte[/* 6 */] macAddr) -> {
1949                      if (checkStatusAndLogFailure(status, methodStr)) {
1950                          gotMac.value = NativeUtil.macAddressFromByteArray(macAddr);
1951                      }
1952                  });
1953              } catch (RemoteException e) {
1954                  handleRemoteException(e, methodStr);
1955              }
1956              return gotMac.value;
1957          }
1958      }

WifiNative的getMacAddress则是调用SupplicantStaIfaceHal的getMacAddress通过ISupplicantStaIface接口将请求转发给了wpa_supplicant进程中。最终调用到了

/external/wpa_supplicant_8/wpa_supplicant/hidl/1.1/sta_iface.cpp
43  StaIface::getMacAddressInternal()
744  {
745  	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
746  	std::vector<char> cmd(
747  	    kGetMacAddress, kGetMacAddress + sizeof(kGetMacAddress));
748  	char driver_cmd_reply_buf[4096] = {};
        //向wpa_supplicant 下发kGetMacAddress的命令并将结果存储在driver_cmd_reply_buf中
749  	int ret = wpa_drv_driver_cmd(
750  	    wpa_s, cmd.data(), driver_cmd_reply_buf,
751  	    sizeof(driver_cmd_reply_buf));
752  	// Reply is of the format: "Macaddr = XX:XX:XX:XX:XX:XX"
753  	std::string reply_str = driver_cmd_reply_buf;
754  	if (ret < 0 || reply_str.empty() ||
755  	    reply_str.find("=") == std::string::npos) {
756  		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
757  	}
758  	// Remove all whitespace first and then split using the delimiter "=".
759  	reply_str.erase(
760  	    remove_if(reply_str.begin(), reply_str.end(), isspace),
761  	    reply_str.end());
762  	std::string mac_addr_str =
763  	    reply_str.substr(reply_str.find("=") + 1, reply_str.size());
764  	std::array<uint8_t, 6> mac_addr;
765  	if (hwaddr_aton(mac_addr_str.c_str(), mac_addr.data())) {
766  		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
767  	}
768  	return {{SupplicantStatusCode::SUCCESS, ""}, mac_addr};
769  }

6.5 WifiNative.connectToNetwork

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java 
2016      public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
2017          // Abort ongoing scan before connect() to unblock connection request.
              //中止任何正在进行的扫描以免阻塞连接请求
2018          mWificondControl.abortScan(ifaceName);
2019          return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
2020      }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
932       */
933      public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
934          synchronized (mLock) {
935              boolean isAscii = WifiGbk.isAllAscii(WifiGbk.getSsidBytes(config.SSID, "UTF-8")); // wifigbk++
936              logd("connectToNetwork " + config.configKey() + " isAscii=" + isAscii);
937              WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
938              if (WifiConfigurationUtil.isSameNetwork(config, currentConfig) && isAscii) {
939                  String networkSelectionBSSID = config.getNetworkSelectionStatus()
940                          .getNetworkSelectionBSSID();
941                  String networkSelectionBSSIDCurrent =
942                          currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID();
943                  if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
944                      logd("Network is already saved, will not trigger remove and add operation.");
945                  } else {
946                      logd("Network is already saved, but need to update BSSID.");
947                      if (!setCurrentNetworkBssid(
948                              ifaceName,
949                              config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
950                          loge("Failed to set current network BSSID.");
951                          return false;
952                      }
953                      mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
954                  }
955              } else {
956                  mCurrentNetworkRemoteHandles.remove(ifaceName);
957                  mCurrentNetworkLocalConfigs.remove(ifaceName);
958                  if (!removeAllNetworks(ifaceName)) {
959                      loge("Failed to remove existing networks");
960                      return false;
961                  }
962                 /**
963                  * Handle connection to saved FILS network when wifi is
964                  * restarted with altered driver configuration.
965                  */
966                  if (!getCapabilities(ifaceName, "key_mgmt").contains("FILS-SHA256"))
967                      config.allowedKeyManagement.clear(WifiConfiguration.KeyMgmt.FILS_SHA256);
968  
969                  if (!getCapabilities(ifaceName, "key_mgmt").contains("FILS-SHA384"))
970                      config.allowedKeyManagement.clear(WifiConfiguration.KeyMgmt.FILS_SHA384);
971                  //在wpa_supplicant中保存提供的configuration
972                  Pair<SupplicantStaNetworkHal, WifiConfiguration> pair =
973                          addNetworkAndSaveConfig(ifaceName, config);
974                  if (pair == null) {
975                      loge("Failed to add/save network configuration: " + config.configKey());
976                      return false;
977                  }
978                  mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
979                  mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
980              }
981              getCapabilities(ifaceName, "key_mgmt");
982              SupplicantStaNetworkHal networkHandle =
983                      checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
                 //开始连接网络
984              if (networkHandle == null || !networkHandle.select()) {
985                  loge("Failed to select network configuration: " + config.configKey());
986                  return false;
987              }
988              return true;
989          }
990      }

WifiNative的connectToNetwork从注释上看做了6件事儿:

(1)中止任何正在进行的扫描以免阻塞连接请求

(2)移除wpa_supplicant里的所有现有网络(这会隐式触发断开连接)

(3)在wpa_supplicant里添加一个新的网络

(4)在wpa_supplicant中保存提供的configuration

(5)在wpa_supplicant中选择新的网络

(6)触发wpa_supplicant 的重新连接命令

最终触发连接网络的是SupplicantStaNetworkHal的select函数去连接网络

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java 
2588      /**
2589       * Trigger a connection to this network.
2590       *
2591       * @return true if it succeeds, false otherwise.
2592       */
2593      public boolean select() {
2594          synchronized (mLock) {
2595              final String methodStr = "select";
2596              if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false;
2597              try {
2598                  SupplicantStatus status =  mISupplicantStaNetwork.select();
2599                  return checkStatusAndLogFailure(status, methodStr);
2600              } catch (RemoteException e) {
2601                  handleRemoteException(e, methodStr);
2602                  return false;
2603              }
2604          }
2605      }

SupplicantStaNetworkHal的select通过hwbinder ISupplicantStaNetwork 跨进程调用到wpa_supplicant进程中

/external/wpa_supplicant_8/wpa_supplicant/hidl/1.0/sta_network.cpp 
584  Return<void> StaNetwork::select(select_cb _hidl_cb)
585  {
586  	return validateAndCall(
587  	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
588  	    &StaNetwork::selectInternal, _hidl_cb);
589  }
1485  SupplicantStatus StaNetwork::selectInternal()
1486  {
1487  	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
1488  	if (wpa_ssid->disabled == 2) {
1489  		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
1490  	}
1491  	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
1492  	wpa_s->scan_min_time.sec = 0;
1493  	wpa_s->scan_min_time.usec = 0;
        //将请求交给了wpa_supplicant去处理
1494  	wpa_supplicant_select_network(wpa_s, wpa_ssid);
1495  	return {SupplicantStatusCode::SUCCESS, ""};
1496  }

后面就是wpa_supplicant的工作了,这里我们不讨论wpa_supplicant。

七、Wifi连接AP后显示IP地址流程

AP连接的过程中wpa_supplicant会上报连接状态到SupplicantStaIfaceHal,状态的回调是通过SupplicantStaIfaceHalCallback接口的onVendorStateChanged

其中底层状态和上层的状态转换如下:

//Supplicant 和WiFi的状态对应关系
/frameworks/base/wifi/java/android/net/wifi/WifiInfo.java
53      static {
54          stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED);
55          stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED);
56          stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE);
57          stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING);
58          stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING);
59          stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING);
60          stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING);
61          stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING);
62          stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING);
63          stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR);
64          stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED);
65          stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE);
66          stateMap.put(SupplicantState.INVALID, DetailedState.FAILED);
67      }

//网络详细状态和上层UI状态的对应关系
/frameworks/base/core/java/android/net/NetworkInfo.java
101      static {
102          stateMap.put(DetailedState.IDLE, State.DISCONNECTED);
103          stateMap.put(DetailedState.SCANNING, State.DISCONNECTED);
104          stateMap.put(DetailedState.CONNECTING, State.CONNECTING);
105          stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING);
106          stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING);
107          stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING);
108          stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING);
109          stateMap.put(DetailedState.CONNECTED, State.CONNECTED);
110          stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED);
111          stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
112          stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
113          stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
114          stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
115      }
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java$SupplicantStaIfaceHalCallback
2763          public void onVendorStateChanged(int newState, byte[/* 6 */] bssid, int id,
2764                                     ArrayList<Byte> ssid, boolean filsHlpSent) {
2765              synchronized (mLock) {
2766                  logCallback("onVendorStateChanged");
2767                  SupplicantState newSupplicantState = supplicantHidlStateToFrameworkState(newState);
2768                  WifiSsid wifiSsid = // wifigbk++
2769                          WifiGbk.createWifiSsidFromByteArray(NativeUtil.byteArrayFromArrayList(ssid));
2770                  String bssidStr = NativeUtil.macAddressFromByteArray(bssid);
2771                  mSupplicantStaIfacecallback.updateStateIsFourway(
2772                          (newState == ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE));
2773                  if (newSupplicantState == SupplicantState.COMPLETED) {
2774                      if (filsHlpSent == false) {
                              //当连接过程完成时发送NETWORK_CONNECTION_EVENT消息
2775                          mWifiMonitor.broadcastNetworkConnectionEvent(
2776                                  mIfaceName, getCurrentNetworkId(mIfaceName), bssidStr);
2777                      } else {
2778                          mWifiMonitor.broadcastFilsNetworkConnectionEvent(
2779                                  mIfaceName, getCurrentNetworkId(mIfaceName), bssidStr);
2780                      }
2781                  }
                      //当wpa_supplicant底层状态改变时发送SUPPLICANT_STATE_CHANGE_EVENT消息
2782                  mWifiMonitor.broadcastSupplicantStateChangeEvent(
2783                          mIfaceName, getCurrentNetworkId(mIfaceName), wifiSsid, bssidStr, newSupplicantState);
2784              }
2785          }

7.1 WifiMonitor.broadcastSupplicantStateChangeEvent

在接收到wpa_supplicant上报的状态后会调用WifiMonitor通过broadcastSupplicantStateChangeEvent发送SUPPLICANT_STATE_CHANGE_EVENT给WifiStateMachine,在6.3小节我们知道在连接AP时WifiStateMachine的状态是 DisconnectedState ,所以这条消息是在DisconnectedState 中处理的。

 /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java 
     
5865                  case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5866                      StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
5867                      if (mVerboseLoggingEnabled) {
5868                          logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state
5869                                  + " -> state= "
5870                                  + WifiInfo.getDetailedStateOf(stateChangeResult.state));
5871                      }
                          //调用setNetworkDetailedState将状态保存
5872                      setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
5873                      /* ConnectModeState does the rest of the handling */
5874                      ret = NOT_HANDLED;
5875                      break;
777      private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
2778          boolean hidden = false;
2779  
2780          if (mIsAutoRoaming) {
2781              // There is generally a confusion in the system about colluding
2782              // WiFi Layer 2 state (as reported by supplicant) and the Network state
2783              // which leads to multiple confusion.
2784              //
2785              // If link is roaming, we already have an IP address
2786              // as well we were connected and are doing L2 cycles of
2787              // reconnecting or renewing IP address to check that we still have it
2788              // This L2 link flapping should ne be reflected into the Network state
2789              // which is the state of the WiFi Network visible to Layer 3 and applications
2790              // Note that once roaming is completed, we will
2791              // set the Network state to where it should be, or leave it as unchanged
2792              //
2793              hidden = true;
2794          }
2795          if (mVerboseLoggingEnabled) {
2796              log("setDetailed state, old ="
2797                      + mNetworkInfo.getDetailedState() + " and new state=" + state
2798                      + " hidden=" + hidden);
2799          }
2800          if (hidden == true) {
2801              return false;
2802          }
2803          //
2804          if (state != mNetworkInfo.getDetailedState()) {
                  //保存网络信息
2805              mNetworkInfo.setDetailedState(state, null, null);
2806              if (mNetworkAgent != null) {
                      //向ConnectivityService发送EVENT_NETWORK_INFO_CHANGED消息
2807                  mNetworkAgent.sendNetworkInfo(mNetworkInfo);
2808              }
                  //发送NETWORK_STATE_CHANGED_ACTION的广播
2809              sendNetworkStateChangeBroadcast(null);
2810              return true;
2811          }
2812          return false;
2813      }

7.2 WifiMonitor.broadcastNetworkConnectionEvent

当连接完成时底层上报COMPLETED状态,这时WifiMonitor会调用broadcastNetworkConnectionEvent发送NETWORK_CONNECTION_EVENT消息通知WifiStateMachine连接已经建立,接着还会再次发送SUPPLICANT_STATE_CHANGE_EVENT消息。

由于SUPPLICANT_STATE_CHANGE_EVENT消息不会改变WifiStateMachine的状态,所以NETWORK_CONNECTION_EVENT仍然是在DisconnectedState 中处理的,但是DisconnectedState没有对NETWORK_CONNECTION_EVENT的处理,所以这时会传递给它的父State ConnectModeState处理,其处理如下:

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java$ConnectModeState 
4511                  case WifiMonitor.NETWORK_CONNECTION_EVENT:
4512                      if (mVerboseLoggingEnabled) log("Network connection established");
4513                          ...
                              //发送NETWORK_STATE_CHANGED_ACTION广播
4553                          sendNetworkStateChangeBroadcast(mLastBssid);
4554                          mIpReachabilityMonitorActive = true;
                              //切换到ObtainingIpState
4555                          transitionTo(mObtainingIpState);
4556                      } else {
4557                          logw("Connected to unknown networkId " + mLastNetworkId
4558                                  + ", disconnecting...");
4559                          sendMessage(CMD_DISCONNECT);
4560                      }
4561                      break;

可以看到ConnectModeState对于NETWORK_CONNECTION_EVENT的消息只是切换到ObtainingIpState中,在这时ObtainingIpState和其父State L2ConnectedState的enter函数都会调用。现在我们先分别看这两个State的enter函数都做了什么,首先执行的是父State L2ConnectedState的enter

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java$L2ConnectedState
5001          public void enter() {
5002              mRssiPollToken++;
5003              if (mEnableRssiPolling) {
5004                  sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
5005              }
5006              if (mNetworkAgent != null) {
5007                  loge("Have NetworkAgent when entering L2Connected");
5008                  setNetworkDetailedState(DetailedState.DISCONNECTED);
5009              }
                  //将上层wifi的状态设置成CONNECTING
5010              setNetworkDetailedState(DetailedState.CONNECTING);
5011  
5012              final NetworkCapabilities nc;
5013              if (mWifiInfo != null && !mWifiInfo.getSSID().equals(WifiSsid.NONE)) {
5014                  nc = new NetworkCapabilities(mNetworkCapabilitiesFilter);
5015                  nc.setSSID(mWifiInfo.getSSID());
5016              } else {
5017                  nc = mNetworkCapabilitiesFilter;
5018              }
                  //创建WifiNetworkAgent  这个信息可以使用dumpsys connectivity来查看
5019              mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
5020                      "WifiNetworkAgent", mNetworkInfo, nc, mLinkProperties, 60, mNetworkMisc);
5021  
5022              // We must clear the config BSSID, as the wifi chipset may decide to roam
5023              // from this point on and having the BSSID specified in the network block would
5024              // cause the roam to faile and the device to disconnect
5025              clearTargetBssid("L2ConnectedState");
5026              mCountryCode.setReadyForChange(false);
5027              mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
5028          }

L2ConnectedState的enter函数主要是将上层的WIFI的状态设置成了CONNECTING并且创建了WifiNetworkAgent 接着调用ObtainingIpState的enter函数。

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
5264      class ObtainingIpState extends State {
5265          @Override
5266          public void enter() {
5267              final WifiConfiguration currentConfig = getCurrentWifiConfiguration();
5268              final boolean isUsingStaticIp =
5269                      (currentConfig.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
5270              if (mVerboseLoggingEnabled) {
5271                  final String key = currentConfig.configKey();
5272                  log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
5273                          + " " + key + " "
5274                          + " roam=" + mIsAutoRoaming
5275                          + " static=" + isUsingStaticIp);
5276              }
5277              //设置状态为OBTAINING_IPADDR并发送广播NETWORK_STATE_CHANGED_ACTION
5278              // Send event to CM & network change broadcast
5279              setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
5280  
5281              // We must clear the config BSSID, as the wifi chipset may decide to roam
5282              // from this point on and having the BSSID specified in the network block would
5283              // cause the roam to fail and the device to disconnect.
                  //清除bssid
                  //我们必须清除配置BSSID,因为wifi芯片组可能决定从此时开始漫游,在网络块中指定BSSID将导致漫游失败和设备断开连接。
5284              clearTargetBssid("ObtainingIpAddress");
5285  
5286              // Reset power save mode after association.
5287              // Kernel does not forward power save request to driver if power
5288              // save state of that interface is same as requested state in
5289              // cfg80211. This happens when driver’s power save state not
5290              // synchronized with cfg80211 power save state.
5291              // By resetting power save state resolves issues of cfg80211
5292              // ignoring enable power save request sent in ObtainingIpState.
5293              mWifiNative.setPowerSave(mInterfaceName, false);
5294  
5295              // Stop IpClient in case we're switching from DHCP to static
5296              // configuration or vice versa.
5297              //
5298              // TODO: Only ever enter this state the first time we connect to a
5299              // network, never on switching between static configuration and
5300              // DHCP. When we transition from static configuration to DHCP in
5301              // particular, we must tell ConnectivityService that we're
5302              // disconnected, because DHCP might take a long time during which
5303              // connectivity APIs such as getActiveNetworkInfo should not return
5304              // CONNECTED.
5305              if (!mIsFilsConnection) {
5306                  stopIpClient();
5307              }
5308              //设置http代理
5309              mIpClient.setHttpProxy(currentConfig.getHttpProxy());
5310              if (!TextUtils.isEmpty(mTcpBufferSizes)) {
5311                  mIpClient.setTcpBufferSizes(mTcpBufferSizes);
5312              }
5313              final IpClient.ProvisioningConfiguration prov;
5314  
5315              if (mIsFilsConnection && mIsIpClientStarted) {
5316                  setPowerSaveForFilsDhcp();
5317              } else if (!isUsingStaticIp) {
                      //动态IP配置
5318                  prov = IpClient.buildProvisioningConfiguration()
5319                              .withPreDhcpAction()
5320                              .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
5321                              .withNetwork(getCurrentNetwork())
5322                              .withDisplayName(currentConfig.SSID)
5323                              .withRandomMacAddress()
5324                              .build();
    				  //启动新的IpClient获取IP
5325                  mIpClient.startProvisioning(prov);
5326                  mIsIpClientStarted = true;
5327              } else {
                      //静态IP配置
5328                  StaticIpConfiguration staticIpConfig = currentConfig.getStaticIpConfiguration();
5329                  prov = IpClient.buildProvisioningConfiguration()
5330                              .withStaticConfiguration(staticIpConfig)
5331                              .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
5332                              .withNetwork(getCurrentNetwork())
5333                              .withDisplayName(currentConfig.SSID)
5334                              .build();
5335                  mIpClient.startProvisioning(prov);
5336                  mIsIpClientStarted = true;
5337              }
5338              // Get Link layer stats so as we get fresh tx packet counters
5339              getWifiLinkLayerStats();
5340              mIsFilsConnection = false;
5341          }

这里执行更新系统的State,清掉bssid以避免其影响到漫游导致断链,停掉当前IpClient,启动新的IpClient获取IP。最后回调IpClient.Callback.onProvisioningSuccess接口。接口如下:

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
1055          @Override
1056          public void onProvisioningSuccess(LinkProperties newLp) {
1057              mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL);
1058              sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
1059              sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
1060          }

接收到配置成功的消息后会发送两条消息,一条是CMD_UPDATE_LINKPROPERTIES 用来更新连接信息,一条是CMD_IP_CONFIGURATION_SUCCESSFUL。

CMD_UPDATE_LINKPROPERTIES 消息是DefaultState处理的主要是调用updateLinkProperties

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
2628      private void updateLinkProperties(LinkProperties newLp) {
2629          if (mVerboseLoggingEnabled) {
2630              log("Link configuration changed for netId: " + mLastNetworkId
2631                      + " old: " + mLinkProperties + " new: " + newLp);
2632          }
2633          // We own this instance of LinkProperties because IpClient passes us a copy.
2634          mLinkProperties = newLp;
2635          if (mNetworkAgent != null) {
                  //将连接信息更新到NetworkAgent中
2636              mNetworkAgent.sendLinkProperties(mLinkProperties);
2637          }
2638  
2639          if (getNetworkDetailedState() == DetailedState.CONNECTED) {
2640              // If anything has changed and we're already connected, send out a notification.
2641              // TODO: Update all callers to use NetworkCallbacks and delete this.
                  //如果当前已经是连上的状态,那么发送LINK_CONFIGURATION_CHANGED_ACTION广播
2642              sendLinkConfigurationChangedBroadcast();
2643          }
2644  
2645          if (mVerboseLoggingEnabled) {
2646              StringBuilder sb = new StringBuilder();
2647              sb.append("updateLinkProperties nid: " + mLastNetworkId);
2648              sb.append(" state: " + getNetworkDetailedState());
2649  
2650              if (mLinkProperties != null) {
2651                  sb.append(" ");
2652                  sb.append(getLinkPropertiesSummary(mLinkProperties));
2653              }
2654              logd(sb.toString());
2655          }
2656      }
2657  

CMD_IP_CONFIGURATION_SUCCESSFUL消息则是L2ConnectedState接收处理的

/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java$L2ConnectedState
5087                  case CMD_IP_CONFIGURATION_SUCCESSFUL:
5088                      handleSuccessfulIpConfiguration();
5089                      reportConnectionAttemptEnd(
5090                              WifiMetrics.ConnectionEvent.FAILURE_NONE,
5091                              WifiMetricsProto.ConnectionEvent.HLF_NONE);
5092                      if (getCurrentWifiConfiguration() == null) {
5093                          // The current config may have been removed while we were connecting,
5094                          // trigger a disconnect to clear up state.
5095                          mWifiNative.disconnect(mInterfaceName);
5096                          transitionTo(mDisconnectingState);
5097                      } else {
5098                          sendConnectedState();
5099                          transitionTo(mConnectedState);
5100                      }
5101                      break;

可以看到这里正常是走else分支调用sendConnectedState并切换到ConnectedState

5390      private void sendConnectedState() {
5391          // If this network was explicitly selected by the user, evaluate whether to call
5392          // explicitlySelected() so the system can treat it appropriately.
5393          WifiConfiguration config = getCurrentWifiConfiguration();
5394          if (shouldEvaluateWhetherToSendExplicitlySelected(config)) {
5395              boolean prompt =
5396                      mWifiPermissionsUtil.checkNetworkSettingsPermission(config.lastConnectUid);
5397              if (mVerboseLoggingEnabled) {
5398                  log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
5399              }
5400              if (prompt) {
5401                  // Selected by the user via Settings or QuickSettings. If this network has Internet
5402                  // access, switch to it. Otherwise, switch to it only if the user confirms that they
5403                  // really want to switch, or has already confirmed and selected "Don't ask again".
5404                  if (mVerboseLoggingEnabled) {
5405                      log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
5406                  }
5407                  if (mNetworkAgent != null) {
5408                      mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
5409                  }
5410              }
5411          }
5412  
5413          setNetworkDetailedState(DetailedState.CONNECTED);
5414          sendNetworkStateChangeBroadcast(mLastBssid);
5415      }

sendConnectedState主要是将网络状态设置为CONNECTED并发送NETWORK_STATE_CHANGED_ACTION广播

当我们连接上WiFi后点击进去会看到一个网络详情页面如下:

WiFi_网络详情.png

上面这个页面的加载是下面这个函数的调用启动的

/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java
913      private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) {
914          new SubSettingLauncher(getContext())
915                  .setTitle(R.string.pref_title_network_details)
916                  .setDestination(WifiNetworkDetailsFragment.class.getName())
917                  .setArguments(pref.getExtras())
918                  .setSourceMetricsCategory(getMetricsCategory())
919                  .launch();
920      }

最终启动了一个WifiNetworkDetailsFragment,在其中布局文件是/packages/apps/Settings/res/xml/wifi_network_details_fragment.xml

其中内容的更新则是在 WifiDetailPreferenceController中更新的

   private void updateIpLayerInfo() {
436          mButtonsPref.setButton2Visible(canSignIntoNetwork());
437          mButtonsPref.setVisible(canSignIntoNetwork() || canForgetNetwork());
438  
439          if (mNetwork == null || mLinkProperties == null) {
440              mIpAddressPref.setVisible(false);
441              mSubnetPref.setVisible(false);
442              mGatewayPref.setVisible(false);
443              mDnsPref.setVisible(false);
444              mIpv6Category.setVisible(false);
445              return;
446          }
447  
448          // Find IPv4 and IPv6 addresses.
449          String ipv4Address = null;
450          String subnet = null;
451          StringJoiner ipv6Addresses = new StringJoiner("\n");
452          //获取ip地址信息
453          for (LinkAddress addr : mLinkProperties.getLinkAddresses()) {
454              if (addr.getAddress() instanceof Inet4Address) {
455                  ipv4Address = addr.getAddress().getHostAddress();
456                  subnet = ipv4PrefixLengthToSubnetMask(addr.getPrefixLength());
457              } else if (addr.getAddress() instanceof Inet6Address) {
458                  ipv6Addresses.add(addr.getAddress().getHostAddress());
459              }
460          }
461  
462          // Find IPv4 default gateway.
463          String gateway = null;
464          for (RouteInfo routeInfo : mLinkProperties.getRoutes()) {
465              if (routeInfo.isIPv4Default() && routeInfo.hasGateway()) {
466                  gateway = routeInfo.getGateway().getHostAddress();
467                  break;
468              }
469          }
470  
471          // Find all (IPv4 and IPv6) DNS addresses.
472          String dnsServers = mLinkProperties.getDnsServers().stream()
473                  .map(InetAddress::getHostAddress)
474                  .collect(Collectors.joining("\n"));
475  
476          // Update UI.
477          updatePreference(mIpAddressPref, ipv4Address);
478          updatePreference(mSubnetPref, subnet);
479          updatePreference(mGatewayPref, gateway);
480          updatePreference(mDnsPref, dnsServers);
481  
482          if (ipv6Addresses.length() > 0) {
483              mIpv6AddressPref.setSummary(
484                      BidiFormatter.getInstance().unicodeWrap(ipv6Addresses.toString()));
485              mIpv6Category.setVisible(true);
486          } else {
487              mIpv6Category.setVisible(false);
488          }
489      }

可以看到IP信息是通过 mConnectivityManager.getLinkProperties(mNetwork);这个函数获取到的而getLinkProperties则是获取NetworkAgentInfo的linkProperties成员函数。而上面StateMachine在接收到CMD_UPDATE_LINKPROPERTIES 消息后会将信息更新到WifiNetworkAgent中

八、WiFi设置更新状态

在7.2小节我们知道当网络状态发生改变时会发送出NETWORK_STATE_CHANGED_ACTION,我们WiFi设置界面的更新也是有这个广播引起的,当WifiTracker接收到这个广播后,就会触发更新流程,下面一起来看一下这个流程。

WifiTracker中的广播如下:

797      final BroadcastReceiver mReceiver = new BroadcastReceiver() {
798          @Override
799          public void onReceive(Context context, Intent intent) {
800              String action = intent.getAction();
801              sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
802  
803              if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
804                  updateWifiState(
805                          intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
806                                  WifiManager.WIFI_STATE_UNKNOWN));
807              } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
808                  mStaleScanResults = false;
809  
810                  fetchScansAndConfigsAndUpdateAccessPoints();
811              } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
812                      || WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
813                  fetchScansAndConfigsAndUpdateAccessPoints();
814              } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
815                  // TODO(sghuman): Refactor these methods so they cannot result in duplicate
816                  // onAccessPointsChanged updates being called from this intent.
817                  NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
818                  updateNetworkInfo(info);
819                  fetchScansAndConfigsAndUpdateAccessPoints();
820              } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
821                  NetworkInfo info =
822                          mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
823                  updateNetworkInfo(info);
824              }
825          }
826      };

其中fetchScansAndConfigsAndUpdateAccessPoints就会触发WiFi设置界面的状态的改变,从这个广播接收者也可以看到当接收到SCAN_RESULTS_AVAILABLE_ACTION、CONFIGURED_NETWORKS_CHANGED_ACTION、LINK_CONFIGURATION_CHANGED_ACTION、NETWORK_STATE_CHANGED_ACTION等广播都会调用到fetchScansAndConfigsAndUpdateAccessPoints函数。

8.1 fetchScansAndConfigsAndUpdateAccessPoints

/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
558      private void fetchScansAndConfigsAndUpdateAccessPoints() {
559          List<ScanResult> newScanResults = mWifiManager.getScanResults();
560  
561          // Filter all unsupported networks from the scan result list
562          final List<ScanResult> filteredScanResults =
563                  filterScanResultsByCapabilities(newScanResults);
564  
565          if (isVerboseLoggingEnabled()) {
566              Log.i(TAG, "Fetched scan results: " + filteredScanResults);
567          }
568  
569          List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
570          updateAccessPoints(filteredScanResults, configs);
571      }

fetchScansAndConfigsAndUpdateAccessPoints会首先通过网络能力过滤一遍扫描结果,接着调用updateAccessPoints更新AccessPoint

updateAccessPoints的流程可以参考5.8小节,在5.8小节的最后会在WifiSettings中调用updateAccessPointPreferences来更新UI,我们重点看一下如何更新UI的。

8.2 updateAccessPointPreferences

/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java 
716      private void updateAccessPointPreferences() {
717          // in case state has changed
718          if (!mWifiManager.isWifiEnabled()) {
719              return;
720          }
721          // AccessPoints are sorted by the WifiTracker
722          final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
723          if (isVerboseLoggingEnabled()) {
724              Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
725          }
726  
727          boolean hasAvailableAccessPoints = false;
728          mAccessPointsPreferenceCategory.removePreference(mStatusMessagePreference);
729          cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);
730          //这里的configureConnectedAccessPointPreferenceCategory会将连接上的Preference重新设置clicklistener 并且设置WiFi的状态
731          int index =
732                  configureConnectedAccessPointPreferenceCategory(accessPoints) ? 1 : 0;
733          int numAccessPoints = accessPoints.size();
734          for (; index < numAccessPoints; index++) {
735              AccessPoint accessPoint = accessPoints.get(index);
736              // Ignore access points that are out of range.
737              if (accessPoint.isReachable()) {
738                  String key = accessPoint.getKey();
739                  hasAvailableAccessPoints = true;
740                  LongPressAccessPointPreference pref =
741                          (LongPressAccessPointPreference) getCachedPreference(key);
742                  if (pref != null) {
743                      pref.setOrder(index);
744                      continue;
745                  }
                     //创建一个新的LongPressAccessPointPreference
746                  LongPressAccessPointPreference preference =
747                          createLongPressAccessPointPreference(accessPoint);
748                  preference.setKey(key);
749                  preference.setOrder(index);
750                  if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
751                          && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                         //如果没有保存并且密码错误再次弹出密码框
752                      if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
753                          onPreferenceTreeClick(preference);
754                          mOpenSsid = null;
755                      }
756                  }
757                  mAccessPointsPreferenceCategory.addPreference(preference);
758                  accessPoint.setListener(WifiSettings.this)
                     //为新加入的accessPoint刷新界面
759                  preference.refresh();
760              }
761          }
762          removeCachedPrefs(mAccessPointsPreferenceCategory);
763          mAddPreference.setOrder(index);
764          mAccessPointsPreferenceCategory.addPreference(mAddPreference);
765          setAdditionalSettingsSummaries();
766  
767          if (!hasAvailableAccessPoints) {
768              setProgressBarVisible(true);
769              Preference pref = new Preference(getPrefContext());
770              pref.setSelectable(false);
771              pref.setSummary(R.string.wifi_empty_list_wifi_on);
772              pref.setOrder(index++);
773              pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
774              mAccessPointsPreferenceCategory.addPreference(pref);
775          } else {
776              // Continuing showing progress bar for an additional delay to overlap with animation
777              getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
778          }
779      }

8.3 configureConnectedAccessPointPreferenceCategory

我们WiFi的状态的设置是在configureConnectedAccessPointPreferenceCategory函数中完成的

799      private boolean configureConnectedAccessPointPreferenceCategory(
800              List<AccessPoint> accessPoints) {
801          if (accessPoints.size() == 0) {
802              removeConnectedAccessPointPreference();
803              return false;
804          }
805  
806          AccessPoint connectedAp = accessPoints.get(0);
807          if (!connectedAp.isActive()) {
808              removeConnectedAccessPointPreference();
809              return false;
810          }
811  
812          // Is the preference category empty?
813          if (mConnectedAccessPointPreferenceCategory.getPreferenceCount() == 0) {
814              addConnectedAccessPointPreference(connectedAp);
815              return true;
816          }
817  
818          // Is the previous currently connected SSID different from the new one?
819          ConnectedAccessPointPreference preference =
820                  (ConnectedAccessPointPreference)
821                          (mConnectedAccessPointPreferenceCategory.getPreference(0));
822          // The AccessPoints need to be the same reference to ensure that updates are reflected
823          // in the UI.
824          if (preference.getAccessPoint() != connectedAp) {
825              removeConnectedAccessPointPreference();
826              addConnectedAccessPointPreference(connectedAp);
827              return true;
828          }
829          //刷新UI的状态
830          // Else same AP is connected, simply refresh the connected access point preference
831          // (first and only access point in this category).
832          preference.refresh();
833          // Update any potential changes to the connected network and ensure that the callback is
834          // registered after an onStop lifecycle event.
835          registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), preference);
836          return true;
837      }

主要是一些设置最后调用ConnectedAccessPointPreference的refresh去刷新UI,而ConnectedAccessPointPreference继承于 AccessPointPreference,

/packages/apps/Settings/src/com/android/settings/wifi/ConnectedAccessPointPreference.java
48      public void refresh() {
            //调用父类的refresh来刷新UI
49          super.refresh();
50  
51          setShowDivider(mIsCaptivePortal);
52          if (mIsCaptivePortal) {
53              setSummary(R.string.wifi_tap_to_sign_in);
54          }
55      }
 /frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java 
245      public void refresh() {
246          setTitle(this, mAccessPoint, mForSavedNetworks);
247          final Context context = getContext();
248          int level = mAccessPoint.getLevel();
249          int wifiSpeed = mAccessPoint.getSpeed();
250          if (level != mLevel || wifiSpeed != mWifiSpeed) {
251              mLevel = level;
252              mWifiSpeed = wifiSpeed;
253              updateIcon(mLevel, context);
254              notifyChanged();
255          }
256  
257          updateBadge(context);
258          //设置WIFI状态
259          setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
260                  : mAccessPoint.getSettingsSummary());
261  
262          mContentDescription = buildContentDescription(getContext(), this /* pref */, mAccessPoint);
263      }

AccessPoint的getSettingsSummary会根据WiFi的不同状态获取不同的提示。至此WiFi设置界面的状态更新就完成了。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值