一.WifiService的启动WifiService的启动可用如下简单时序图表示:
启动过程的图示画的比较简单,下面就顺着这个思路理一下代码的实现。
在SystemServer.java的 startOtherServices() 方法中,启动了WifiService,代码如下: mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS); mSystemServiceManager.startService(WIFI_SERVICE_CLASS); mSystemServiceManager.startService( "com.android.server.wifi.WifiScanningService"); mSystemServiceManager.startService("com.android.server.wifi.RttService");其中用到的WIFI_P2P_SERVICE_CLASS,WIFI_SERVICE_CLASS两个变量的值如下: private static final String WIFI_SERVICE_CLASS = "com.android.server.wifi.WifiService"; private static final String WIFI_P2P_SERVICE_CLASS = "com.android.server.wifi.p2p.WifiP2pService";以上代码可以看到,SystemServier中启动的Wifi相关的服务有四个,从上往下依次是P2P wifi服务,普通wifi,wifi扫描附近热点的服务以及以太网服务。 - p2p wifi服务主要为Wi-Fi Direct提供相应的服务,Wi-Fi Direct是一种全新的技术,即使在没有传统的Wi-Fi网络或Wi-Fi接入点的环境中,仍然能够在诸如智能手机和数码相机等设备间实现点对点Wi-Fi连接。
- wifi 服务这是我们关注的重点。
下面我们看下wifi服务的启动过程。
@SuppressWarnings("unchecked") public SystemService startService(String className) { final Class<SystemService> serviceClass; try { serviceClass = (Class<SystemService>)Class.forName(className); } catch (ClassNotFoundException ex) { Slog.i(TAG, "Starting " + className); throw new RuntimeException("Failed to create service " + className + ": service class not found, usually indicates that the caller should " + "have called PackageManager.hasSystemFeature() to check whether the " + "feature is available on this device before trying to start the " + "services that implement it", ex); } return startService(serviceClass); }startService方法中通过Class.forName获得一个Class实例,但是这还不是WifiService的实例,然后调用startService进一步处理。这两个startService方法是重载方法,他们的参数类型不同。 public <T extends SystemService> T startService(Class<T> serviceClass) { final String name = serviceClass.getName(); Slog.i(TAG, "Starting " + name); // Create the service. if (!SystemService.class.isAssignableFrom(serviceClass)) { throw new RuntimeException("Failed to create " + name + ": service must extend " + SystemService.class.getName()); } final T service; try { C**tructor<T> c**tructor = serviceClass.getC**tructor(Context.class); service = c**tructor.newInstance(mContext); } catch (InstantiationException ex) { throw new RuntimeException("Failed to create service " + name + ": service could not be instantiated", ex); } catch (IllegalAcces**ception ex) { throw new RuntimeException("Failed to create service " + name + ": service must have a public c**tructor with a Context argument", ex); } catch (NoSuchMethodException ex) { throw new RuntimeException("Failed to create service " + name + ": service must have a public c**tructor with a Context argument", ex); } catch (InvocationTargetException ex) { throw new RuntimeException("Failed to create service " + name + ": service c**tructor threw an exception", ex); } // Register it. mServices.add(service); // Start it. try { service.**tart(); } catch (RuntimeException ex) { throw new RuntimeException("Failed to start service " + name + ": **tart threw an exception", ex); } return service; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
在这个startService方法中,使用 C**tructor c**tructor = serviceClass.getC**tructor(Context.class);
service = c**tructor.newInstance(mContext);构建了一个WifiService的实例,然后使用mServices.add(service);向系统注册WifiService,并调用WifiService的**tart方法。构造WifiService会调用WifiService的构造方法,它的构造方法如下: public WifiService(Context context) { super(context); mImpl = new WifiServiceImpl(context); }wifiService构造函数有新建了一个WifiServiceImpl实例,它才是Wifi管理服务真正的实现者,构造函数调用后不是调用了WifiService的**tart方法吗? @Override public void **tart() { Log.i(TAG, "Registering " + Context.WIFI_SERVICE); publishBinderService(Context.WIFI_SERVICE, mImpl); }在**tart方法中发布了Wifi服务,发布的WifiServiceImpl的实例。发布的过程如下:
1. protected final void publishBinderService(String name, IBinder service) { publishBinderService(name, service, false); }2. protected final void publishBinderService(String name, IBinder service, boolean allowIsolated) { ServiceManager.addService(name, service, allowIsolated); }也就是说还是调用了ServiceManager的addService方法,这里就不再深入了,再深入就有点跑偏了。
通过以上分析,我们知道了真的wifi服务是WifiServiceImpl,它的构造方法如下: public WifiServiceImpl(Context context) { mContext = context; mInterfaceName = SystemProperties.get("wifi.interface", "wlan0"); mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName); mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller); mWifiStateMachine.enableRssiPolling(true); mBatteryStats = BatteryStatsService.getService(); mPowerManager = context.getSystemService(PowerManager.class); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); mUserManager = UserManager.get(mContext); mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine); mSettingsStore = new WifiSettingsStore(mContext); HandlerThread wifiThread = new HandlerThread("WifiService"); wifiThread.start(); mClientHandler = new ClientHandler(wifiThread.getLooper()); mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); mWifiController = new WifiController(mContext, this, wifiThread.getLooper()); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
这里面做的事情还是很多的,主要有以下几点:
1.mInterfaceName 是从系统属性中获取的,它的值一般就是wlan0;
2.mTrafficPoller 这个实例的作用从其类的简介(Polls for traffic stats and notifies the clients )上可以看出他是用来查询流量统计信息比通知给客户端的。
3.mWifiStateMachine 这个实例代表着一个Wifi状态机,它定义了wifi的很多状态,通过消息驱动状态的转变。
4.mBatteryStats ,mPowerManager 用于wifi的电源管理,
5.mNotificationController 处理打开“打开wifi并且可以使用“的通知。
6.wifiThread 它是一个HandlerThread 的实例,HandlerThread 是一个内部有Looper的线程,wifiThread会一直**消息,消息到来以后,通过mClientHandler 的handleMessage来处理消息。
7.WifiStateMachineHandler 用于发送和处理wifi状态机相关的消息。
8.mWifiController 是另一个状态机,它和mWifiStateMachine 不同,mWifiStateMachine 表述wifi具体的状态,比如supplicant启动/关闭状态,driver启动/关闭状态等,mWifiController 则更高一级的控制wifi设备的开关状态,wifi热点的开关状态等。
理解mWifiController 和mWifiStateMachine 对于理解Android wifi框架至关重要。所以接下来,我们就着重分析wifi状态机的工作原理。 二.wifi状态机工作原理我们说mWifiController 是高级别的wifi状态机,因为它管理的状态是wifi开关,wifi热点开关等状态,只有在wifi开关等具体状态下,判断wifi处于启动扫描附近热点状态等才是有意义的。
状态机无非就是一个定义了很多状态的机器,它收到消息后,会根据消息来切换这个机器的状态。mWifiController 的状态构造在它的构造方法中: addState(mDefaultState); addState(mApStaDisabledState, mDefaultState); addState(mStaEnabledState, mDefaultState); addState(mDeviceActiveState, mStaEnabledState); addState(mDeviceInactiveState, mStaEnabledState); addState(mScanOnlyLockHeldState, mDeviceInactiveState); addState(mFullLockHeldState, mDeviceInactiveState); addState(mFullHighPerfLockHeldState, mDeviceInactiveState); addState(mNoLockHeldState, mDeviceInactiveState); addState(mStaDisabledWithScanState, mDefaultState); addState(mApEnabledState, mDefaultState); addState(mEcmState, mDefaultState);结构图如下:
每一个状态机都有一个初始状态: if (isScanningAlwaysAvailable) { setInitialState(mStaDisabledWithScanState); } else { setInitialState(mApStaDisabledState); }mWifiStateMachine 则表述wifi更加细致的状态,它的状态构建也是在构造函数中: addState(mDefaultState); addState(mInitialState, mDefaultState); addState(mSupplicantStartingState, mDefaultState); addState(mSupplicantStartedState, mDefaultState); addState(mDriverStartingState, mSupplicantStartedState); addState(mDriverStartedState, mSupplicantStartedState); addState(mScanModeState, mDriverStartedState); addState(mConnectModeState, mDriverStartedState); addState(mL2ConnectedState, mConnectModeState); addState(mObtainingIpState, mL2ConnectedState); addState(mVerifyingLinkState, mL2ConnectedState); addState(mConnectedState, mL2ConnectedState); addState(mRoamingState, mL2ConnectedState); addState(mDisconnectingState, mConnectModeState); addState(mDisconnectedState, mConnectModeState); addState(mWpsRunningState, mConnectModeState); addState(mWaitForP2pDisableState, mSupplicantStartedState); addState(mDriverStoppingState, mSupplicantStartedState); addState(mDriverStoppedState, mSupplicantStartedState); addState(mSupplicantStoppingState, mDefaultState); addState(mSoftApStartingState, mDefaultState); addState(mSoftApStartedState, mDefaultState); addState(mTetheringState, mSoftApStartedState); addState(mTetheredState, mSoftApStartedState); addState(mUntetheringState, mSoftApStartedState); setInitialState(mInitialState);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
结构图如下:
![]()
并且初始化状态为mInitialState。
以上Android wifi框架中两个重要的状态机,那么状态机的工作机制是怎么样的呢?
以下是状态机工作原理简介:
状态机中的一个状态由State类的实例表示,State实例必须实现processMessage方法用来处理消息。并且可选的实现enter/exit/getName三个方法,enter/exit 等价于类的构造方法和销毁方法,本别用于初始化和清理一个状态。getName方法返回State的名字,默认的实现是返回类名。
当我们创建一个状态机时,需要使用addState方法给状态机添加状态,正如前面所展示的那样。setInitialState用于初始化一个状态机的初始状态。构建好一个状态机以后,我们需要调用start方法启动这个状态机,它就像一个机器,造好以后,加油或者充电,然后发动它,它就进入工作状态了。这个过程会调用初始化状态的enter方法初始化初始状态,如果初始状态由父状态,就会递归调用父状态,知道所有父状态的enter方法被调用。这样才算是完全初始化好了一个状态机,start方法还会时状态机进入已经构造结束阶段,这个时候,当有消息到来时,状态机就可以处理消息了。
处理消息的过程和初始化类似。当消息到来以后,当前状态就会调用processMessage来处理消息,如果当前消息能够处理消息,那么消息处理过程就结束了,此时会根据具体情况选择切换或者不切换状态机的状态。如果当前State不能处理消息,那么就会递交父State的processMessage来处理,父状态如果还不能处理就继续往上递交。如果一个消息从未被处理,unhandledMessage方法会被调用,这是最后处理这个消息的机会了。
如果我们期望停止状态机,可以调用quitNow或者quit方法。
当我们切换状态时,旧State的exit方法会被调用而新State的enter方法会被调用,同时他们父State也会做相同的事情。但是如果两个状态由相同的父状态,那么这个时候他们父状态就没有必要做任何操作了,因为它的状态其实并没有变。
以上就是一个状态机的工作原理的简要概述。我们可以想象,当应用程序需要扫描附近的热点时,如果wifi状态机正处于开启状态,那么上层的操作会导致wifi状态机接收到一个消息,开启的状态对它处理后,发现需要把wifi状态机切换到scan状态,于是开启状态的exit方法被调用,scan状态的enter方法被调用。切换不应该只是wifi状态机状态的切换,这个过程应该会调用底层的代码真正的把wifi的状态切换到对应的状态。切换过去以后wpa_supplicant会返回响应的事件,这又会导致响应的消息被wifi状态机接受,从而又促使wifi状态机状态的切换。 三.wifi框架梳理再分析wifi框架之前,我先把我理解的wifi框架以图的形式展示出来:
android6.0的wifi框架中有两个非常重要的状态机:WifiController和WifiStateMachine,它们一起管理着wifi的各个状态以及状态之间的切换。WifiMonitor负责从wpa_supplicant接收事件,并且和WifiStateMachine交互。它们最终都会调用wifiNative,最终和wpa_supplicant交互。
拍砖要趁早,如果理解的不对,希望指出来。
下面我将会从给wap_supplicant发送命令与接收wpa_supplicant发出来的事件两方面梳理wifi框架的具体实现。 向wpa_supplicant发送命令想象一下在应用程序我们怎么连接wifi:
1打开和关闭wifi
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(true);
2扫描附近热点
startScan();之后,接受WifiManager.SCAN_RESULTS_AVAILABLE_ACTION的广播会触发,在这个广播中调用getScanResults()方法可以获得一个List,它里面的每一个条目就是一个可连接的热点。
wifi.startScan();
results = wifi.getScanResults();
一般我们可能都需要做这两步吧,那么这两步会导致wifi状态机做怎么样的改变呢?
首先,用一张图来概括这个过程,然后大家可以顺着这个图的思路分析代码:
代码的分析过程如下:
首先从setWifiEnabled开始,wifi是一个WifiServiceImpl的客户端,它会通过binder和WifiServiceImpl的实例交互,也就是我么在WifiService中通过addService方法向系统注册的mImpl对象,忘记的可以回头看看前面。 public boolean setWifiEnabled(boolean enabled) { try { return mService.setWifiEnabled(enabled); } catch (RemoteException e) { return false; } }最终调用的的是WifiServiceImpl中的setWifiEnabled方法: public synchronized boolean setWifiEnabled(boolean enable) { enforceChangePermission(); Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); if (DBG) { Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n"); } /* * Caller might not have WRITE_SECURE_SETTINGS, * only CHANGE_WIFI_STATE is enforced */ long ident = Binder.clearCallingIdentity(); try { if (! mSettingsStore.handleWifiToggled(enable)) { // Nothing to do if wifi cannot be toggled return true; } } finally { Binder.restoreCallingIdentity(ident); } mWifiController.sendMessage(CMD_WIFI_TOGGLED); return true; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
这个方法首先要使用mSettingsStore.handleWifiToggled(enable)来判断wifi状态是否可以切换,不能切换就直接返回。如果wifi状态可以切换,那么接下来会使用mWifiController.sendMessage(CMD_WIFI_TOGGLED);来给mWifiController状态佳发送一条消息,我们说过mWifiController状态机控制wifi设备的开关灯状态,由此开来这句话是对的哈。WifiController的sendMessage方法定义如下: /** * Enqueue a message to this state machine. * * Message is ignored if state machine has quit. */ public final void sendMessage(int what) { // mSmHandler can be null if the state machine has quit. SmHandler smh = mSmHandler; if (smh == null) return; smh.sendMessage(obtainMessage(what)); }这里有使用了smh.sendMessage真正的向WifiController状态机的消息队列中发送消息。这时候,因为是使用mSmHandler来发送的消息,所以mSmHandler的handlerMessage方法会被调用: @Override public final void handleMessage(Message msg) { if (!mHasQuit) { if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what); /** Save the current message */ mMsg = msg; /** State that processed the message */ State msgProcessedState = null; if (mIsC**tructionCompleted) { /** Normal path */ msgProcessedState = processMsg(msg); } else if (!mIsC**tructionCompleted && (mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) { /** Initial one time path. */ mIsC**tructionCompleted = true; invokeEnterMethods(0); } else { throw new RuntimeException("StateMachine.handleMessage: " + "The start method not called, received msg: " + msg); } performTransiti**(msgProcessedState, msg); // We need to check if mSm == null here as we could be quitting. if (mDbg && mSm != null) mSm.log("handleMessage: X"); } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
这个方法首先判断状态机是否退出,如果没有退出,就进一步判断状态机是否构建完成,如果构建完成的话,就调用processMsg来处理消息。
下面看看处理消息的过程: private final State processMsg(Message msg) { StateInfo curStateInfo = mStateStack[mStateStackTopIndex]; if (mDbg) { mSm.log("processMsg: " + curStateInfo.state.getName()); } if (isQuit(msg)) { transitionTo(mQuittingState); } else { while (!curStateInfo.state.processMessage(msg)) { /** * Not processed */ curStateInfo = curStateInfo.parentStateInfo; if (curStateInfo == null) { /** * No parents left so it's not handled */ mSm.unhandledMessage(msg); break; } if (mDbg) { mSm.log("processMsg: " + curStateInfo.state.getName()); } } } return (curStateInfo != null) ? curStateInfo.state : null; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
1.首先获得当前的状态。‘
/* Stack used to manage the current hierarchy of states /
private StateInfo mStateStack[];
就是说mStateStack就是保存着当前的状态链。mStateStackTopIndex指向的状当前状态链最顶层的状态,比如说有如下状态链:
m
/\
a b
/\
c d
加入当前状态链是mdb,mStateStackTopIndex指向的就是d状态了。
2.判断是不是退出消息,如果是,就把状态机的状态置为退出状态。
3.调用当前状态的processMessage方法处理消息,如果当前状态没有处理消息,就调用其父状态的processMessage处理消息,依次往上。如果所有状态都没有处理消息,最终unhandledMessage方法就会被调用,这正如我们之前在wifi状态机原理中所说的那样。
4.如果消息被处理了,就返回curStateInfo,否则返回null。
curStateInfo是StateInfo的实例,StateInfo封装了State的状态信息类,这个类用于维护状态机中状态的层次关系。
这个时候,假如我们的状态机的状态为StaEnabledState状态,那么它的processMessage方法就会被调用: public boolean processMessage(Message msg) { switch (msg.what) { case CMD_WIFI_TOGGLED: if (mWifiStateMachine.syncGetWifiState() == 1) { log("wifi start fail before, now start it again"); mWifiStateMachine.setSupplicantRunning(true); } if (! mSettingsStore.isWifiToggleEnabled() || msg.arg1 == WifiManager.WIFI_STATE_DISABLED) { if (mSettingsStore.isScanAlwaysAvailable()) { transitionTo(mStaDisabledWithScanState); } else { transitionTo(mApStaDisabledState); } } break; ...1.当消息为CMD_AIRPLANE_TOGGLED的时候,在这种状态下,会使用mWifiStateMachine.setSupplicantRunning(true);来启动wpa_supplicant服务,这就是为什么上一篇博客 《Android wifi框架分析一:初步认识wpa_supplicant与wifi框架梳理》我们说打开wifi后wpa_supplicant就会启动的原因。然后把状态机切换到响应的状态。
2.WifiStateMachine.setSupplicantRunning方法如下: public void setSupplicantRunning(boolean enable) { if (enable) { sendMessage(CMD_START_SUPPLICANT); } else { sendMessage(CMD_STOP_SUPPLICANT); } }我们看到这个时候逻辑就转到WifiStateMachine中了,这是一个新的状态机,工作原理都是一样的,这里就是发送对应的消息,这会促使WifiStateMachine做相应的操作。
3.transitionTo只是把简单的给mDestState变量赋值: private final void transitionTo(IState destState) { mDestState = (State) destState; if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName()); }我们说过状态机的切换要调用旧状态的exit方法,新状态的enter方法,那么回到handleMessage方法,在processMsg方法调用结束后,performTransiti**方法就会被调用: private void performTransiti**(State msgProcessedState, Message msg) { /** * If transitionTo has been called, exit and then enter * the appropriate states. We loop on this to allow * enter and exit methods to use transitionTo. */ State orgState = mStateStack[mStateStackTopIndex].state; /** * Record whether message needs to be logged before we transition and * and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which * always set msg.obj to the handler. */ boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj != mSmHandlerObj); if (mLogRecords.logOnlyTransiti**()) { /** Record only if there is a transition */ if (mDestState != null) { mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState, orgState, mDestState); } } else if (recordLogMsg) { /** Record message */ mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState, orgState, mDestState); } State destState = mDestState; if (destState != null) { /** * Process the transiti** including transiti** in the enter/exit methods */ while (true) { if (mDbg) mSm.log("handleMessage: new destination call exit/enter"); /** * Determine the states to exit and enter and return the * common ancestor state of the enter/exit states. Then * invoke the exit methods then the enter methods. */ StateInfo comm**tateInfo = setupTempStateStackWithStatesToEnter(destState); invokeExitMethods(comm**tateInfo); int stateStackEnteringIndex = moveTempStateStackToStateStack(); invokeEnterMethods(stateStackEnteringIndex); /** * Since we have transitioned to a new state we need to have * any deferred messages moved to the front of the message queue * so they will be processed before any other messages in the * message queue. */ moveDeferredMessageAtFrontOfQueue(); if (destState != mDestState) { // A new mDestState so continue looping destState = mDestState; } else { // No change in mDestState so we're done break; } } mDestState = null; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
1.首先从mStateStack[mStateStackTopIndex].state获取当前的状态
2.State destState = mDestState;从mDestState中获取目标状态。mDestState不就是我们在transitionTo中设置的目标状态吗?这里就用到了。
3.这里面invokeExitMethods和invokeEnterMethods方法就是调用对应状态的额exit和enter方法的。 至此状态机的操作结束,setWifiEnabled造成的影响终于结束了。 wifi.startScan()
那么 wifi.startScan(); 又做了什么事情呢?
因为我们已经详细分析过setWifiEnabled,这里简单分析:
WifiServiceImpl中的startScan方法被调用: public void startScan(ScanSettings settings, WorkSource workSource) { ... mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++, settings, workSource); }WifiStateMachine.startScan方法被调用: public void startScan(int callingUid, int scanCounter, ScanSettings settings, WorkSource workSource) { Bundle bundle = new Bundle(); bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle); }都是一样的套路,给状态机发消息。
handleMessage方法被调用,和之前一模一样。
然后当前状态的processMessage被调用来处理消息,不能处理就调用其父状态的processMessage来处理,以此类推。
假设我们处于DriverStartedState状态,其processMessage方法如下: @Override public boolean processMessage(Message message) { logStateAndMessage(message, getClass().getSimpleName()); switch(message.what) { case CMD_START_SCAN: handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); break;调用handleScanRequest进一步处理: private void handleScanRequest(int type, Message message) { ... // call wifi native to start the scan if (startScanNative(type, freqs)) { // only count battery c**umption if scan request is accepted noteScanStart(message.arg1, workSource); // a full scan covers everything, clearing scan request buffer if (freqs == null) mBufferedScanMsg.clear(); messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; if (workSource != null) { // External worksource was passed along the scan request, // hence always send a broadcast mSendScanResultsBroadcast = true; } return; } ... }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
可以看到调用startScanNative进一步处理: private boolean startScanNative(int type, String freqs) { if (mWifiNative.scan(type, freqs)) { mIsScanOngoing = true; mIsFullScanOngoing = (freqs == null); lastScanFreqs = freqs; return true; } return false; }调用到mWifiNative.scan,看过上一篇博客的就会知道WifiNative会直接调用jni方法,进一步调用wifi.c中的方法和wpa_supplicant交互。整个wifi的框架就走了一遍。
执行完以后wpa_supplicant还要有事件返回呀,这个事件谁来接收?
|