(九十三) Android O 连接WiFi AP流程梳理续——保存网络

前言: 之前在(五十五)Android O 连接WiFi AP流程梳理 梳理连接流程梳理到SupplicantStaNetworkHal 然后没梳理的下去,现在继续梳理下。

 

之前梳理的时序图

 

1.流程梳理-保存网络

现在重新梳理了下流程发现漏了些细节,完善一下。

1.1 Settings

    /* package */ void submit(WifiConfigController configController) {

        final WifiConfiguration config = configController.getConfig();

        if (config == null) {
            if (mSelectedAccessPoint != null
                    && mSelectedAccessPoint.isSaved()) {
                connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
            }
        } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
            mWifiManager.save(config, mSaveListener);
        } else {
            mWifiManager.save(config, mSaveListener);
            if (mSelectedAccessPoint != null) { // Not an "Add network"
                connect(config, false /* isSavedNetwork */);
            }
        }

        mWifiTracker.resumeScanning();
    }

在第一次连接WiFi的时候,我们一般先输入密码,然后连接,之后的过程是先调用WifiManager保存该网络,可以观察到我们连接过的网络都会在已保存网络里有所显示,之后才是连接网络。而其中的参数WifiConfiguration是从WifiConfigController中获取的,这其实就是将用户输入转换为对象。

    /* package */ WifiConfiguration getConfig() {
        if (mMode == WifiConfigUiBase.MODE_VIEW) {
            return null;
        }

        WifiConfiguration config = new WifiConfiguration();

        if (mAccessPoint == null) {
            config.SSID = AccessPoint.convertToQuotedString(
                    mSsidView.getText().toString());
            // If the user adds a network manually, assume that it is hidden.
            config.hiddenSSID = true;
        } else if (!mAccessPoint.isSaved()) {
            config.SSID = AccessPoint.convertToQuotedString(
                    mAccessPoint.getSsidStr());
        } else {
            config.networkId = mAccessPoint.getConfig().networkId;
            config.hiddenSSID = mAccessPoint.getConfig().hiddenSSID;
        }

        config.shared = mSharedCheckBox.isChecked();

        switch (mAccessPointSecurity) {
            case AccessPoint.SECURITY_NONE:
                config.allowedKeyManagement.set(KeyMgmt.NONE);
                break;

            case AccessPoint.SECURITY_WEP:
...
                break;

            case AccessPoint.SECURITY_PSK:
                config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
                if (mPasswordView.length() != 0) {
                    String password = mPasswordView.getText().toString();
                    if (password.matches("[0-9A-Fa-f]{64}")) {
                        config.preSharedKey = password;
                    } else {
                        config.preSharedKey = '"' + password + '"';
                    }
                }
                break;

            case AccessPoint.SECURITY_EAP:
                ...
                break;
            default:
                return null;
        }

        config.setIpConfiguration(
                new IpConfiguration(mIpAssignment, mProxySettings,
                                    mStaticIpConfiguration, mHttpProxy));

        return config;
    }

先添加的wpa/wpa2类型的网络 config一般就初始化SSID、hiddenSSID、shared、allowedKeyManagement、preSharedKey和setIpConfiguration。

 

1.2 WifiManager

    /**
     * Save the given network to the list of configured networks for the
     * foreground user. If the network already exists, the configuration
     * is updated. Any new network is enabled by default.
     *
     * For a new network, this function is used instead of a
     * sequence of addNetwork(), enableNetwork() and saveConfiguration().
     *
     * For an existing network, it accomplishes the task of updateNetwork()
     * and saveConfiguration()
     *
     * @param config the set of variables that describe the configuration,
     *            contained in a {@link WifiConfiguration} object.
     * @param listener for callbacks on success or failure. Can be null.
     * @throws IllegalStateException if the WifiManager instance needs to be
     * initialized again
     * @hide
     */
    public void save(WifiConfiguration config, ActionListener listener) {
        if (config == null) throw new IllegalArgumentException("config cannot be null");
        getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
    }

从注释我们看到了save是一系列方法的封装。

对于新网络:save完成addNetwork(), enableNetwork() and saveConfiguration()

对于已保存网络:save完成updateNetwork() and saveConfiguration()

 

