(一百九十二) Android Q 学习WiFi AP的禁用

前言:wifi ap使用过程中会由于各种原因变得不可靠,比如密码错误,认证失败等等,这时候需要禁用该类型的AP使得WiFi不自动连接该AP,优化用户体验

 

1.ClientModeImpl

                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
                    mWifiDiagnostics.captureBugReportData(
                            WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);
                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
                    int disableReason = WifiConfiguration.NetworkSelectionStatus
                            .DISABLED_AUTHENTICATION_FAILURE;
                    reasonCode = message.arg1;
                    // Check if this is a permanent wrong password failure.
                    if (isPermanentWrongPasswordFailure(mTargetNetworkId, reasonCode)) {
                        disableReason = WifiConfiguration.NetworkSelectionStatus
                                .DISABLED_BY_WRONG_PASSWORD;
                        WifiConfiguration targetedNetwork =
                                mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
                        if (targetedNetwork != null) {
                            mWrongPasswordNotifier.onWrongPasswordError(
                                    targetedNetwork.SSID);
                        }
                    } else if (reasonCode == WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE) {
                        int errorCode = message.arg2;
                        handleEapAuthFailure(mTargetNetworkId, errorCode);
                        if (errorCode == WifiNative.EAP_SIM_NOT_SUBSCRIBED) {
                            disableReason = WifiConfiguration.NetworkSelectionStatus
                                .DISABLED_AUTHENTICATION_NO_SUBSCRIPTION;
                        }
                    }
                    mWifiConfigManager.updateNetworkSelectionStatus(
                            mTargetNetworkId, disableReason);
                    mWifiConfigManager.clearRecentFailureReason(mTargetNetworkId);

                    ...
                    break;

大致逻辑是如果监听到底层上报上来的WifiMonitor.AUTHENTICATION_FAILURE_EVENT事件,则再细分判断一下类型

 

1.1 永久的密码错误

    /**
     * Determine if the specified auth failure is considered to be a permanent wrong password
     * failure. The criteria for such failure is when wrong password error is detected
     * and the network had never been connected before.
     *
     * For networks that have previously connected successfully, we consider wrong password
     * failures to be temporary, to be on the conservative side.  Since this might be the
     * case where we are trying to connect to a wrong network (e.g. A network with same SSID
     * but different password).
     */
    private boolean isPermanentWrongPasswordFailure(int networkId, int reasonCode) {
        if (reasonCode != WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD) {
            return false;
        }
        WifiConfiguration network = mWifiConfigManager.getConfiguredNetwork(networkId);
        if (network != null && network.getNetworkSelectionStatus().getHasEverConnected()) {
            return false;
        }
        return true;
    }

注解说的很明白,只有未成功连接过的network 报密码错误才会认为是真正的密码错误

 

1.2 ERROR_AUTH_FAILURE_EAP_FAILURE

 else if (reasonCode == WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE) {
                        int errorCode = message.arg2;
                        handleEapAuthFailure(mTargetNetworkId, errorCode);
                        if (errorCode == WifiNative.EAP_SIM_NOT_SUBSCRIBED) {
                            disableReason = WifiConfiguration.NetworkSelectionStatus
                                .DISABLED_AUTHENTICATION_NO_SUBSCRIPTION;
                        }
                    }

    private void handleEapAuthFailure(int networkId, int errorCode) {
        WifiConfiguration targetedNetwork =
                mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
        if (targetedNetwork != null) {
            switch (targetedNetwork.enterpriseConfig.getEapMethod()) {
                case WifiEnterpriseConfig.Eap.SIM:
                case WifiEnterpriseConfig.Eap.AKA:
                case WifiEnterpriseConfig.Eap.AKA_PRIME:
                    if (errorCode == WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED) {
                        getTelephonyManager()
                                .createForSubscriptionId(
                                        SubscriptionManager.getDefaultDataSubscriptionId())
                                .resetCarrierKeysForImsiEncryption();
                    }
                    break;

                default:
                    // Do Nothing
            }
        }
    }

由于eap-sim aka aka_prime与sim卡有关,所有失败处理看起来是和tele reset相关

 

