【问题标题】:How to update an already created Wi-Fi configuration (or "UID XXX does not have permission to update [Wi-Fi] configuration error")?如何更新已创建的 Wi-Fi 配置(或“UID XXX 无权更新 [Wi-Fi] 配置错误”)?
【发布时间】:2019-05-26 03:12:04
【问题描述】:

我正在开发一个管理 Wi-Fi 连接的应用程序。我的场景如下:假设整个建筑物有一个名为“testing-tls”的 Wi-Fi 网络。我的应用程序应该只能连接到选定的接入点(基于 BSSID 或 MAC ID)。我们使用 TLS 身份验证 机制来验证用户(自定义 CA 证书)。

我能够通过应用程序建立连接,但是当我尝试连接到不同的接入点(不同的 BSSID)时失败。即使我以编程方式创建了 Wi-Fi 配置,在第一次成功连接后我也无法更新配置。我已经在 Oreo 和 Marshmallow 中测试了我的应用程序。但是,我在奥利奥面临问题(不确定牛轧糖)。我开始怀疑是否有可能在创建配置后对其进行更新。

这些是我正在遵循的步骤:

1) 创建一个 WifiConfiguration 对象

private WifiConfiguration createWifiConfiguration() {
    WifiConfiguration config = new WifiConfiguration();
    config.SSID = "\"testing-tls\"";
    config.priority = 1;
    config.status = WifiConfiguration.Status.ENABLED;
    config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP;
    config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
    config.enterpriseConfig.setIdentity(identityName);
    config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);

    PKCS12ParseInfo parseInfo;
    try {
        parseInfo = CertificateUtils.parsePKCS12Certificate(
                       certificateFilePath, identityPassword);
        if (parseInfo != null) {
            config.enterpriseConfig.setClientKeyEntry(parseInfo.getPrivateKey(),
                           parseInfo.getCertificate());
            return config;
        }
        return null;
    } catch (KeyStoreException | NoSuchAlgorithmException | IOException |
                   CertificateException | UnrecoverableKeyException | KeyManagementException e1) {
        Timber.e("WifiMonitorService, Fail to parse the input certificate: %s", e1.toString());
        Toast.makeText(this, "Error occurred", Toast.LENGTH_SHORT).show();
        return null;
    }
}

2) 尝试建立连接

private void establishWifiConnection(String result) {
    Timber.d("WifiMonitorService, establishing WifiConnection");

    WifiConfiguration configuration = createWifiConfiguration();
    if (configuration != null) {
        // result contains a mac id - 00:45:69:c5:34:f2
        configuration.BSSID = result;

        int networkId = wifiManager.addNetwork(configuration);
        if (networkId == -1) {
            networkId = getExistingNetworkId(wifiSsid);
            // Add a new configuration to the db
            if (networkId == -1) {
                Timber.e("Couldn't add network with SSID");
                Toast.makeText(this, "Wifi configuration error", Toast.LENGTH_SHORT).show();
                return;
            }
        }
        Timber.i("WifiMonitorService, # addNetwork returned: %d", networkId);
        wifiManager.saveConfiguration();
        wifiManager.enableNetwork(networkId, true);
        wifiManager.reassociate();
    } else {
        Toast.makeText(this, "Wifi conf Error occurred", Toast.LENGTH_SHORT).show();
    }
}

3) 获取退出网络 ID(如果存在)

private int getExistingNetworkId(String ssid) {
    List<WifiConfiguration> configuredNetworks  = 
    wifiManager.getConfiguredNetworks();
    if (configuredNetworks != null) {
        for (WifiConfiguration existingConfig : configuredNetworks) {
            if (existingConfig.SSID.equals("\"testing-tls\"")) {
                return existingConfig.networkId;
            }
        }
    }
    return -1;
}

清单权限如下:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />

<uses-feature android:name="android.hardware.wifi" />
<uses-feature android:name="android.hardware.camera" />

<permission
   android:name="android.permission.INTERACT_ACROSS_USERS"
   android:protectionLevel="signature" />

错误:我总是在奥利奥中得到UID 10189 does not have permission to update configuration error

2018-12-28 12:23:44.571 1320-1847/? E/WifiConfigManager: UID 10189 does not have permission to update configuration "testing-tls"WPA_EAP
2018-12-28 12:23:44.571 1320-1847/? I/WifiStateMachine: connectToUserSelectNetwork Allowing uid 10189 with insufficient permissions to connect=1