1.3 WifiServiceImpl

                case WifiManager.SAVE_NETWORK: {
                    if (checkChangePermissionAndReplyIfNotAuthorized(
                            msg, WifiManager.SAVE_NETWORK_FAILED)) {
                        WifiConfiguration config = (WifiConfiguration) msg.obj;
                        int networkId = msg.arg1;
                        Slog.d(TAG, "SAVE"
                                + " nid=" + Integer.toString(networkId)
                                + " uid=" + msg.sendingUid
                                + " name="
                                + mContext.getPackageManager().getNameForUid(msg.sendingUid));
                        if (config != null) {
                            if (DBG) Slog.d(TAG, "Save network with config " + config);
                            /* Command is forwarded to state machine */
                            mWifiStateMachine.sendMessage(Message.obtain(msg));
                        } else {
                            Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
                            replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
                                    WifiManager.INVALID_ARGS);
                        }
                    }
                    break;
                }

 

1.4 WifiStateMachine

                case WifiManager.SAVE_NETWORK:
                    result = saveNetworkConfigAndSendReply(message);
                    netId = result.getNetworkId();
                    if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
                        mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
                        if (result.hasCredentialChanged()) {
                            config = (WifiConfiguration) message.obj;
                            // The network credentials changed and we're connected to this network,
                            // start a new connection with the updated credentials.
                            logi("SAVE_NETWORK credential changed for config=" + config.configKey()
                                    + ", Reconnecting.");
                            startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
                        } else {
                            if (result.hasProxyChanged()) {
                                log("Reconfiguring proxy on connection");
                                mIpClient.setHttpProxy(
                                        getCurrentWifiConfiguration().getHttpProxy());
                            }
                            if (result.hasIpChanged()) {
                                // The current connection configuration was changed
                                // We switched from DHCP to static or from static to DHCP, or the
                                // static IP address has changed.
                                log("Reconfiguring IP on connection");
                                // TODO(b/36576642): clear addresses and disable IPv6
                                // to simplify obtainingIpState.
                                transitionTo(mObtainingIpState);
                            }
                        }
                    }
                    break;

 

    /**
     * Private method to handle calling WifiConfigManager to add & enable network configs and reply
     * to the message from the sender of the outcome.
     *
     * @return NetworkUpdateResult with networkId of the added/updated configuration. Will return
     * {@link WifiConfiguration#INVALID_NETWORK_ID} in case of error.
     */
    private NetworkUpdateResult saveNetworkConfigAndSendReply(Message message) {
        WifiConfiguration config = (WifiConfiguration) message.obj;
        if (config == null) {
            loge("SAVE_NETWORK with null configuration "
                    + mSupplicantStateTracker.getSupplicantStateName()
                    + " my state " + getCurrentState().getName());
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
            replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }
        NetworkUpdateResult result =
                mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
        if (!result.isSuccess()) {
            loge("SAVE_NETWORK adding/updating config=" + config + " failed");
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
            replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
            return result;
        }
        if (!mWifiConfigManager.enableNetwork(
                result.getNetworkId(), false, message.sendingUid)) {
            loge("SAVE_NETWORK enabling config=" + config + " failed");
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
            replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }
        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
        return result;
    }

1.5 WifiConfigManager

1.5.1 addOrUpdateNetwork

