diff options
author | Oscar Shu <xshu@google.com> | 2019-12-09 23:25:58 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-12-09 23:25:58 +0000 |
commit | f05e2f3f34b31061c22e5ceaed861a4e9f97a69d (patch) | |
tree | 7f8ed7d552905364e11199196e77a423bc1c1856 /service | |
parent | 9ead0105a7c3b8cba6b735d5b53e28ff22c04c3e (diff) | |
parent | 3f656193a2c6d6ae6b6ba81d1450c813ad1cbbb0 (diff) |
Merge "Notification to set MAC randomization setting"
Diffstat (limited to 'service')
7 files changed, 356 insertions, 0 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 1c02ac73d..304ad1b87 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -689,6 +689,7 @@ public class ClientModeImpl extends StateMachine { private WifiStateTracker mWifiStateTracker; private final BackupManagerProxy mBackupManagerProxy; private final WrongPasswordNotifier mWrongPasswordNotifier; + private final ConnectionFailureNotifier mConnectionFailureNotifier; private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; // Maximum duration to continue to log Wifi usability stats after a data stall is triggered. @VisibleForTesting @@ -745,6 +746,8 @@ public class ClientModeImpl extends StateMachine { mSupplicantStateTracker = supplicantStateTracker; mWifiConnectivityManager = mWifiInjector.makeWifiConnectivityManager(this); mBssidBlocklistMonitor = mWifiInjector.getBssidBlocklistMonitor(); + mConnectionFailureNotifier = mWifiInjector.makeConnectionFailureNotifier( + mWifiConnectivityManager); mLinkProperties = new LinkProperties(); mMcastLockManagerFilterController = new McastLockManagerFilterController(); @@ -2722,6 +2725,16 @@ public class ClientModeImpl extends StateMachine { bssidBlocklistMonitorReason); } } + boolean isAssociationRejection = level2FailureCode + == WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION; + boolean isAuthenticationFailure = level2FailureCode + == WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE + && level2FailureReason != WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD; + if ((isAssociationRejection || isAuthenticationFailure) + && mWifiConfigManager.isInFlakyRandomizationSsidHotlist(mTargetNetworkId)) { + mConnectionFailureNotifier + .showFailedToConnectDueToNoRandomizedMacSupportNotification(mTargetNetworkId); + } // if connected, this should be non-null. WifiConfiguration configuration = getCurrentWifiConfiguration(); if (configuration == null) { diff --git a/service/java/com/android/server/wifi/ConnectionFailureNotificationBuilder.java b/service/java/com/android/server/wifi/ConnectionFailureNotificationBuilder.java new file mode 100644 index 000000000..817c55bb1 --- /dev/null +++ b/service/java/com/android/server/wifi/ConnectionFailureNotificationBuilder.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.annotation.NonNull; +import android.app.AlertDialog; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.wifi.WifiConfiguration; +import android.os.Handler; +import android.view.WindowManager; + +import com.android.internal.notification.SystemNotificationChannels; +import com.android.wifi.resources.R; + +/** + * Helper class for ConnectionFailureNotifier. + */ +public class ConnectionFailureNotificationBuilder { + private static final String TAG = "ConnectionFailureNotifier"; + + public static final String ACTION_SHOW_SET_RANDOMIZATION_DETAILS = + "com.android.server.wifi.ACTION_SHOW_SET_RANDOMIZATION_DETAILS"; + public static final String RANDOMIZATION_SETTINGS_NETWORK_ID = + "com.android.server.wifi.RANDOMIZATION_SETTINGS_NETWORK_ID"; + public static final String RANDOMIZATION_SETTINGS_NETWORK_SSID = + "com.android.server.wifi.RANDOMIZATION_SETTINGS_NETWORK_SSID"; + + private Context mContext; + private String mPackageName; + private FrameworkFacade mFrameworkFacade; + private WifiConnectivityManager mWifiConnectivityManager; + private NotificationManager mNotificationManager; + private Handler mHandler; + + public ConnectionFailureNotificationBuilder(Context context, String packageName, + FrameworkFacade framework) { + mContext = context; + mPackageName = packageName; + mFrameworkFacade = framework; + } + + /** + * Creates a notification that alerts the user that the connection may be failing due to + * MAC randomization. + * @param config + */ + public Notification buildNoMacRandomizationSupportNotification( + @NonNull WifiConfiguration config) { + String ssid = config.SSID; + String ssidAndSecurityType = config.getSsidAndSecurityTypeString(); + String title = mContext.getResources().getString( + R.string.wifi_cannot_connect_with_randomized_mac_title, ssid); + String content = mContext.getResources().getString( + R.string.wifi_cannot_connect_with_randomized_mac_message); + + Intent showDetailIntent = new Intent(ACTION_SHOW_SET_RANDOMIZATION_DETAILS) + .setPackage(mPackageName); + showDetailIntent.putExtra(RANDOMIZATION_SETTINGS_NETWORK_ID, config.networkId); + showDetailIntent.putExtra(RANDOMIZATION_SETTINGS_NETWORK_SSID, ssidAndSecurityType); + PendingIntent pendingShowDetailIntent = mFrameworkFacade.getBroadcast( + mContext, 0, showDetailIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + return mFrameworkFacade.makeNotificationBuilder(mContext, + SystemNotificationChannels.NETWORK_ALERTS) + .setSmallIcon(android.R.drawable.stat_notify_wifi_in_range) + .setTicker(title) + .setContentTitle(title) + .setContentText(content) + .setContentIntent(pendingShowDetailIntent) + .setShowWhen(false) + .setLocalOnly(true) + .setColor(mContext.getResources().getColor( + android.R.color.system_notification_accent_color, mContext.getTheme())) + .setAutoCancel(true) + .build(); + } + + /** + * Creates an AlertDialog that allows the user to disable MAC randomization for a network. + * @param ssid the displayed SSID in the dialog + * @param onUserConfirm + */ + public AlertDialog buildChangeMacRandomizationSettingDialog( + String ssid, DialogInterface.OnClickListener onUserConfirm) { + AlertDialog.Builder builder = mFrameworkFacade.makeAlertDialogBuilder(mContext) + .setTitle(mContext.getResources().getString( + R.string.wifi_disable_mac_randomization_dialog_title)) + .setMessage(mContext.getResources().getString( + R.string.wifi_disable_mac_randomization_dialog_message, ssid)) + .setPositiveButton( + mContext.getResources().getString( + R.string.wifi_disable_mac_randomization_dialog_confirm_text), + onUserConfirm) + // A null listener allows the dialog to be dismissed directly. + .setNegativeButton(android.R.string.no, null); + AlertDialog dialog = builder.create(); + dialog.setCanceledOnTouchOutside(false); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + return dialog; + } +} diff --git a/service/java/com/android/server/wifi/ConnectionFailureNotifier.java b/service/java/com/android/server/wifi/ConnectionFailureNotifier.java new file mode 100644 index 000000000..6cdbfed15 --- /dev/null +++ b/service/java/com/android/server/wifi/ConnectionFailureNotifier.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.app.AlertDialog; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.WifiConfiguration; +import android.os.Handler; +import android.os.Process; +import android.util.Log; + +import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; +import com.android.wifi.resources.R; + +/** + * This class may be used to launch notifications when wifi connections fail. + */ +public class ConnectionFailureNotifier { + private static final String TAG = "ConnectionFailureNotifier"; + + private Context mContext; + private WifiInjector mWifiInjector; + private FrameworkFacade mFrameworkFacade; + private WifiConfigManager mWifiConfigManager; + private WifiConnectivityManager mWifiConnectivityManager; + private NotificationManager mNotificationManager; + private Handler mHandler; + private ConnectionFailureNotificationBuilder mConnectionFailureNotificationBuilder; + + public ConnectionFailureNotifier( + Context context, WifiInjector wifiInjector, FrameworkFacade framework, + WifiConfigManager wifiConfigManager, WifiConnectivityManager wifiConnectivityManager, + Handler handler) { + mContext = context; + mWifiInjector = wifiInjector; + mFrameworkFacade = framework; + mWifiConfigManager = wifiConfigManager; + mWifiConnectivityManager = wifiConnectivityManager; + mNotificationManager = mWifiInjector.getNotificationManager(); + mHandler = handler; + mConnectionFailureNotificationBuilder = + mWifiInjector.getConnectionFailureNotificationBuilder(); + + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectionFailureNotificationBuilder + .ACTION_SHOW_SET_RANDOMIZATION_DETAILS); + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(ConnectionFailureNotificationBuilder + .ACTION_SHOW_SET_RANDOMIZATION_DETAILS)) { + int networkId = intent.getIntExtra( + ConnectionFailureNotificationBuilder + .RANDOMIZATION_SETTINGS_NETWORK_ID, + WifiConfiguration.INVALID_NETWORK_ID); + String ssidAndSecurityType = intent.getStringExtra( + ConnectionFailureNotificationBuilder + .RANDOMIZATION_SETTINGS_NETWORK_SSID); + showRandomizationSettingsDialog(networkId, ssidAndSecurityType); + } + } + }, filter); + } + + /** + * Shows a notification which will bring up a dialog which offers the user an option to disable + * MAC randomization on |networkdId|. + * @param networkId + */ + public void showFailedToConnectDueToNoRandomizedMacSupportNotification(int networkId) { + WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId); + if (config == null) { + return; + } + Notification notification = mConnectionFailureNotificationBuilder + .buildNoMacRandomizationSupportNotification(config); + mNotificationManager.notify(SystemMessage.NOTE_NETWORK_NO_MAC_RANDOMIZATION_SUPPORT, + notification); + } + + class DisableMacRandomizationListener implements DialogInterface.OnClickListener { + private WifiConfiguration mConfig; + + DisableMacRandomizationListener(WifiConfiguration config) { + mConfig = config; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + mHandler.post(() -> { + mConfig.macRandomizationSetting = + WifiConfiguration.RANDOMIZATION_NONE; + mWifiConfigManager.addOrUpdateNetwork(mConfig, Process.SYSTEM_UID); + WifiConfiguration updatedConfig = + mWifiConfigManager.getConfiguredNetwork(mConfig.networkId); + if (updatedConfig.macRandomizationSetting + == WifiConfiguration.RANDOMIZATION_NONE) { + String message = mContext.getResources().getString( + R.string.wifi_disable_mac_randomization_dialog_success); + mFrameworkFacade.showToast(mContext, message); + mWifiConfigManager.enableNetwork(updatedConfig.networkId, true, + Process.SYSTEM_UID, null); + mWifiConnectivityManager.forceConnectivityScan( + ClientModeImpl.WIFI_WORK_SOURCE); + } else { + // Shouldn't ever fail, but here for completeness + String message = mContext.getResources().getString( + R.string.wifi_disable_mac_randomization_dialog_failure); + mFrameworkFacade.showToast(mContext, message); + Log.e(TAG, "Failed to modify mac randomization setting"); + } + }); + } + } + + /** + * Class to show a AlertDialog which notifies the user of a network not being privacy + * compliant and then suggests an action. + */ + private void showRandomizationSettingsDialog(int networkId, String ssidAndSecurityType) { + WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId); + // Make sure the networkId is still pointing to the correct WifiConfiguration since + // there might be a large time gap between when the notification shows and when + // it's tapped. + if (config == null || ssidAndSecurityType == null + || !ssidAndSecurityType.equals(config.getSsidAndSecurityTypeString())) { + String message = mContext.getResources().getString( + R.string.wifi_disable_mac_randomization_dialog_network_not_found); + mFrameworkFacade.showToast(mContext, message); + return; + } + + AlertDialog dialog = mConnectionFailureNotificationBuilder + .buildChangeMacRandomizationSettingDialog(config.SSID, + new DisableMacRandomizationListener(config)); + dialog.show(); + } +} diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java index e50981696..67f465081 100644 --- a/service/java/com/android/server/wifi/FrameworkFacade.java +++ b/service/java/com/android/server/wifi/FrameworkFacade.java @@ -19,6 +19,7 @@ package com.android.server.wifi; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; import android.app.ActivityManager; +import android.app.AlertDialog; import android.app.Notification; import android.app.PendingIntent; import android.content.ContentResolver; @@ -34,6 +35,7 @@ import android.os.ServiceManager; import android.provider.Settings; import android.sysprop.WifiProperties; import android.telephony.CarrierConfigManager; +import android.widget.Toast; import com.android.server.wifi.util.WifiAsyncChannel; @@ -228,4 +230,23 @@ public class FrameworkFacade { public void stopSupplicant() { WifiProperties.stop_supplicant(true); } + + /** + * Create a new instance of {@link AlertDialog.Builder}. + * @param context reference to a Context + * @return an instance of AlertDialog.Builder + */ + public AlertDialog.Builder makeAlertDialogBuilder(Context context) { + return new AlertDialog.Builder(context); + } + + /** + * Show a toast message + * @param context reference to a Context + * @param text the message to display + */ + public void showToast(Context context, String text) { + Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT); + toast.show(); + } } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index bd2a435d1..9e2fa6e2d 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AppOpsManager; +import android.app.NotificationManager; import android.content.Context; import android.net.IpMemoryStore; import android.net.NetworkCapabilities; @@ -158,6 +159,7 @@ public class WifiInjector { private final TelephonyUtil mTelephonyUtil; private WifiChannelUtilization mWifiChannelUtilization; private final KeyStore mKeyStore; + private final ConnectionFailureNotificationBuilder mConnectionFailureNotificationBuilder; private final ThroughputPredictor mThroughputPredictor; public WifiInjector(Context context) { @@ -184,6 +186,8 @@ public class WifiInjector { mFrameworkFacade = new FrameworkFacade(); mMacAddressUtil = new MacAddressUtil(); mContext = context; + mConnectionFailureNotificationBuilder = new ConnectionFailureNotificationBuilder( + mContext, getWifiStackPackageName(), mFrameworkFacade); mBatteryStats = context.getSystemService(BatteryStatsManager.class); mWifiScoreCard = new WifiScoreCard(mClock, Secure.getString(mContext.getContentResolver(), Secure.ANDROID_ID)); @@ -620,6 +624,17 @@ public class WifiInjector { } /** + * Construct a new instance of ConnectionFailureNotifier. + * @param wifiConnectivityManager + * @return the created instance + */ + public ConnectionFailureNotifier makeConnectionFailureNotifier( + WifiConnectivityManager wifiConnectivityManager) { + return new ConnectionFailureNotifier(mContext, this, mFrameworkFacade, mWifiConfigManager, + wifiConnectivityManager, new Handler(mWifiHandlerThread.getLooper())); + } + + /** * Construct a new instance of {@link WifiNetworkFactory}. * TODO(b/116233964): Remove cyclic dependency between WifiConnectivityManager & ClientModeImpl. */ @@ -706,6 +721,14 @@ public class WifiInjector { return mMacAddressUtil; } + public NotificationManager getNotificationManager() { + return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + } + + public ConnectionFailureNotificationBuilder getConnectionFailureNotificationBuilder() { + return mConnectionFailureNotificationBuilder; + } + /** * Returns a single instance of HalDeviceManager for injection. */ diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml index 6068474a1..450aa1711 100644 --- a/service/res/values/overlayable.xml +++ b/service/res/values/overlayable.xml @@ -128,6 +128,14 @@ <item type="string" name="wifi_p2p_show_pin_message" /> <item type="string" name="wifi_p2p_frequency_conflict_message" /> <item type="string" name="dlg_ok" /> + <item type="string" name="wifi_cannot_connect_with_randomized_mac_title" /> + <item type="string" name="wifi_cannot_connect_with_randomized_mac_message" /> + <item type="string" name="wifi_disable_mac_randomization_dialog_title" /> + <item type="string" name="wifi_disable_mac_randomization_dialog_message" /> + <item type="string" name="wifi_disable_mac_randomization_dialog_confirm_text" /> + <item type="string" name="wifi_disable_mac_randomization_dialog_success" /> + <item type="string" name="wifi_disable_mac_randomization_dialog_failure" /> + <item type="string" name="wifi_disable_mac_randomization_dialog_network_not_found" /> <!-- Params from strings.xml that can be overlayed --> <!-- Params from styles.xml that can be overlayed --> diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml index 4cb06447f..69f438a6a 100644 --- a/service/res/values/strings.xml +++ b/service/res/values/strings.xml @@ -94,4 +94,15 @@ <!-- Dialog ok button--> <string name="dlg_ok">OK</string> + <!-- Start of string constants used to inform the user that the current network may be failing to connect due to not supporting randomized MAC--> + <string name="wifi_cannot_connect_with_randomized_mac_title">Can\'t connect to <xliff:g id="ssid">%1$s</xliff:g></string> + <string name="wifi_cannot_connect_with_randomized_mac_message">Tap to change privacy settings and retry</string> + <string name="wifi_disable_mac_randomization_dialog_title">Change privacy setting?</string> + <string name="wifi_disable_mac_randomization_dialog_message"><xliff:g id="ssid">%1$s</xliff:g> may want to connect using your device MAC address, a unique identifier. This may allow your device\'s location to be tracked by nearby devices. + \n\nIf you continue, <xliff:g id="ssid">%1$s</xliff:g> will change your privacy setting and try to connect again.</string> + <string name="wifi_disable_mac_randomization_dialog_confirm_text">Change setting</string> + <string name="wifi_disable_mac_randomization_dialog_success">Setting updated. Try Connecting again.</string> + <string name="wifi_disable_mac_randomization_dialog_failure">Can\'t change privacy setting</string> + <string name="wifi_disable_mac_randomization_dialog_network_not_found">Network not found</string> + <!-- End of string constants used to inform the user that the current network may be failing to connect due to not supporting randomized MAC--> </resources> |