调查

翻遍源码后,在WifiConfigManager类中找到了addOrUpdateNetwork方法的实现。

实现addOrUpdateNetwork,在标签android_8.0.0_r21 (Build number OPD1.170816.010)中如下:

  • 首先检查我们是否已经有一个具有提供的网络 ID 或 configKey 的网络
  • 如果未找到现有网络,请验证配置并添加。
  • 如果找到现有网络,请更新网络配置。在此之前,请检查应用是否具有更新网络所需的权限。

AddOrUpdateNetwork 内部调用了一个名为canModifyNetwork 的函数:

/**
 * Checks if |uid| has permission to modify the provided configuration.
 *
 * @param config         WifiConfiguration object corresponding to the network to be modified.
 * @param uid            UID of the app requesting the modification.
 * @param ignoreLockdown Ignore the configuration lockdown checks for connection attempts.
 */
private boolean canModifyNetwork(WifiConfiguration config, int uid, boolean ignoreLockdown) {
    // Passpoint configurations are generated and managed by PasspointManager. They can be
    // added by either PasspointNetworkEvaluator (for auto connection) or Settings app
    // (for manual connection), and need to be removed once the connection is completed.
    // Since it is "owned" by us, so always allow us to modify them.
    if (config.isPasspoint() && uid == Process.WIFI_UID) {
        return true;
    }
    // EAP-SIM/AKA/AKA' network needs framework to update the anonymous identity provided
    // by authenticator back to the WifiConfiguration object.
    // Since it is "owned" by us, so always allow us to modify them.
    if (config.enterpriseConfig != null
            && uid == Process.WIFI_UID
            && TelephonyUtil.isSimEapMethod(config.enterpriseConfig.getEapMethod())) {
        return true;
    }
    final DevicePolicyManagerInternal dpmi = LocalServices.getService(
            DevicePolicyManagerInternal.class);
    final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid,
            DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
    // If |uid| corresponds to the device owner, allow all modifications.
    if (isUidDeviceOwner) {
        return true;
    }
    final boolean isCreator = (config.creatorUid == uid);
    // Check if the |uid| holds the |NETWORK_SETTINGS| permission if the caller asks us to
    // bypass the lockdown checks.
    if (ignoreLockdown) {
        return mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
    }
    // Check if device has DPM capability. If it has and |dpmi| is still null, then we
    // treat this case with suspicion and bail out.
    if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)
            && dpmi == null) {
        Log.w(TAG, "Error retrieving DPMI service.");
        return false;
    }
    // WiFi config lockdown related logic. At this point we know uid is NOT a Device Owner.
    final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy(
            config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
    if (!isConfigEligibleForLockdown) {
        return isCreator || mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
    }
    final ContentResolver resolver = mContext.getContentResolver();
    final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
            Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
    return !isLockdownFeatureEnabled
            && mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}

据我所知,只有以下 uid 有权修改网络配置。

  1. 系统应用
  2. 设备所有者
  3. Creator(由于某种原因失败了)

我在这两款手机中的行为相同。

  1. 像素 2(奥利奥 8.0.0)
  2. 三星 J8(奥利奥 8.0.0)

此外,Samsung J8 总是显示此警告:

CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certificate path not found

问题:

  • 如何以编程方式更新已创建的 Wi-Fi 配置?
    • 是否可以在 Wi-Fi 的内部数据库中创建 Wi-Fi 配置后对其进行更新?
    • 在更新或启用配置之前是否必须断开 Wi-Fi?

【问题讨论】:

  • @jww 感谢您的建议。我从帖子中删除了一些额外的问题。
  • @jww 在挖掘源代码后,我得到了我发布的问题的答案。请重新打开问题。我想为我的帖子写一个答案。
  • 完成。多亏了 Stephen 和 Makyen 这样的人,这个人才能幸存下来。我认为这是一个非常好的选择。这是质量研究的一个独特问题。我想在 Stack Overflow 上看到更多类似的问题。
  • @jww 和其他人,感谢您重新提出问题。感谢您的努力。

标签: android wifi android-wifi tls1.2 android-8.0-oreo


【解决方案1】:

挖掘了源代码,终于得到了我的问题的答案。

问题:配置创建后是否可以更新?

回答:是的,Android 操作系统允许您更新从应用程序创建的配置。当我调用wifiManager.addNetwork() 时,在日志窗口中打印了以下语句。