保存网络第一步:添加网络

    /**
     * Add a network or update a network configuration to our database.
     * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty
     * network configuration. Otherwise, the networkId should refer to an existing configuration.
     *
     * @param config provided WifiConfiguration object.
     * @param uid    UID of the app requesting the network addition/modification.
     * @return NetworkUpdateResult object representing status of the update.
     */
    public NetworkUpdateResult addOrUpdateNetwork(WifiConfiguration config, int uid) {
        if (!doesUidBelongToCurrentUser(uid)) {
            Log.e(TAG, "UID " + uid + " not visible to the current user");
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }
        if (config == null) {
            Log.e(TAG, "Cannot add/update network with null config");
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }
        if (mPendingStoreRead) {
            Log.e(TAG, "Cannot add/update network before store is read!");
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }
        NetworkUpdateResult result = addOrUpdateNetworkInternal(config, uid);
        if (!result.isSuccess()) {
            Log.e(TAG, "Failed to add/update network " + config.getPrintableSsid());
            return result;
        }
        WifiConfiguration newConfig = getInternalConfiguredNetwork(result.getNetworkId());
        sendConfiguredNetworkChangedBroadcast(
                newConfig,
                result.isNewNetwork()
                        ? WifiManager.CHANGE_REASON_ADDED
                        : WifiManager.CHANGE_REASON_CONFIG_CHANGE);
        // Unless the added network is ephemeral or Passpoint, persist the network update/addition.
        if (!config.ephemeral && !config.isPasspoint()) {
            saveToStore(true);
            if (mListener != null) {
                if (result.isNewNetwork()) {
                    mListener.onSavedNetworkAdded(newConfig.networkId);
                } else {
                    mListener.onSavedNetworkUpdated(newConfig.networkId);
                }
            }
        }
        return result;
    }

 

    /**
     * Add a network or update a network configuration to our database.
     * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty
     * network configuration. Otherwise, the networkId should refer to an existing configuration.
     *
     * @param config provided WifiConfiguration object.
     * @param uid    UID of the app requesting the network addition/deletion.
     * @return NetworkUpdateResult object representing status of the update.
     */
    private NetworkUpdateResult addOrUpdateNetworkInternal(WifiConfiguration config, int uid) {
        if (mVerboseLoggingEnabled) {
            Log.v(TAG, "Adding/Updating network " + config.getPrintableSsid());
        }
        WifiConfiguration newInternalConfig = null;

        // First check if we already have a network with the provided network id or configKey.
        WifiConfiguration existingInternalConfig = getInternalConfiguredNetwork(config);
        // No existing network found. So, potentially a network add.
        if (existingInternalConfig == null) {
            if (!WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)) {
                Log.e(TAG, "Cannot add network with invalid config");
                return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
            }
            newInternalConfig = createNewInternalWifiConfigurationFromExternal(config, uid);
            // Since the original config provided may have had an empty
            // {@link WifiConfiguration#allowedKeyMgmt} field, check again if we already have a
            // network with the the same configkey.
            existingInternalConfig = getInternalConfiguredNetwork(newInternalConfig.configKey());
        }
        // Existing network found. So, a network update.
        if (existingInternalConfig != null) {
            if (!WifiConfigurationUtil.validate(
                    config, WifiConfigurationUtil.VALIDATE_FOR_UPDATE)) {
                Log.e(TAG, "Cannot update network with invalid config");
                return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
            }
            // Check for the app's permission before we let it update this network.
            if (!canModifyNetwork(existingInternalConfig, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
                Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
                        + config.configKey());
                return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
            }
            newInternalConfig =
                    updateExistingInternalWifiConfigurationFromExternal(
                            existingInternalConfig, config, uid);
        }

        // Only add networks with proxy settings if the user has permission to
        if (WifiConfigurationUtil.hasProxyChanged(existingInternalConfig, newInternalConfig)
                && !canModifyProxySettings(uid)) {
            Log.e(TAG, "UID " + uid + " does not have permission to modify proxy Settings "
                    + config.configKey() + ". Must have NETWORK_SETTINGS,"
                    + " or be device or profile owner.");
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }

        // Update the keys for non-Passpoint enterprise networks.  For Passpoint, the certificates
        // and keys are installed at the time the provider is installed.
        if (config.enterpriseConfig != null
                && config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE
                && !config.isPasspoint()) {
            if (!(mWifiKeyStore.updateNetworkKeys(newInternalConfig, existingInternalConfig))) {
                return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
            }
        }

        boolean newNetwork = (existingInternalConfig == null);
        // This is needed to inform IpClient about any IP configuration changes.
        boolean hasIpChanged =
                newNetwork || WifiConfigurationUtil.hasIpChanged(
                        existingInternalConfig, newInternalConfig);
        boolean hasProxyChanged =
                newNetwork || WifiConfigurationUtil.hasProxyChanged(
                        existingInternalConfig, newInternalConfig);
        // Reset the |hasEverConnected| flag if the credential parameters changed in this update.
        boolean hasCredentialChanged =
                newNetwork || WifiConfigurationUtil.hasCredentialChanged(
                        existingInternalConfig, newInternalConfig);
        if (hasCredentialChanged) {
            newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false);
        }

        // Add it to our internal map. This will replace any existing network configuration for
        // updates.
        try {
            mConfiguredNetworks.put(newInternalConfig);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Failed to add network to config map", e);
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }

        if (mDeletedEphemeralSSIDs.remove(config.SSID)) {
            if (mVerboseLoggingEnabled) {
                Log.v(TAG, "Removed from ephemeral blacklist: " + config.SSID);
            }
        }

        // Stage the backup of the SettingsProvider package which backs this up.
        mBackupManagerProxy.notifyDataChanged();

        NetworkUpdateResult result =
                new NetworkUpdateResult(hasIpChanged, hasProxyChanged, hasCredentialChanged);
        result.setIsNewNetwork(newNetwork);
        result.setNetworkId(newInternalConfig.networkId);

        localLog("addOrUpdateNetworkInternal: added/updated config."
                + " netId=" + newInternalConfig.networkId
                + " configKey=" + newInternalConfig.configKey()
                + " uid=" + Integer.toString(newInternalConfig.creatorUid)
                + " name=" + newInternalConfig.creatorName);
        return result;
    }

