【Android 11 framework学习之wifi 关闭】

前面几步与wifi开启的一样,从后面不一致的开始分析,关闭的时序图如下:
在这里插入图片描述
从处理 CMD_WIFI_TOGGLED 消息(即开启step5)开始不一致。之前可以参考另一篇文章。

wifi开启之后WifiController状态机为 EnabledState 状态,因此在EnabledState中去处理 CMD_WIFI_TOGGLED 消息。
shouldEnableSta()返回false,消息处理会走入到else中,进入到stopAllClientModeManagers()方法中

/*** com.android.server.wifi.ActiveModeWarden.WifiController.EnabledState.processMessageFiltered ***/

    ...
    case CMD_WIFI_TOGGLED:
    case CMD_SCAN_ALWAYS_MODE_CHANGED:
        if (shouldEnableSta()) {
            if (hasAnyClientModeManager()) {
                switchAllClientModeManagers();
            } else {
                startClientModeManager();
            }
        } else {
            stopAllClientModeManagers();
        }
        break;
    ...

分析:首先会去判断数据库中是否写入开启wifi的值,这里我们是关闭,因此mSettingsStore.isWifiToggleEnabled()返回的false;那再来具体看 checkScanOnlyModeAvailable(),mSettingsStore.isScanAlwaysAvailable()返回的是是否需要一直能够扫描,这个值需要专门调用WifiManager.setScanAlwaysAvailable()将其设置为true,由于一开始一直没有调用设置,所以mSettingsStore.isScanAlwaysAvailable()返回false,因此shouldEnableSta()返回false,消息处理会走入到else中,进入到stopAllClientModeManagers()方法中。

/*** com.android.server.wifi.ActiveModeWarden.WifiController.shouldEnableSta ***/

private boolean shouldEnableSta() {
    return mSettingsStore.isWifiToggleEnabled() || checkScanOnlyModeAvailable();
}

/*** com.android.server.wifi.ActiveModeWarden.checkScanOnlyModeAvailable ***/

private boolean checkScanOnlyModeAvailable() {
    return mWifiPermissionsUtil.isLocationModeEnabled()
            && mSettingsStore.isScanAlwaysAvailable();
}

关闭了所有之前开启的ClientModeManager,进入到ClientModeManager.stop()中

/*** com.android.server.wifi.ActiveModeWarden.stopAllClientModeManagers ***/

private void stopAllClientModeManagers() {
    Log.d(TAG, "Shutting down all client mode managers");
    for (ActiveModeManager manager : mActiveModeManagers) {
        if (!(manager instanceof ClientModeManager)) continue;
        ClientModeManager clientModeManager = (ClientModeManager) manager;
        clientModeManager.stop();
    }
}

由于之前是正常打开,所以接口是起来的mIfaceIsUp为true,会对外发送一个wifi状态广播,由WIFI_STATE_ENABLED变换为WIFI_STATE_DISABLING。随后进入到DeferStopHandler.start()方法中

/*** com.android.server.wifi.ClientModeManager.stop ***/

@Override
public void stop() {
    Log.d(TAG, " currentstate: " + getCurrentStateName());
    mTargetRole = ROLE_UNSPECIFIED;
    if (mIfaceIsUp) {
        updateConnectModeState(WifiManager.WIFI_STATE_DISABLING,
                WifiManager.WIFI_STATE_ENABLED);
    } else {
        updateConnectModeState(WifiManager.WIFI_STATE_DISABLING,
                WifiManager.WIFI_STATE_ENABLING);
    }
    mDeferStopHandler.start(getWifiOffDeferringTimeMs());
}

###step4
这里传入的是一个延时,表示要延迟多久关闭wifi,假设不延时即delayMs==0(延不延时都会调到continueToStopWifi去停止wifi),则会继续进入continueToStopWifi()

/*** com.android.server.wifi.ClientModeManager.DeferStopHandler.start ***/

public void start(int delayMs) {
    ...
    // Most cases don't need delay, check it first to avoid unnecessary work.
    if (delayMs == 0) {
        continueToStopWifi();
        return;
    }
    ...
}

step3中设置的mTargetRole值为ROLE_UNSPECIFIED,因此走到第一个分支中
WifiMetrics这个类主要用于记录wifi框架中的一些性能指标和打印一些日志,没有很实际的流程在内
所以只需关注mStateMachine.quitNow(),这个状态机对象就是 ClientModeStateMachine

/*** com.android.server.wifi.ClientModeManager.DeferStopHandler.continueToStopWifi ***/

private void continueToStopWifi() {
    ...
    if (mTargetRole == ROLE_UNSPECIFIED) {
        Log.d(TAG, "Continue to stop wifi");
        mStateMachine.quitNow();
        mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis);
    } else if (mTargetRole == ROLE_CLIENT_SCAN_ONLY) {
        ...
    } else {
        ...
    }
    ...//注销一些回调操作
}

