Wi-Fi 密码WifiConfigStore.xml

本文详细介绍了Android13中基于AOSP的Wifi配置文件的变化,包括共享配置文件和用户特定文件的存储路径,以及如何在不同Android版本间进行迁移。在Android10到Android11的升级过程中,`WifiConfigStore.xml`等文件的位置有所改变,并涉及到加密和用户安全。在系统启动时,`WifiConfigManager`会加载这些配置文件,恢复网络设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于 Android 13 的代码:http://aospxref.com/android-13.0.0_r3/

从这里我们知道版本的区别:http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/wifi/migration_samples/README.txt

Shared files
============
1) WifiConfigStore.xml - General storage for shared configurations. Includes
user's saved Wi-Fi networks.
AOSP Path in Android 10: /data/misc/wifi/WifiConfigStore.xml
AOSP Path in Android 11: /data/misc/apexdata/com.android/wifi/WifiConfigStore.xml
Sample File (in this folder): Shared_WifiConfigStore.xml

2) WifiConfigStoreSoftAp.xml - Storage for user's softap/tethering configuration.
AOSP Path in Android 10: /data/misc/wifi/softap.conf.
Note: Was key/value format in Android 10. Conversion to XML done in SoftApConfToXmlMigrationUtil.java.
AOSP Path in Android 11: /data/misc/apexdata/com.android/wifi/WifiConfigStore.xml
Sample File (in this folder): Shared_WifiConfigStoreSoftAp.xml

User specific files
==================
3) WifiConfigStore.xml - General storage for user specific configurations. Includes
user's saved passpoint networks, Wi-Fi network request approvals, etc.
AOSP Path in Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStore.xml
AOSP Path in Android 11: /data/misc_ce/<userId>/apexdata/com.android/wifi/WifiConfigStore.xml
Sample File (in this folder): User_WifiConfigStore.xml

4) WifiConfigStoreNetworkSuggestions.xml - Storage for app installed network suggestions.
AOSP Path in Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStoreNetworkSuggestions.xml
AOSP Path in Android 11: /data/misc_ce/<userId>/apexdata/com.android/wifi/WifiConfigStoreNetworkSuggestions.xml
Sample File (in this folder): User_WifiConfigStoreNetworkSuggestions.xml

Android 10 之前一般都在:/data/vendor/wifi/wpa 目录下有份 wpa_supplicant.conf 文件

这里我们记录下这个配置文件如何保存的

WifiConfigStore.java - OpenGrok cross reference for /packages/modules/Wifi/service/java/com/android/server/wifi/WifiConfigStore.java

​//Config store file name for general shared store file. 
private static final String STORE_FILE_NAME_SHARED_GENERAL = "WifiConfigStore.xml";
public static final int STORE_FILE_SHARED_GENERAL = 0;

//Mapping of Store file Id to Store file names.
private static final SparseArray<String> STORE_ID_TO_FILE_NAME =
            new SparseArray<String>() {{
                //这里我们只关心 WifiConfigStore.xml 有关的,key + value的组合
                //put(0, WifiConfigStore.xml)
                put(STORE_FILE_SHARED_GENERAL, STORE_FILE_NAME_SHARED_GENERAL);  
                put(STORE_FILE_SHARED_SOFTAP, STORE_FILE_NAME_SHARED_SOFTAP);
                put(STORE_FILE_USER_GENERAL, STORE_FILE_NAME_USER_GENERAL);
                put(STORE_FILE_USER_NETWORK_SUGGESTIONS, STORE_FILE_NAME_USER_NETWORK_SUGGESTIONS); }};

// 创建的地方
public static @NonNull List<StoreFile> createSharedFiles(boolean shouldEncryptCredentials) {
  return createFiles(
                Environment.getWifiSharedDirectory(),
                Arrays.asList(STORE_FILE_SHARED_GENERAL, STORE_FILE_SHARED_SOFTAP),
                UserHandle.ALL,
                shouldEncryptCredentials);
}

 看下创建是的参数:Environment.getWifiSharedDirectory()

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/framework/java/android/net/wifi/util/Environment.java?fi=getWifiSharedDirectory#getWifiSharedDirectory

  private static final String WIFI_APEX_NAME = "com.android.wifi";    
  public static File getWifiSharedDirectory() {
        // ApexEnvironment.getApexEnvironment() 方法,并传入 Wi-Fi APEX 的名称作为参数。
        // 然后使用返回的ApexEnvironment对象调用getDeviceProtectedDataDir()方法,以获取 Wi-Fi APEX 模块的设备保护数据目录
        return ApexEnvironment.getApexEnvironment(WIFI_APEX_NAME).getDeviceProtectedDataDir();
    }