1)这次梳理的保存网络是针对新网络添加,新网络添加会对Settings传来的如下参数进行校验,这和之前梳理的是正好对上的。

    public static boolean validate(WifiConfiguration config, boolean isAdd) {
        if (!validateSsid(config.SSID, isAdd)) {
            return false;
        }
        if (!validateKeyMgmt(config.allowedKeyManagement)) {
            return false;
        }
        if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
                && !validatePsk(config.preSharedKey, isAdd)) {
            return false;
        }
        if (!validateIpConfiguration(config.getIpConfiguration())) {
            return false;
        }
        // TBD: Validate some enterprise params as well in the future here.
        return true;
    }

2)校验成功以后会将外部配置转换为内部配置

    /**
     * Create a new internal WifiConfiguration object by copying over parameters from the provided
     * external configuration and set defaults for the appropriate parameters.
     *
     * @param externalConfig WifiConfiguration object provided from the external API.
     * @return New WifiConfiguration object with parameters merged from the provided external
     * configuration.
     */
    private WifiConfiguration createNewInternalWifiConfigurationFromExternal(
            WifiConfiguration externalConfig, int uid) {
        WifiConfiguration newInternalConfig = new WifiConfiguration();

        // First allocate a new network ID for the configuration.
        newInternalConfig.networkId = mNextNetworkId++;

        // First set defaults in the new configuration created.
        setDefaultsInWifiConfiguration(newInternalConfig);

        // Copy over all the public elements from the provided configuration.
        mergeWithInternalWifiConfiguration(newInternalConfig, externalConfig);

        // Copy over the hidden configuration parameters. These are the only parameters used by
        // system apps to indicate some property about the network being added.
        // These are only copied over for network additions and ignored for network updates.
        newInternalConfig.requirePMF = externalConfig.requirePMF;
        newInternalConfig.noInternetAccessExpected = externalConfig.noInternetAccessExpected;
        newInternalConfig.ephemeral = externalConfig.ephemeral;
        newInternalConfig.useExternalScores = externalConfig.useExternalScores;
        newInternalConfig.shared = externalConfig.shared;

        // Add debug information for network addition.
        newInternalConfig.creatorUid = newInternalConfig.lastUpdateUid = uid;
        newInternalConfig.creatorName = newInternalConfig.lastUpdateName =
                mContext.getPackageManager().getNameForUid(uid);
        newInternalConfig.creationTime = newInternalConfig.updateTime =
                createDebugTimeStampString(mClock.getWallClockMillis());

        return newInternalConfig;
    }

3)初始化NetworkUpdateResult,由于是newNetwork,所以以下参数都是true。

        boolean newNetwork = (existingInternalConfig == null);
        // This is needed to inform IpClient about any IP configuration changes.
        boolean hasIpChanged =
                newNetwork || WifiConfigurationUtil.hasIpChanged(
                        existingInternalConfig, newInternalConfig);
        boolean hasProxyChanged =
                newNetwork || WifiConfigurationUtil.hasProxyChanged(
                        existingInternalConfig, newInternalConfig);
        // Reset the |hasEverConnected| flag if the credential parameters changed in this update.
        boolean hasCredentialChanged =
                newNetwork || WifiConfigurationUtil.hasCredentialChanged(
                        existingInternalConfig, newInternalConfig);
        if (hasCredentialChanged) {
            newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false);
        }

        // Add it to our internal map. This will replace any existing network configuration for
        // updates.
        try {
            mConfiguredNetworks.put(newInternalConfig);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Failed to add network to config map", e);
            return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
        }

        if (mDeletedEphemeralSSIDs.remove(config.SSID)) {
            if (mVerboseLoggingEnabled) {
                Log.v(TAG, "Removed from ephemeral blacklist: " + config.SSID);
            }
        }

        // Stage the backup of the SettingsProvider package which backs this up.
        mBackupManagerProxy.notifyDataChanged();

        NetworkUpdateResult result =
                new NetworkUpdateResult(hasIpChanged, hasProxyChanged, hasCredentialChanged);
        result.setIsNewNetwork(newNetwork);
        result.setNetworkId(newInternalConfig.networkId);

        localLog("addOrUpdateNetworkInternal: added/updated config."
                + " netId=" + newInternalConfig.networkId
                + " configKey=" + newInternalConfig.configKey()
                + " uid=" + Integer.toString(newInternalConfig.creatorUid)
                + " name=" + newInternalConfig.creatorName);