因为ClientModeStateMachine没有重写父类quitNow()方法,因此进入状态机父类StateMachine.quitNow()中

/*** com.android.internal.util.StateMachine.quitNow ***/

public final void quitNow() {
    // mSmHandler can be null if the state machine is already stopped.
    SmHandler smh = mSmHandler;
    if (smh == null) return;

    smh.quitNow();
}

向状态机内部的SmHandler发送了一个SM_QUIT_CMD消息

/*** com.android.internal.util.StateMachine.SmHandler.quitNow ***/

private final void quitNow() {
    if (mDbg) mSm.log("quitNow:");
    sendMessageAtFrontOfQueue(obtainMessage(SM_QUIT_CMD, mSmHandlerObj));
}

转入到SmHandler消息处理函数中,发送的是SM_QUIT_CMD消息,因此走入第一个分支,调用processMsg

/*** com.android.internal.util.StateMachine.SmHandler.handleMessage ***/

public final void handleMessage(Message msg) {
    if (!mHasQuit) {
        ...
        mMsg = msg;
        /** State that processed the message */
        State msgProcessedState = null;
        if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
            /** Normal path */
            msgProcessedState = processMsg(msg);
        } ...
        performTransitions(msgProcessedState, msg);
        ...
    }
}

退出isQuit(msg)为true,切换状态机为QuittingState

/*** com.android.internal.util.StateMachine.SmHandler.processMsg ***/

private final State processMsg(Message msg) {
    StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
    ...
    if (isQuit(msg)) {
        transitionTo(mQuittingState);
    } else {
        ...
    }
    return (curStateInfo != null) ? curStateInfo.state : null;
}

再看step8中的performTransitions()

/*** com.android.internal.util.StateMachine.SmHandler.performTransitions ***/

private void performTransitions(State msgProcessedState, Message msg) {
    ...
    invokeExitMethods(commonStateInfo);
    ...
    cleanupAfterQuitting();
    ...
}

invokeExitMethods()方法会将切换状态前的所有状态都退出即都会执行exit()方法,之前是处于ConnectModeState状态,所以ConnectModeState和StartedState(其父类状态)的exit()方法都会被执行。

/*** com.android.server.wifi.ClientModeManager.ClientModeStateMachine.ConnectModeState.exit ***/

public void exit() {
    updateConnectModeState(WifiManager.WIFI_STATE_DISABLED,
            WifiManager.WIFI_STATE_DISABLING);
    // Inform sar manager that wifi is being disabled
    mSarManager.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
}
/*** com.android.server.wifi.ClientModeManager.ClientModeStateMachine.StartedState.exit ***/

public void exit() {
    mClientModeImpl.setOperationalMode(ClientModeImpl.DISABLED_MODE, null);
    if (mClientInterfaceName != null) {
        mWifiNative.teardownInterface(mClientInterfaceName);
        mClientInterfaceName = null;
        mIfaceIsUp = false;
    }
    // once we leave started, nothing else to do...  stop the state machine
    mRole = ROLE_UNSPECIFIED;
    mStateMachine.quitNow();
    mModeListener.onStopped();
}

可以看出ConnectModeState的退出方法中对外发送了广播wifi状态由WIFI_STATE_DISABLING变化到WIFI_STATE_DISABLED
然后继续进入StartedState的退出方法,首先是将wifi状态机切到DISABLED_MODE,然后因为mClientInterfaceName为之前打开的wifi的Iface,所以暂时还不为空,进入到WifiNative.teardownInterface()中将开启的Iface关闭,此时wifi其实已经关闭了
后面虽然再一次调用了StateMachine.quitNow(),但其实是在状态机处理消息的队列中再加一个退出消息,所以在前面一次退出执行完之后,这次退出其实是直接就不会执行了,具体可以自行分析StateMachine的源码。执行完invokeExitMethods(),后面会继续进入到step9#cleanupAfterQuitting()中。

/*** com.android.internal.util.StateMachine.SmHandler.cleanupAfterQuitting ***/

private final void cleanupAfterQuitting() {
    if (mSm.mSmThread != null) {
        // If we made the thread then quit looper which stops the thread.
        getLooper().quit();
        mSm.mSmThread = null;
    }
    mSm.mSmHandler = null;
    mSm = null;
    mMsg = null;
    mLogRecords.cleanup();
    mStateStack = null;
    mTempStateStack = null;
    mStateInfo.clear();
    mInitialState = null;
    mDestState = null;
    mDeferredMessages.clear();
    mHasQuit = true;
}

此方法就是将状态机内部的所有关键变量都置为空或者清干净。并且处理消息的Looper也会一并别关闭,后续不会再有任何方法执行了。至此,关闭wifi的流程结束。

参考:
https://blog.csdn.net/qq_39036223/article/details/124164745

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值