参数差不多就知道了,然后看下是什么地方调用这个 createSharedFiles 方法来创建

http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiInjector.java#346

344          // New config store
345          mWifiConfigStore = new WifiConfigStore(mContext, wifiHandler, mClock, mWifiMetrics,
346                  WifiConfigStore.createSharedFiles(mFrameworkFacade.isNiapModeOn(mContext)));

可以知道是在WifiInjector初始化的时候创建了这个,参数:mFrameworkFacade.isNiapModeOn(mContext) 是判断符不符合 NIAP,可以百度下NIAP是啥:NIAP(National Information Assurance Partnership)模式是一个安全标准和认证程序,旨在确保信息技术产品满足特定的安全性要求和标准。NIAP 是由美国国家安全局(NSA)和国家科学基金会(NSF)共同发起的一个合作伙伴关系计划。NIAP 的目标是确保计算机和通信系统的安全性,以保护敏感信息免受未经授权的访问和恶意活动的威胁。它通过制定一系列安全性要求和测试程序,对信息技术产品进行评估和认证,以验证其符合特定的安全标准。NIAP 模式是指在设备中启用了符合 NIAP 标准的安全配置和措施。它可能涉及硬件和软件层面的安全性要求,包括加密、身份验证、访问控制、漏洞修复等方面。设备处于 NIAP 模式可以提供更高的安全级别,并满足特定安全需求的组织和部门的要求。需要注意的是,NIAP 模式的具体实现和要求可能因不同的国家、组织和产品而有所不同。它通常涉及与特定的安全标准和认证计划相关的要求和规范

        到此,我们知道了,上面的Shared files中的General storage for shared configurations的配置,接下来再看下User specific files中的General storage for user specific configurations,同理,创建的时候调用方法还是在WifiConfigStore.java中:

    public static @Nullable List<StoreFile> createUserFiles(int userId,
            boolean shouldEncryptCredentials) {
        UserHandle userHandle = UserHandle.of(userId);
        return createFiles(
                Environment.getWifiUserDirectory(userId),   ---> 这个上面已经记录过了,就是获取路径
                //数组转集合,参数就是(2,3),对应 SparseArray<String> STORE_ID_TO_FILE_NAME 里面的value
                Arrays.asList(STORE_FILE_USER_GENERAL, STORE_FILE_USER_NETWORK_SUGGESTIONS),
                userHandle,
                shouldEncryptCredentials);
    }    
    // 调用下面这个方法
    private static @Nullable List<StoreFile> createFiles(File storeDir, List<Integer> storeFileIds,
            UserHandle userHandle, boolean shouldEncryptCredentials) {
        List<StoreFile> storeFiles = new ArrayList<>();
        for (int fileId : storeFileIds) {
        // 参数:路径,需要创建的xml,……,……。具体的看下面
            StoreFile storeFile = createFile(storeDir, fileId, userHandle, shouldEncryptCredentials);
            if (storeFile == null) {
                return null;
            }
            storeFiles.add(storeFile);
        }
        return storeFiles;
    }    
    // 看这里创建啥
    private static @Nullable StoreFile createFile(@NonNull File storeDir,
            @StoreFileId int fileId, UserHandle userHandle, boolean shouldEncryptCredentials) {
        if (!storeDir.exists()) {
            if (!storeDir.mkdir()) {  ---> 不存在创建一个目录
                Log.w(TAG, "Could not create store directory " + storeDir);
                return null;
            }
        }
        File file = new File(storeDir, STORE_ID_TO_FILE_NAME.get(fileId));
        WifiConfigStoreEncryptionUtil encryptionUtil = null;
        if (shouldEncryptCredentials) {
            encryptionUtil = new WifiConfigStoreEncryptionUtil(file.getName());
        }
        return new StoreFile(file, fileId, userHandle, encryptionUtil);  ---> 和StoreFile对应,返回
    }   
     
    public StoreFile(File file, @StoreFileId int fileId,
                @NonNull UserHandle userHandle,
                @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) {
            mAtomicFile = new AtomicFile(file);
            mFileName = file.getAbsolutePath();
            mFileId = fileId;
            mUserHandle = userHandle;
            mEncryptionUtil = encryptionUtil;
        }