2019-01-04 12:23:16.168 1328-3114/? I/addOrUpdateNetwork:  uid = 10190 SSID "testing-tls" nid=-1
2019-01-04 12:23:16.169 1328-1851/? V/WifiConfigManager: Adding/Updating network testing-tls
2019-01-04 12:23:16.193 1328-1851/? D/WifiConfigManager: addOrUpdateNetworkInternal: added/updated config. netId=6 configKey="testing-tls"WPA_EAP uid=10190 name=in.ac.iisc.wifimonitoring vendorAP=false hiddenSSID=false autoReconnect=1
2019-01-04 12:23:16.204 1328-1851/? D/WifiConfigStore: Writing to stores completed in 7 ms.
2019-01-04 12:23:16.205 1328-1851/? D/WifiIssueDetector: report htime=2019-01-04_12:23:16 time=1546584796205 rid=105 callBy=in.ac.iisc.wifimonitoring apiName=addOrUpdateNetwork netid=6 callUid=in.ac.iisc.wifimonitoring
2019-01-04 12:23:16.206 15873-15873/in.ac.iisc.wifimonitoring I/WifiMonitorService: WifiMonitorService, #addNetwork returned: 6

问题:Oreo 中的“UID 10189 无权更新配置错误”是什么意思?

答案: 更新配置后,我们必须调用wifimanager.enableNetwork() 方法来建立与所需接入点的连接。 EnableNetwork()的工作流程如下。

  1. WifiManager.enableNetwork() 内部调用 WifiStateMachine 类的SyncEnableNetwork() 方法。

WifiStateMachine 是跟踪 Wifi 连接状态的核心类。所有事件处理和连接状态的所有更改都在此类中启动。

  1. SyncEnableNetwork() 方法将 CMD_ENABLE_NETWORK 消息发送到ConnectModeState class

  2. 如果 disableOthers 为 true,则调用 connectToUserSelectNetwork() 方法并传递 networkId,调用 UID 并强制重新连接 [始终为 false - 硬编码值] 作为参数。

  3. 1234563将打印以下语句。
2018-12-28 12:23:44.571 1320-1847/? E/WifiConfigManager: UID 10189 does not have permission to update configuration "testing-tls"WPA_EAP
2018-12-28 12:23:44.571 1320-1847/? I/WifiStateMachine: connectToUserSelectNetwork Allowing uid 10189 with insufficient permissions to connect=1

注意: checkAndUpdateLastUid() 方法在 Android Pie 中已重命名为 updateLastConnectUid()。他们也稍微修改了它的功能。

更多信息请参考下图【我不擅长画流程图。如果需要任何更改,请多多包涵或提出建议]。

问题3:更新或启用配置前是否必须断开wifi?

答案:操作系统会在以下情况下触发连接/重新连接到网络:

  1. 所选网络 ID 必须与当前连接的网络 ID 不同。
  2. 如果 forceReconnect 参数为 true,则 Android 准备重新连接 [True only for system settings/sysui app]。

由于开发者应用没有强制连接的能力,我们应该在更新配置后断开 wifi 以便连接/重新连接到网络。

希望这对其他人有所帮助。

【讨论】:

  • 如果用户从 WiFi 设置中手动添加接入点,并且应用程序使用该接入点的 ID 调用 enableNetwork,则面临“UID 10189 无权更新配置错误”。为什么我们无法连接到系统添加的那个 AP,因为我们只是连接 AP 而不是修改 WiFiConfig?任何想法@Sarweshkumar
  • @KhushbuShah AFAIK,您将无法修改用户从应用程序手动创建的 wifi 设置。如果您想这样做,请从您的应用程序创建 wifi 配置并启用它。
  • @KhushbuShah 您可以在运行 Marshmallow 及更低版本的设备上禁用其他 wifi 配置。
  • @KhushbuShah 一些安卓手机(例如:三星)有一个特殊功能,您可以禁用自动连接到 wifi 网络(您可以单独从系统应用程序中禁用)。在这种情况下,您可以通过该应用轻松连接到所需的网络。
  • 我将无法修改用户从应用程序手动创建的 wifi 设置,但是否可以添加列表中已有的相同网络?如果是,那么我可以从应用程序创建 wifi 配置并连接到它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-16
  • 1970-01-01
  • 1970-01-01
  • 2013-05-05
  • 1970-01-01
相关资源
最近更新 更多