summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorxshu <xshu@google.com>2019-11-12 16:04:50 -0800
committerxshu <xshu@google.com>2019-12-10 12:02:54 -0800
commit491c22553879a8d56d761c218177dec6afa80aa9 (patch)
tree7fd89e447f0618ebd9e8ae1d34e14724d5f8d964 /service
parent45448ffb610477fc7ac2406c33276f461288bb91 (diff)
Notification to set MAC randomization setting
Launches a notification, which when tapped will show a dialog that explains to the user why the connection is potentially failing and provides an option to fix the problem by disabling MAC randomization. Bug: 144172117 Test: atest FrameworksWifiTests Test: manaully verified on a device: notification is trigger at the right time, and the dialogue is successfully disabling MAC randomization. Test: verified on device that the fallback path works as expected if the user removes the network before tapping on the notification. Change-Id: Id02c56a96b7cba49880b29518d29f79c76db982c Merged-In: Id02c56a96b7cba49880b29518d29f79c76db982c (cherry picked from 3f656193a2c6d6ae6b6ba81d1450c813ad1cbbb0)
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java14
-rw-r--r--service/java/com/android/server/wifi/ConnectionFailureNotificationBuilder.java123
-rw-r--r--service/java/com/android/server/wifi/ConnectionFailureNotifier.java162
-rw-r--r--service/java/com/android/server/wifi/FrameworkFacade.java21
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java27
5 files changed, 346 insertions, 1 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 119d6d0e8..5cf909695 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -763,6 +763,7 @@ public class ClientModeImpl extends StateMachine {
private WifiStateTracker mWifiStateTracker;
private final BackupManagerProxy mBackupManagerProxy;
private final WrongPasswordNotifier mWrongPasswordNotifier;
+ private final ConnectionFailureNotifier mConnectionFailureNotifier;
private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
private boolean mConnectedMacRandomzationSupported;
// Maximum duration to continue to log Wifi usability stats after a data stall is triggered.
@@ -816,7 +817,8 @@ public class ClientModeImpl extends StateMachine {
mSupplicantStateTracker =
mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
mWifiConnectivityManager = mWifiInjector.makeWifiConnectivityManager(this);
-
+ mConnectionFailureNotifier = mWifiInjector.makeConnectionFailureNotifier(
+ mWifiConnectivityManager);
mLinkProperties = new LinkProperties();
mMcastLockManagerFilterController = new McastLockManagerFilterController();
@@ -3158,6 +3160,16 @@ public class ClientModeImpl extends StateMachine {
mWifiScoreCard.noteConnectionFailure(mWifiInfo,
level2FailureCode, connectivityFailureCode);
}
+ 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..f4f89f09e
--- /dev/null
+++ b/service/java/com/android/server/wifi/ConnectionFailureNotificationBuilder.java
@@ -0,0 +1,123 @@
+/*
+ * 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.content.res.Resources;
+import android.net.wifi.WifiConfiguration;
+import android.os.Handler;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
+
+/**
+ * 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 Resources mResources;
+ private FrameworkFacade mFrameworkFacade;
+ private WifiConnectivityManager mWifiConnectivityManager;
+ private NotificationManager mNotificationManager;
+ private Handler mHandler;
+
+ public ConnectionFailureNotificationBuilder(Context context, String packageName,
+ FrameworkFacade framework) {
+ mContext = context;
+ mPackageName = packageName;
+ mResources = context.getResources();
+ 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 = mResources.getString(
+ R.string.wifi_cannot_connect_with_randomized_mac_title, ssid);
+ String content = mResources.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(R.drawable.stat_notify_wifi_in_range)
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setContentIntent(pendingShowDetailIntent)
+ .setShowWhen(false)
+ .setLocalOnly(true)
+ .setColor(mResources.getColor(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(mResources.getString(
+ R.string.wifi_disable_mac_randomization_dialog_title))
+ .setMessage(mResources.getString(
+ R.string.wifi_disable_mac_randomization_dialog_message, ssid))
+ .setPositiveButton(
+ mResources.getString(
+ R.string.wifi_disable_mac_randomization_dialog_confirm_text),
+ onUserConfirm)
+ // A null listener allows the dialog to be dismissed directly.
+ .setNegativeButton(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..bbef2ff6e
--- /dev/null
+++ b/service/java/com/android/server/wifi/ConnectionFailureNotifier.java
@@ -0,0 +1,162 @@
+/*
+ * 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.content.res.Resources;
+import android.net.wifi.WifiConfiguration;
+import android.os.Handler;
+import android.os.Process;
+import android.util.Log;
+
+import com.android.internal.R;
+
+/**
+ * This class may be used to launch notifications when wifi connections fail.
+ */
+public class ConnectionFailureNotifier {
+ private static final String TAG = "ConnectionFailureNotifier";
+ public static final int NO_RANDOMIZED_MAC_SUPPORT_NOTIFICATION_ID = 123;
+
+ private Context mContext;
+ private WifiInjector mWifiInjector;
+ private Resources mResources;
+ 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;
+ mResources = context.getResources();
+ 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(NO_RANDOMIZED_MAC_SUPPORT_NOTIFICATION_ID, 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 = mResources.getString(
+ R.string.wifi_disable_mac_randomization_dialog_success);
+ mFrameworkFacade.showToast(mContext, message);
+ mWifiConfigManager.enableNetwork(updatedConfig.networkId, true,
+ Process.SYSTEM_UID);
+ mWifiConnectivityManager.forceConnectivityScan(
+ ClientModeImpl.WIFI_WORK_SOURCE);
+ } else {
+ // Shouldn't ever fail, but here for completeness
+ String message = mResources.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 = mResources.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 4fbe31867..fe3027e50 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -17,6 +17,7 @@
package com.android.server.wifi;
import android.app.ActivityManagerInternal;
+import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.Notification;
import android.app.PendingIntent;
@@ -35,6 +36,7 @@ import android.os.ServiceManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
+import android.widget.Toast;
import com.android.internal.app.IBatteryStats;
import com.android.server.LocalServices;
@@ -227,4 +229,23 @@ public class FrameworkFacade {
public Notification.Builder makeNotificationBuilder(Context context, String channelId) {
return new Notification.Builder(context, channelId);
}
+
+ /**
+ * 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 af8c14764..339e169f6 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.content.pm.PackageManager;
import android.hardware.SystemSensorManager;
@@ -155,6 +156,7 @@ public class WifiInjector {
private final IpMemoryStore mIpMemoryStore;
private final CellularLinkLayerStatsCollector mCellularLinkLayerStatsCollector;
private final MacAddressUtil mMacAddressUtil;
+ private final ConnectionFailureNotificationBuilder mConnectionFailureNotificationBuilder;
public WifiInjector(Context context) {
if (context == null) {
@@ -172,6 +174,8 @@ public class WifiInjector {
mMacAddressUtil = new MacAddressUtil();
mContext = context;
mDeviceConfigFacade = new DeviceConfigFacade();
+ mConnectionFailureNotificationBuilder = new ConnectionFailureNotificationBuilder(
+ mContext, getWifiStackPackageName(), mFrameworkFacade);
mWifiScoreCard = new WifiScoreCard(mClock,
Secure.getString(mContext.getContentResolver(), Secure.ANDROID_ID));
mSettingsStore = new WifiSettingsStore(mContext);
@@ -623,6 +627,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(mWifiCoreHandlerThread.getLooper()));
+ }
+
+ /**
* Construct a new instance of {@link WifiNetworkFactory}.
* TODO(b/116233964): Remove cyclic dependency between WifiConnectivityManager & ClientModeImpl.
*/
@@ -701,6 +716,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.
*/
@@ -759,4 +782,8 @@ public class WifiInjector {
public HostapdHal getHostapdHal() {
return mHostapdHal;
}
+
+ public String getWifiStackPackageName() {
+ return mContext.getPackageName();
+ }
}