看下什么地方调用的:http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiConfigManager.java#loadFromStore

    /**
     * Read the config store and load the in-memory lists from the store data retrieved and sends
     * out the networks changed broadcast.
     *
     * This reads all the network configurations from:
     * 1. Shared WifiConfigStore.xml
     * 2. User WifiConfigStore.xml
     *
     * @return true on success or not needed (fresh install), false otherwise.
     */
    public boolean loadFromStore() {  ---> 在系统启动后就调用checkAndStartWifi方法,然后就加载配置,即此方法
        // If the user unlock comes in before we load from store, which means the user store have
        // not been setup yet for the current user. Setup the user store before the read so that
        // configurations for the current user will also being loaded.
        if (mDeferredUserUnlockRead) {
            Log.i(TAG, "Handling user unlock before loading from store.");
            List<WifiConfigStore.StoreFile> userStoreFiles =
                    WifiConfigStore.createUserFiles(
                            mCurrentUserId, mFrameworkFacade.isNiapModeOn(mContext));
            if (userStoreFiles == null) {
                Log.wtf(TAG, "Failed to create user store files");
                return false;
            }
            mWifiConfigStore.setUserStores(userStoreFiles);
            mDeferredUserUnlockRead = false;
        }
        try {
            mWifiConfigStore.read();
        } catch (IOException | IllegalStateException e) {
            Log.wtf(TAG, "Reading from new store failed. All saved networks are lost!", e);
            return handleConfigStoreFailure(false);
        } catch (XmlPullParserException e) {
            Log.wtf(TAG, "XML deserialization of store failed. All saved networks are lost!", e);
            return handleConfigStoreFailure(false);
        }
        loadInternalData(mNetworkListSharedStoreData.getConfigurations(),
                mNetworkListUserStoreData.getConfigurations(),
                mRandomizedMacStoreData.getMacMapping());
        return true;
    }

支持我们也大致知道了初始化的地方,那接着上面这段代码,大致我们知道这段代码是从存储中加载已保存的网络配置数据,并进行相应的处理和加载操作,以便在系统启动或用户解锁后能够正确地恢复网络配置。具体的我们看下这两个地方在干嘛,一个个来看:

  mWifiConfigStore.read()

http://10.5.11.16:8000/cp12t/xref/packages/modules/Wifi/service/java/com/android/server/wifi/WifiConfigStore.java#read()

    public void read() throws XmlPullParserException, IOException {
        // Reset both share and user store data.
        for (StoreFile sharedStoreFile : mSharedStores) { ---> 这个就是指 STORE_FILE_NAME_SHARED_GENERAL,即 WifiConfigStore.xml
            resetStoreData(sharedStoreFile);
        }
        if (mUserStores != null) {
            for (StoreFile userStoreFile : mUserStores) {  ---> STORE_FILE_NAME_USER_GENERAL,即 WifiConfigStore.xml
                resetStoreData(userStoreFile);
            }
        }
        // 上面先重置掉,现在下面这个去读取
        long readStartTime = mClock.getElapsedSinceBootMillis();
        readFromSharedStoreFiles();  --->最终通XmlUtil类里面的parseFromXml方法去匹配对应的xml文件
        if (mUserStores != null) {
            readFromUserStoreFiles();
        }
        long readTime = mClock.getElapsedSinceBootMillis() - readStartTime;
        try {
            mWifiMetrics.noteWifiConfigStoreReadDuration(toIntExact(readTime));
        } catch (ArithmeticException e) {
            // Silently ignore on any overflow errors.
        }
        Log.d(TAG, "Reading from all stores completed in " + readTime + " ms.");
    }

​​​​​​​        从注释我们就大致知道这个方法了,把存储的填充到内存中

    /**
     * Helper function to populate the internal (in-memory) data from the retrieved stores (file)
     * data.
     * This method:
     * 1. Clears all existing internal data.
     * 2. Sends out the networks changed broadcast after loading all the data.
     *
     * @param sharedConfigurations list of network configurations retrieved from shared store.
     * @param userConfigurations list of network configurations retrieved from user store.
     * @param macAddressMapping
     */
    private void loadInternalData(
            List<WifiConfiguration> sharedConfigurations,
            List<WifiConfiguration> userConfigurations,
            Map<String, String> macAddressMapping) {
        // Clear out all the existing in-memory lists and load the lists from what was retrieved
        // from the config store.
        clearInternalData();
        loadInternalDataFromSharedStore(sharedConfigurations, macAddressMapping);
        loadInternalDataFromUserStore(userConfigurations);
        generateRandomizedMacAddresses();
        if (mConfiguredNetworks.sizeForAllUsers() == 0) {
            Log.w(TAG, "No stored networks found.");
        }
        // reset identity & anonymous identity for networks using SIM-based authentication
        // on load (i.e. boot) so that if the user changed SIMs while the device was powered off,
        // we do not reuse stale credentials that would lead to authentication failure.
        resetSimNetworks();
        sendConfiguredNetworkChangedBroadcast(WifiManager.CHANGE_REASON_ADDED);
        mPendingStoreRead = false;
    }

至此,我们大致就知道了文件是如何创建的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值