4)保存数据

        mWifiConfigStore.registerStoreData(mNetworkListStoreData);
        mWifiConfigStore.registerStoreData(mDeletedEphemeralSsidsStoreData);


        // Unless the added network is ephemeral or Passpoint, persist the network update/addition.
        if (!config.ephemeral && !config.isPasspoint()) {
            saveToStore(true);
            if (mListener != null) {
                if (result.isNewNetwork()) {
                    mListener.onSavedNetworkAdded(newConfig.networkId);
                } else {
                    mListener.onSavedNetworkUpdated(newConfig.networkId);
                }
            }
        }


    /**
     * Save the current snapshot of the in-memory lists to the config store.
     *
     * @param forceWrite Whether the write needs to be forced or not.
     * @return Whether the write was successful or not, this is applicable only for force writes.
     */
    public boolean saveToStore(boolean forceWrite) {
        if (mPendingStoreRead) {
            Log.e(TAG, "Cannot save to store before store is read!");
            return false;
        }
        ArrayList sharedConfigurations = new ArrayList<>();
        ArrayList userConfigurations = new ArrayList<>();
        // List of network IDs for legacy Passpoint configuration to be removed.
        List legacyPasspointNetId = new ArrayList<>();
        for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
            // Ignore ephemeral networks and non-legacy Passpoint configurations.
            if (config.ephemeral || (config.isPasspoint() && !config.isLegacyPasspointConfig)) {
                continue;
            }

            // Migrate the legacy Passpoint configurations owned by the current user to
            // {@link PasspointManager}.
            if (config.isLegacyPasspointConfig && WifiConfigurationUtil.doesUidBelongToAnyProfile(
                        config.creatorUid, mUserManager.getProfiles(mCurrentUserId))) {
                legacyPasspointNetId.add(config.networkId);
                // Migrate the legacy Passpoint configuration and add it to PasspointManager.
                if (!PasspointManager.addLegacyPasspointConfig(config)) {
                    Log.e(TAG, "Failed to migrate legacy Passpoint config: " + config.FQDN);
                }
                // This will prevent adding |config| to the |sharedConfigurations|.
                continue;
            }

            // We push all shared networks & private networks not belonging to the current
            // user to the shared store. Ideally, private networks for other users should
            // not even be in memory,
            // But, this logic is in place to deal with store migration from N to O
            // because all networks were previously stored in a central file. We cannot
            // write these private networks to the user specific store until the corresponding
            // user logs in.
            if (config.shared || !WifiConfigurationUtil.doesUidBelongToAnyProfile(
                    config.creatorUid, mUserManager.getProfiles(mCurrentUserId))) {
                sharedConfigurations.add(config);
            } else {
                userConfigurations.add(config);
            }
        }

        // Remove the configurations for migrated Passpoint configurations.
        for (int networkId : legacyPasspointNetId) {
            mConfiguredNetworks.remove(networkId);
        }

        // Setup store data for write.
        mNetworkListStoreData.setSharedConfigurations(sharedConfigurations);
        mNetworkListStoreData.setUserConfigurations(userConfigurations);
        mDeletedEphemeralSsidsStoreData.setSsidList(mDeletedEphemeralSSIDs);

        try {
            mWifiConfigStore.write(forceWrite);
        } catch (IOException e) {
            Log.wtf(TAG, "Writing to store failed. Saved networks maybe lost!", e);
            return false;
        } catch (XmlPullParserException e) {
            Log.wtf(TAG, "XML serialization for store failed. Saved networks maybe lost!", e);
            return false;
        }
        return true;
    }