2. WifiConfigManager

    /**
     * Update a network's status (both internal and public) according to the update reason and
     * its current state.
     *
     * Each network has 2 status:
     * 1. NetworkSelectionStatus: This is internal selection status of the network. This is used
     * for temporarily disabling a network for Network Selector.
     * 2. Status: This is the exposed status for a network. This is mostly set by
     * the public API's {@link WifiManager#enableNetwork(int, boolean)} &
     * {@link WifiManager#disableNetwork(int)}.
     *
     * @param networkId network ID of the network that needs the update.
     * @param reason    reason to update the network.
     * @return true if the input configuration has been updated, false otherwise.
     */
    public boolean updateNetworkSelectionStatus(int networkId, int reason) {
        WifiConfiguration config = getInternalConfiguredNetwork(networkId);
        if (config == null) {
            return false;
        }
        return updateNetworkSelectionStatus(config, reason);
    }

更新WiFi configuration里的状态

    /**
     * Update a network's status (both internal and public) according to the update reason and
     * its current state.
     *
     * @param config network to be updated.
     * @param reason reason code for update.
     * @return true if the input configuration has been updated, false otherwise.
     */
    private boolean updateNetworkSelectionStatus(WifiConfiguration config, int reason) {
        NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
        if (reason != NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) {

            // Do not update SSID blacklist with information if this is the only
            // SSID be observed. By ignoring it we will cause additional failures
            // which will trigger Watchdog.
            if (reason == NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION
                    || reason == NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE
                    || reason == NetworkSelectionStatus.DISABLED_DHCP_FAILURE) {
                if (mWifiInjector.getWifiLastResortWatchdog().shouldIgnoreSsidUpdate()) {
                    if (mVerboseLoggingEnabled) {
                        Log.v(TAG, "Ignore update network selection status "
                                    + "since Watchdog trigger is activated");
                    }
                    return false;
                }
            }

WiFi禁用有例外条件,当该ap是当前WifiConnectivityManager唯一可候选的AP并且该AP之前连接上过,那么就不能disable它,Google估计是基于这是唯一可能连上WiFi的考虑,即使WiFi重启也不disable。

            networkStatus.incrementDisableReasonCounter(reason);
            // For network disable reasons, we should only update the status if we cross the
            // threshold.
            int disableReasonCounter = networkStatus.getDisableReasonCounter(reason);
            int disableReasonThreshold = NETWORK_SELECTION_DISABLE_THRESHOLD[reason];
            if (disableReasonCounter < disableReasonThreshold) {
                if (mVerboseLoggingEnabled) {
                    Log.v(TAG, "Disable counter for network " + config.getPrintableSsid()
                            + " for reason "
                            + NetworkSelectionStatus.getNetworkDisableReasonString(reason) + " is "
                            + networkStatus.getDisableReasonCounter(reason) + " and threshold is "
                            + disableReasonThreshold);
                }
                return true;
            }
        }
        return setNetworkSelectionStatus(config, reason);
    }

增加该configuration相应失败reason的计数,每个reason有个阈值,当达到阈值的时候就disable这个AP

阈值是如下定义

    /**
     * Network Selection disable reason thresholds. These numbers are used to debounce network
     * failures before we disable them.
     * These are indexed using the disable reason constants defined in
     * {@link android.net.wifi.WifiConfiguration.NetworkSelectionStatus}.
     */
    @VisibleForTesting
    public static final int[] NETWORK_SELECTION_DISABLE_THRESHOLD = {
            -1, //  threshold for NETWORK_SELECTION_ENABLE
            1,  //  threshold for DISABLED_BAD_LINK
            5,  //  threshold for DISABLED_ASSOCIATION_REJECTION
            5,  //  threshold for DISABLED_AUTHENTICATION_FAILURE
            5,  //  threshold for DISABLED_DHCP_FAILURE
            5,  //  threshold for DISABLED_DNS_FAILURE
            1,  //  threshold for DISABLED_NO_INTERNET_TEMPORARY
            1,  //  threshold for DISABLED_WPS_START
            6,  //  threshold for DISABLED_TLS_VERSION_MISMATCH
            1,  //  threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS
            1,  //  threshold for DISABLED_NO_INTERNET_PERMANENT
            1,  //  threshold for DISABLED_BY_WIFI_MANAGER
            1,  //  threshold for DISABLED_BY_USER_SWITCH
            1,  //  threshold for DISABLED_BY_WRONG_PASSWORD
            1   //  threshold for DISABLED_AUTHENTICATION_NO_SUBSCRIBED
    };

