赞
踩
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
在接着分析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 }
/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。
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。
状态机调用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中。
/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 }
这里的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 }
/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主要调用的是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去执行。
WifiControler继承于StateMachine说明它是一个状态机。它的状态如下:
可以看到初始化的状态是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的消息。
而mModeStateMachine也是一个简单的状态机,如下:
所以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 }
这里将会调用ClientModeManager的start函数向ClientModeStateMachine中发送一条CMD_START消息。这里的ClientModeManager在初始化时创建了一个ClientModeStateMachine,运行在WifiStateMachine这个线程上。ClientModeStateMachine如下:
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来监听来自底层的消息
下面我们分别看如何实现的
/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。
/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
/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地址)并注册扫描事件的监听
/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
/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扫描过程的触发是在上面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
/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()开启扫描。
/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中
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是一个状态机
可以看到初始状态为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发起扫描
/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打开时向WificondControl设置ClientMode,即3.7小节setupInterfaceForClientMode时调用 wificondScanner.subscribeScanEvents注册了扫描事件的监听,当有扫描结果时就会回调ScanEventHandler的OnScanResultReady。
第二处就是发起扫描时 4.3小节ScanRequestProxy的 startScan函数中在调用 mWifiScanner.startScan传入了ScanRequestProxyScanListener,当有扫描结果时会回调到ScanRequestProxyScanListener的onResults。
下面我们分别看一下这两个流程。
/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去获取。
/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中。
/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是如何注册的了。
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了。
/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扫描的代码一般也是监听这个广播,后获取扫描信息。
在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的应用中。
接着我们看一下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.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的扫描结果就显示在了设置页面了
首先看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消息。
首先我们先看一下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。
我们这里主要分两条线继续分析,第一条向上上报状态,第二条是如何接收底层的扫描状态。
上面我们知道了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.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中调用的。到这里我们的扫描结果就通知到了上层。
这里我们梳理一下整个流程,
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的时候就会执行WifiSettings的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开始连接
在调用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状态机。
在继续往下追代码之前,我们先看一下WifiStateMachine都有哪些状态,如下:
可以看到初始状态是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开始连接网络。
/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连接网络
/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 }
/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。
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 }
在接收到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 }
当连接完成时底层上报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后点击进去会看到一个网络详情页面如下:
上面这个页面的加载是下面这个函数的调用启动的
/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中
在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函数。
/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的。
/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 }
我们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设置界面的状态更新就完成了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。