简单看了下是以xml的形式保存下WiFi的属性配置。而xml最初是由WifiInjector初始化时创建的

WifiInjector.java
        mWifiConfigStore = new WifiConfigStore(
                mContext, wifiStateMachineLooper, mClock,
                WifiConfigStore.createSharedFile());
        // Legacy config store
        DelayedDiskWrite writer = new DelayedDiskWrite();
        mIpConfigStore = new IpConfigStore(writer);
        // Config Manager
        mWifiConfigManager = new WifiConfigManager(mContext, mClock,
                UserManager.get(mContext), TelephonyManager.from(mContext),
                mWifiKeyStore, mWifiConfigStore, mWifiPermissionsUtil,
                mWifiPermissionsWrapper, new NetworkListStoreData(mContext),
                new DeletedEphemeralSsidsStoreData());



WifiConfigStore.java
    private static StoreFile createFile(File storeBaseDir) {
        File storeDir = new File(storeBaseDir, STORE_DIRECTORY_NAME);
        if (!storeDir.exists()) {
            if (!storeDir.mkdir()) {
                Log.w(TAG, "Could not create store directory " + storeDir);
            }
        }
        return new StoreFile(new File(storeDir, STORE_FILE_NAME));
    }

    /**
     * Create a new instance of the shared store file.
     *
     * @return new instance of the store file or null if the directory cannot be created.
     */
    public static StoreFile createSharedFile() {
        return createFile(Environment.getDataMiscDirectory());
    }



    /**
     * Config store file name for both shared & user specific stores.
     */
    private static final String STORE_FILE_NAME = "WifiConfigStore.xml";
    /**
     * Directory to store the config store files in.
     */
    private static final String STORE_DIRECTORY_NAME = "wifi";

应该是在/data/misc/wifi/WifiConfigStore.xml下保存了。

 

1.5.2 enableNetwork

    /**
     * Enable a network using the public {@link WifiManager#enableNetwork(int, boolean)} API.
     *
     * @param networkId     network ID of the network that needs the update.
     * @param disableOthers Whether to disable all other networks or not. This is used to indicate
     *                      that the app requested connection to a specific network.
     * @param uid           uid of the app requesting the update.
     * @return true if it succeeds, false otherwise
     */
    public boolean enableNetwork(int networkId, boolean disableOthers, int uid) {
        if (mVerboseLoggingEnabled) {
            Log.v(TAG, "Enabling network " + networkId + " (disableOthers " + disableOthers + ")");
        }
        if (!doesUidBelongToCurrentUser(uid)) {
            Log.e(TAG, "UID " + uid + " not visible to the current user");
            return false;
        }
        WifiConfiguration config = getInternalConfiguredNetwork(networkId);
        if (config == null) {
            return false;
        }
        if (!canModifyNetwork(config, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
            Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
                    + config.configKey());
            return false;
        }
        if (!updateNetworkSelectionStatus(
                networkId, WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE)) {
            return false;
        }
        if (disableOthers) {
            setLastSelectedNetwork(networkId);
        }
        saveToStore(true);
        return true;
    }

 

    /**
     * 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);
    }

    /**
     * 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) {
            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);
    }



    /**
     * 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;
    }


    /**
     * Helper method to mark a network enabled for network selection.
     */
    private void setNetworkSelectionEnabled(WifiConfiguration config) {
        NetworkSelectionStatus status = config.getNetworkSelectionStatus();
        status.setNetworkSelectionStatus(
                NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
        status.setDisableTime(
                NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
        status.setNetworkSelectionDisableReason(NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);

        // Clear out all the disable reason counters.
        status.clearDisableReasonCounter();
        if (mListener != null) mListener.onSavedNetworkEnabled(config.networkId);
    }


    /**
     * Helper method to set the publicly exposed status for the network and send out the network
     * status change broadcast.
     */
    private void setNetworkStatus(WifiConfiguration config, int status) {
        config.status = status;
        sendConfiguredNetworkChangedBroadcast(config, WifiManager.CHANGE_REASON_CONFIG_CHANGE);
    }

saveConfiguration应该是对应于saveToStore?

 

 

2.总结

(九十三) Android O 连接WiFi AP流程梳理续——保存网络_第1张图片

你可能感兴趣的:(Wifi)