在打开WiFi详细日志后每个ap的summary里也会显示各个大于0计数的reason。

    /**
     * Sets a network's status (both internal and public) according to the update reason and
     * its current state.
     *
     * This updates the network's {@link WifiConfiguration#mNetworkSelectionStatus} field and the
     * public {@link WifiConfiguration#status} field if the network is either enabled or
     * permanently disabled.
     *
     * @param config network to be updated.
     * @param reason reason code for update.
     * @return true if the input configuration has been updated, false otherwise.
     */
    private boolean setNetworkSelectionStatus(WifiConfiguration config, int reason) {
        NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
        if (reason < 0 || reason >= NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX) {
            Log.e(TAG, "Invalid Network disable reason " + reason);
            return false;
        }
        if (reason == NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) {
            setNetworkSelectionEnabled(config);
            setNetworkStatus(config, WifiConfiguration.Status.ENABLED);
        } else if (reason < NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) {
            setNetworkSelectionTemporarilyDisabled(config, reason);
        } else {
            setNetworkSelectionPermanentlyDisabled(config, reason);
            setNetworkStatus(config, WifiConfiguration.Status.DISABLED);
        }
        localLog("setNetworkSelectionStatus: configKey=" + config.configKey()
                + " networkStatus=" + networkStatus.getNetworkStatusString() + " disableReason="
                + networkStatus.getNetworkDisableReasonString() + " at="
                + createDebugTimeStampString(mClock.getWallClockMillis()));
        saveToStore(false);
        return true;
    }

然后禁用分暂时禁用和永久禁用

2.1 暂时禁用reason列表

        //Quality Network disabled reasons
        /**
         * Default value. Means not disabled
         */
        public static final int NETWORK_SELECTION_ENABLE = 0;
        /**
         * The starting index for network selection disabled reasons
         */
        public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
        /**
         * @deprecated it is not used any more.
         * This network is disabled because higher layer (>2) network is bad
         */
        public static final int DISABLED_BAD_LINK = 1;
        /**
         * This network is disabled because multiple association rejects
         */
        public static final int DISABLED_ASSOCIATION_REJECTION = 2;
        /**
         * This network is disabled because multiple authentication failure
         */
        public static final int DISABLED_AUTHENTICATION_FAILURE = 3;
        /**
         * This network is disabled because multiple DHCP failure
         */
        public static final int DISABLED_DHCP_FAILURE = 4;
        /**
         * This network is disabled because of security network but no credentials
         */
        public static final int DISABLED_DNS_FAILURE = 5;
        /**
         * This network is temporarily disabled because it has no Internet access.
         */
        public static final int DISABLED_NO_INTERNET_TEMPORARY = 6;
        /**
         * This network is disabled because we started WPS
         */
        public static final int DISABLED_WPS_START = 7;

2.2 永久禁用

(注释写的不大对,从代码来看DISABLED_TLS_VERSION_MISMATCH也是永久禁用)

        /**
         * This network is disabled because EAP-TLS failure
         */
        public static final int DISABLED_TLS_VERSION_MISMATCH = 8;
        // Values above are for temporary disablement; values below are for permanent disablement.
       /**
         * This network is disabled due to absence of user credentials
         */
        public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 9;
        /**
         * This network is permanently disabled because it has no Internet access and user does not
         * want to stay connected.
         */
        public static final int DISABLED_NO_INTERNET_PERMANENT = 10;
        /**
         * This network is disabled due to WifiManager disable it explicitly
         */
        public static final int DISABLED_BY_WIFI_MANAGER = 11;
        /**
         * This network is disabled due to user switching
         */
        public static final int DISABLED_DUE_TO_USER_SWITCH = 12;
        /**
         * This network is disabled due to wrong password
         */
        public static final int DISABLED_BY_WRONG_PASSWORD = 13;
        /**
         * This network is disabled because service is not subscribed
         */
        public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 14;
        /**
         * This Maximum disable reason value
         */
        public static final int NETWORK_SELECTION_DISABLED_MAX = 15;

 

 

 

 

你可能感兴趣的:(Wifi)