Как обновить уже созданную конфигурацию Wi-Fi (или «UID XXX не имеет разрешения на обновление ошибки конфигурации [Wi-Fi]»)? - PullRequest
0 голосов
/ 28 декабря 2018

Я занимаюсь разработкой приложения, которое управляет подключениями Wi-Fi.Мой сценарий таков: скажем, во всем здании есть сеть Wi-Fi под названием «testing-tls».Мое приложение должно иметь возможность подключаться только к выбранным точкам доступа (на основе BSSID или MAC ID).Для проверки пользователя мы используем механизм TLS-аутентификация (пользовательские сертификаты CA).

Я могу установить соединение через приложение, но не удается, когда я пытаюсь подключиться к другой точке доступа(разные BSSID).Несмотря на то, что я создал конфигурацию Wi-Fi программно, я не могу обновить конфигурацию после первого успешного подключения.Я проверил свое приложение в Орео и Зефир.Но я сталкиваюсь с проблемами в Oreo (не уверен насчет нуги).Я начинаю задумываться, возможно ли вообще обновить конфигурацию после ее создания.

Вот следующие шаги, которые я выполняю:

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) Получить идентификатор выхода из сети, если имеется

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 в Oreo

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

Расследование

После копания в исходном коде я нашел реализацию метода addOrUpdateNetwork в WifiConfigManager class.

Реализация addOrUpdateNetwork, в теге android_8.0.0_r21 (номер сборки OPD1.170816.010) выглядит следующим образом:

  • Сначала проверьте, если у нас уже есть сеть с предоставленным идентификатором сети или 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);
}

Насколько я вижу, только следующие пользователи имеют доступ для изменения конфигурации сети.

  1. Системное приложение
  2. Владелец устройства
  3. Создатель (По какой-то причине происходит сбой)

Я получаю одинаковое поведение в этих двух телефонах.

  1. Пиксель 2 (Oreo 8.0.0)
  2. Samsung J8 (Oreo 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 перед обновлением или включением конфигурации?

1 Ответ

0 голосов
/ 06 января 2019

После копания исходного кода, наконец-то получил ответы на мои вопросы.

Вопрос: можно ли обновить конфигурации после его создания?

Ответ: Да, Android OS позволяет обновлять конфигурацию, созданную из вашего приложения.Когда я позвонил 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

Вопрос: что такое UID 10189 не имеет разрешения на обновление«Ошибка конфигурации» в Oreo?

Ответ: После обновления конфигурации мы должны вызвать метод wifimanager.enableNetwork () , чтобы установить соединение сжелаемая точка доступа.Рабочий процесс EnableNetwork () выглядит следующим образом.

  1. WifiManager.enableNetwork () внутренне вызывает SyncEnableNetwork () метод класса WifiStateMachine.

WifiStateMachine является базовым классом, который отслеживает состояние подключения к Wi-Fi.Вся обработка событий и все изменения в состоянии подключения инициируются в этом классе.

Метод SyncEnableNetwork () отправляет сообщение CMD_ENABLE_NETWORK на класс ConnectModeState .

Если параметр disableOthers имеет значение true, вызовите connectToUserSelectNetwork () метод и передает networkId, вызывая UID и принудительно переподключая [всегда false - жестко закодированное значение] в качестве аргументов.

Если приложение не имеет всех необходимых разрешений для обновления конфигурации [использует checkAndUpdateLastUid () метод в WifiConfigManager class - возвращает true только для системных настроек / приложения sysui] или если не удается включить сеть, будут напечатаны следующие операторы.

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 () был переименован в updateLastConnectUid () в Android Pie.Они также немного изменили его функциональность.

Для получения дополнительной информации, пожалуйста, обратитесь к диаграмме ниже [Я плохо разбираюсь в блок-схемах.Пожалуйста, согласитесь со мной или предложите, если потребуются какие-либо изменения].

enable network

Вопрос 3. Обязательно ли отключать Wi-Fi перед обновлением или включениемконфигурация?

Ответ: ОС запускает соединение / переподключение к сети при следующих условиях:

  1. Выбранный идентификатор сети должен отличаться от текущегоидентификатор подключенной сети.
  2. Если аргумент forceReconnect имеет значение true, Android готовится к повторному подключению [Истина только для системных настроек / приложения sysui].

Поскольку приложения разработчика не имеют возможностипринудительное подключение, мы должны отключить Wi-Fi для подключения / повторного подключения к сети после обновления конфигурации.

Надеюсь, что это поможет другим.

...