如何更新已经创建的Wi-Fi配置(或"UID XXX无权限更新[Wi-Fi]配置错误")? [英] How to update an already created Wi-Fi configuration (or "UID XXX does not have permission to update [Wi-Fi] configuration error")?
问题描述
我正在开发一个管理Wi-Fi连接的应用程序.我的情况如下:假设整个建筑物都有一个名为"testing-tls"的Wi-Fi网络.我的应用程序应该只能连接到选定的访问点(基于BSSID或MAC ID).我们使用 TLS身份验证机制来验证用户(自定义CA证书).
I am developing an app which manages the Wi-Fi connections. My scenario is as follows: Let's say, the entire building has a Wi-Fi network named "testing-tls". My app should be able to connect to only selected access points (based on BSSID or MAC ID). We use TLS authentication mechanism to verify the user (Custom CA Certificates).
我能够通过该应用建立连接,但是当我尝试连接到其他访问点(不同的BSSID)时失败.即使我以编程方式创建了Wi-Fi配置,但在首次成功建立连接后仍无法更新配置.我已经在奥利奥(Oreo)和棉花糖(Marshmallow)中测试了我的应用程序.但是,我在奥利奥(Oreo)遇到问题(不确定牛轧糖).我开始怀疑创建后是否甚至可以更新配置.
I am able to establish a connection through the app, but failing when I try to connect to a different access point (different BSSID). Even though I created the Wi-Fi configuration programmatically, I am unable to update configuration after a first successful connection. I have tested my app in Oreo and Marshmallow. But, I am facing problems in Oreo (Not sure about Nougat). I am beginning to wonder if it is even possible to update the configuration once it is created.
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" />
错误:我总是在奥利奥(Oreo)中得到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
调查
在仔细研究了源代码之后,我在实现 android_8.0.0_r21(内部版本号OPD1.170816.010)如下:
- 首先检查我们是否已经有一个具有提供的网络ID或configKey的网络
- 如果未找到现有网络,请验证配置并添加.
- 如果找到现有网络,请更新网络配置.在此之前,请检查应用程序是否具有更新网络所需的权限.
AddOrUpdateNetwork
internally calls a function called 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有权访问修改网络配置.
As far I can see, only the following uids have access to modify network configurations.
- 系统应用
- 设备所有者
- Creator(由于某种原因而失败)
这两部手机的行为相同.
I am getting the same behaviour in these two phones.
- 像素2(Oreo 8.0.0)
- 三星J8(Oreo 8.0.0)
此外,三星J8始终显示以下警告:
Additionally, Samsung J8 always shows this warning:
CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certificate path not found
问题:
- 如何以编程方式更新已创建的Wi-Fi配置?
- 在Wi-Fi的内部数据库中创建Wi-Fi配置后,甚至可以更新它吗?
- 在更新或启用配置之前是否必须断开Wi-Fi的连接?
- How can an already created Wi-Fi configuration be updated programmatically?
- Is it even possible to update the Wi-Fi configuration once it is created in the Wi-Fi's internal database?
- Is it mandatory to disconnect Wi-Fi before updating or enabling the configuration?
推荐答案
在挖掘源代码之后,终于得到了我的问题的答案.
After digging the source code, finally got answers to my questions.
问题:创建配置后是否可以更新配置?
答案:是的,Android os允许您更新从应用程序创建的配置.当我致电 wifiManager.addNetwork(),在日志窗口中打印了以下语句.
Answer: Yes, Android os allows you to update the configuration created from your application. When I called wifiManager.addNetwork(), in the log window the following statements were printed.
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没有权限更新配置错误"?
Answer: After updating the configuration, we have to call wifimanager.enableNetwork() method to establish a connection to the desired access point. Workflow of EnableNetwork() is as follows.
- WifiManager.enableNetwork()内部调用
WifiStateMachine is the core class which tracks the state of Wifi connectivity. All event handling and all changes in connectivity state are initiated in this class.
-
SyncEnableNetwork()方法将CMD_ENABLE_NETWORK消息发送到如果disableOthers为true,请调用
If disableOthers is true, call connectToUserSelectNetwork() method and passes networkId, calling UID and force reconnect [always false - hardcoded value] as arguments.
如果某个应用没有所有必要的权限来更新配置[使用 WifiConfigManager类-仅对系统设置/sysui应用程序返回true],或者如果启用网络失败,则将打印以下语句.
If an app does not have all the necessary permissions to update the configuration [uses checkAndUpdateLastUid() method in WifiConfigManager class - returns true only for system settings/sysui app] or if enabling of a network is failed, the following statements will be printed.
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
注意:在Android Pie中,checkAndUpdateLastUid()方法已重命名为updateLastConnectUid().他们也对它的功能做了些微修改.
Note: checkAndUpdateLastUid() method has been renamed to updateLastConnectUid() in Android Pie. They have slightly modified its functionality as well.
有关更多信息,请参考下图[绘制流程图不好.请忍受或建议是否需要任何更改].
For more information, please refer to the below diagram [I am no good in drawing flowcharts. Please bear with me or suggest if any changes required].
问题3:在更新或启用配置之前是否必须断开wifi连接?
答案:操作系统在以下情况下触发与网络的连接/重新连接:
Answer: OS triggers a connection/reconnection to a network under the following conditions:
- 所选的网络ID必须与当前连接的网络ID不同.
- 如果forceReconnect参数为true,则Android准备重新连接[仅适用于系统设置/sysui应用].
由于开发者应用程序无法强制连接,因此在更新配置后,我们应该断开wifi以便连接/重新连接到网络.
Since developer apps do not have the ability to a force connection, we should disconnect the wifi in order to connect/reconnect to the network after updating the configuration.
希望这对其他人有帮助.
Hope this will help others.
这篇关于如何更新已经创建的Wi-Fi配置(或"UID XXX无权限更新[Wi-Fi]配置错误")?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
-
Question: