summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNate(Qiang) Jiang <qiangjiang@google.com>2020-01-10 09:13:34 -0800
committerNate(Qiang) Jiang <qiangjiang@google.com>2020-01-29 09:30:18 -0800
commitc7668957e0944b894a8e8ddbbc17f09beba9fcdf (patch)
treef9debd0df6838a1f4697f8abcceadf96382aa9df
parente44c5c010c744aeabd78eb3621cc37184606a284 (diff)
IMSI protection notification
When a SIM-based network in the range, if it has no IMSI privacy protection, will send a notifiction to user. If user allow exemption, this network will be considered auto connect next time. Bug: 142001564 Test: atest com.android.server.wifi Change-Id: If94893eb9d6b11abafa197a83c4f3d5f0245f973
-rw-r--r--service/java/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreData.java179
-rw-r--r--service/java/com/android/server/wifi/NetworkSuggestionNominator.java60
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java10
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java322
-rw-r--r--service/java/com/android/server/wifi/WifiShellCommand.java63
-rw-r--r--service/java/com/android/server/wifi/util/TelephonyUtil.java16
-rw-r--r--service/res/values/overlayable.xml4
-rw-r--r--service/res/values/strings.xml9
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreDataTest.java121
-rw-r--r--tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java102
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java267
-rw-r--r--tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java12
12 files changed, 999 insertions, 166 deletions
diff --git a/service/java/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreData.java b/service/java/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreData.java
new file mode 100644
index 000000000..acfba80c5
--- /dev/null
+++ b/service/java/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreData.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2020 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.annotation.Nullable;
+import android.util.Log;
+
+import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
+import com.android.server.wifi.util.XmlUtil;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class performs serialization and parsing of XML data block that contain the map of IMSI
+ * protection exemption user approval info.
+ */
+public class ImsiPrivacyProtectionExemptionStoreData implements WifiConfigStore.StoreData {
+ private static final String TAG = "ImsiPrivacyProtectionExemptionStoreData";
+ private static final String XML_TAG_SECTION_HEADER_IMSI_PROTECTION_EXEMPTION_CARRIER_MAP =
+ "ImsiPrivacyProtectionExemptionMap";
+ private static final String XML_TAG_CARRIER_EXEMPTION_MAP = "CarrierExemptionMap";
+
+ /**
+ * Interface define the data source for the carrier IMSI protection exemption map store data.
+ */
+ public interface DataSource {
+ /**
+ * Retrieve the IMSI protection exemption map from the data source to serialize to disk.
+ *
+ * @return Map of carrier Id to if allowed.
+ */
+ Map<Integer, Boolean> toSerialize();
+
+ /**
+ * Set the IMSI protection exemption map in the data source after serializing them from disk
+ *
+ * @param imsiProtectionExemptionMap Map of carrier Id to allowed or not.
+ */
+ void fromDeserialized(Map<Integer, Boolean> imsiProtectionExemptionMap);
+
+ /**
+ * Clear internal data structure in preparation for user switch or initial store read.
+ */
+ void reset();
+
+ /**
+ * Indicates whether there is new data to serialize.
+ */
+ boolean hasNewDataToSerialize();
+ }
+
+ private final DataSource mDataSource;
+
+ /**
+ * Set the data source fot store data.
+ */
+ public ImsiPrivacyProtectionExemptionStoreData(@NonNull DataSource dataSource) {
+ mDataSource = dataSource;
+ }
+
+ @Override
+ public void serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil)
+ throws XmlPullParserException, IOException {
+ Map<String, Boolean> dataToSerialize = integerMapToStringMap(mDataSource.toSerialize());
+ XmlUtil.writeNextValue(out, XML_TAG_CARRIER_EXEMPTION_MAP, dataToSerialize);
+ }
+
+ @Override
+ public void deserializeData(XmlPullParser in, int outerTagDepth, int version,
+ WifiConfigStoreEncryptionUtil encryptionUtil)
+ throws XmlPullParserException, IOException {
+ // Ignore empty reads.
+ if (in == null) {
+ return;
+ }
+
+ mDataSource.fromDeserialized(parseCarrierImsiProtectionExemptionMap(in, outerTagDepth,
+ version, encryptionUtil));
+
+ }
+
+ private Map<Integer, Boolean> parseCarrierImsiProtectionExemptionMap(XmlPullParser in,
+ int outerTagDepth,
+ @WifiConfigStore.Version int version,
+ @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
+ throws XmlPullParserException, IOException {
+ Map<String, Boolean> protectionExemptionMap = new HashMap<>();
+ while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
+ String[] valueName = new String[1];
+ Object value = XmlUtil.readCurrentValue(in, valueName);
+ if (valueName[0] == null) {
+ throw new XmlPullParserException("Missing value name");
+ }
+ switch (valueName[0]) {
+ case XML_TAG_CARRIER_EXEMPTION_MAP:
+ if (value instanceof Map) {
+ protectionExemptionMap = (Map<String, Boolean>) value;
+ }
+ break;
+ default:
+ Log.w(TAG, "Unknown tag under "
+ + XML_TAG_SECTION_HEADER_IMSI_PROTECTION_EXEMPTION_CARRIER_MAP
+ + ": " + valueName[0]);
+ break;
+ }
+ }
+ return stringMapToIntegerMap(protectionExemptionMap);
+ }
+
+ private Map<String, Boolean> integerMapToStringMap(Map<Integer, Boolean> input) {
+ Map<String, Boolean> output = new HashMap<>();
+ if (input == null) {
+ return output;
+ }
+ for (Map.Entry<Integer, Boolean> entry : input.entrySet()) {
+ output.put(Integer.toString(entry.getKey()), entry.getValue());
+ }
+ return output;
+ }
+
+ private Map<Integer, Boolean> stringMapToIntegerMap(Map<String, Boolean> input) {
+ Map<Integer, Boolean> output = new HashMap<>();
+ if (input == null) {
+ return output;
+ }
+ for (Map.Entry<String, Boolean> entry : input.entrySet()) {
+ try {
+ output.put(Integer.valueOf(entry.getKey()), entry.getValue());
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Failed to Integer convert: " + entry.getKey());
+ }
+ }
+ return output;
+ }
+
+
+ @Override
+ public void resetData() {
+ mDataSource.reset();
+ }
+
+ @Override
+ public boolean hasNewDataToSerialize() {
+ return mDataSource.hasNewDataToSerialize();
+ }
+
+ @Override
+ public String getName() {
+ return XML_TAG_SECTION_HEADER_IMSI_PROTECTION_EXEMPTION_CARRIER_MAP;
+ }
+
+ @Override
+ public int getStoreFileId() {
+ // Suggestion Store.
+ return WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS;
+ }
+
+}
diff --git a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
index d7d08578f..281791631 100644
--- a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
+++ b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
@@ -25,6 +25,7 @@ import android.util.Pair;
import com.android.server.wifi.WifiNetworkSuggestionsManager.ExtendedWifiNetworkSuggestion;
import com.android.server.wifi.hotspot2.PasspointNetworkNominateHelper;
import com.android.server.wifi.util.ScanResultUtil;
+import com.android.server.wifi.util.TelephonyUtil;
import java.util.ArrayList;
import java.util.Arrays;
@@ -54,14 +55,16 @@ public class NetworkSuggestionNominator implements WifiNetworkSelector.NetworkNo
private final WifiConfigManager mWifiConfigManager;
private final PasspointNetworkNominateHelper mPasspointNetworkNominateHelper;
private final LocalLog mLocalLog;
+ private final TelephonyUtil mTelephonyUtil;
NetworkSuggestionNominator(WifiNetworkSuggestionsManager networkSuggestionsManager,
WifiConfigManager wifiConfigManager, PasspointNetworkNominateHelper nominateHelper,
- LocalLog localLog) {
+ LocalLog localLog, TelephonyUtil telephonyUtil) {
mWifiNetworkSuggestionsManager = networkSuggestionsManager;
mWifiConfigManager = wifiConfigManager;
mPasspointNetworkNominateHelper = nominateHelper;
mLocalLog = localLog;
+ mTelephonyUtil = telephonyUtil;
}
@Override
@@ -117,6 +120,9 @@ public class NetworkSuggestionNominator implements WifiNetworkSelector.NetworkNo
if (autoJoinEnabledExtSuggestions.isEmpty()) {
continue;
}
+ if (!isSimBasedNetworkAvailableToAutoConnect(candidate.second)) {
+ continue;
+ }
matchMetaInfo.putAll(autoJoinEnabledExtSuggestions,
candidate.second, candidate.first);
}
@@ -131,14 +137,15 @@ public class NetworkSuggestionNominator implements WifiNetworkSelector.NetworkNo
if (matchingExtNetworkSuggestions == null || matchingExtNetworkSuggestions.isEmpty()) {
continue;
}
- Set<ExtendedWifiNetworkSuggestion> autojoinEnableSuggestions =
- matchingExtNetworkSuggestions.stream()
- .filter(ewns -> ewns.isAutoJoinEnabled)
- .collect(Collectors.toSet());
- autoJoinDisabledSuggestions.addAll(
- matchingExtNetworkSuggestions.stream()
- .filter(ewns -> !ewns.isAutoJoinEnabled)
- .collect(Collectors.toSet()));
+ Set<ExtendedWifiNetworkSuggestion> autojoinEnableSuggestions = new HashSet<>();
+ for (ExtendedWifiNetworkSuggestion ewns : matchingExtNetworkSuggestions) {
+ if (ewns.isAutoJoinEnabled
+ && isSimBasedNetworkAvailableToAutoConnect(ewns.wns.wifiConfiguration)) {
+ autojoinEnableSuggestions.add(ewns);
+ } else {
+ autoJoinDisabledSuggestions.add(ewns);
+ }
+ }
if (autojoinEnableSuggestions.isEmpty()) {
continue;
@@ -147,19 +154,29 @@ public class NetworkSuggestionNominator implements WifiNetworkSelector.NetworkNo
// them to lookup/add the credentials to WifiConfigManager.
// Note: Apps could provide different credentials (password, ceritificate) for the same
// network, need to handle that in the future.
- ExtendedWifiNetworkSuggestion matchingExtNetworkSuggestion =
- autojoinEnableSuggestions.stream().findAny().get();
+ String configKey = autojoinEnableSuggestions.stream().findAny().get()
+ .wns.wifiConfiguration.getKey();
// Check if we already have a network with the same credentials in WifiConfigManager
// database.
WifiConfiguration wCmConfiguredNetwork =
- mWifiConfigManager.getConfiguredNetwork(
- matchingExtNetworkSuggestion.wns.wifiConfiguration.getKey());
+ mWifiConfigManager.getConfiguredNetwork(configKey);
if (wCmConfiguredNetwork != null) {
// If existing network is not from suggestion, ignore.
if (!(wCmConfiguredNetwork.fromWifiNetworkSuggestion
&& wCmConfiguredNetwork.allowAutojoin)) {
continue;
}
+ int creatorUid = wCmConfiguredNetwork.creatorUid;
+ Set<ExtendedWifiNetworkSuggestion> matchingExtNetworkSuggestionsFromSamePackage =
+ autojoinEnableSuggestions.stream()
+ .filter(ewns -> ewns.wns.wifiConfiguration.creatorUid
+ == creatorUid)
+ .collect(Collectors.toSet());
+ if (matchingExtNetworkSuggestionsFromSamePackage.isEmpty()) {
+ continue;
+ }
+ ExtendedWifiNetworkSuggestion matchingExtNetworkSuggestion =
+ matchingExtNetworkSuggestionsFromSamePackage.stream().findFirst().get();
// Update the WifiConfigManager with the latest WifiConfig
WifiConfiguration config = createConfigForAddingToWifiConfigManager(
matchingExtNetworkSuggestion, true);
@@ -178,11 +195,28 @@ public class NetworkSuggestionNominator implements WifiNetworkSelector.NetworkNo
+ WifiNetworkSelector.toNetworkString(wCmConfiguredNetwork));
continue;
}
+ matchingExtNetworkSuggestions = matchingExtNetworkSuggestionsFromSamePackage;
}
matchMetaInfo.putAll(matchingExtNetworkSuggestions, wCmConfiguredNetwork, scanDetail);
}
}
+ private boolean isSimBasedNetworkAvailableToAutoConnect(WifiConfiguration config) {
+ if (config.enterpriseConfig == null
+ || !config.enterpriseConfig.isAuthenticationSimBased()) {
+ return true;
+ }
+ int subId = mTelephonyUtil.getBestMatchSubscriptionId(config);
+ if (!mTelephonyUtil.isSimPresent(subId)) {
+ mLocalLog.log("SIM is not present for subId: " + subId);
+ return false;
+ }
+ if (mTelephonyUtil.requiresImsiEncryption(subId)) {
+ return mTelephonyUtil.isImsiEncryptionInfoAvailable(subId);
+ }
+ return true;
+ }
+
// Add auto-join disabled suggestions also to WifiConfigManager if the app allows credential
// sharing.This will surface these networks on the UI, to allow the user manually connect to it.
private void addAutojoinDisabledSuggestionToWifiConfigManager(
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 4c6c67068..fdcbb2b10 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -294,7 +294,7 @@ public class WifiInjector {
mSavedNetworkNominator = new SavedNetworkNominator(
mWifiConfigManager, nominateHelper, mConnectivityLocalLog, mTelephonyUtil);
mNetworkSuggestionNominator = new NetworkSuggestionNominator(mWifiNetworkSuggestionsManager,
- mWifiConfigManager, nominateHelper, mConnectivityLocalLog);
+ mWifiConfigManager, nominateHelper, mConnectivityLocalLog, mTelephonyUtil);
mScoredNetworkNominator = new ScoredNetworkNominator(mContext, wifiHandler,
mFrameworkFacade, mNetworkScoreManager, mContext.getPackageManager(),
mWifiConfigManager, mConnectivityLocalLog,
@@ -652,6 +652,14 @@ public class WifiInjector {
}
/**
+ *
+ */
+ public ImsiPrivacyProtectionExemptionStoreData makeImsiProtectionExemptionStoreData(
+ ImsiPrivacyProtectionExemptionStoreData.DataSource dataSource) {
+ return new ImsiPrivacyProtectionExemptionStoreData(dataSource);
+ }
+
+ /**
* Construct an instance of {@link SoftApStoreData}.
*/
public SoftApStoreData makeSoftApStoreData(
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index 4ae1378ae..00ac1b34c 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -47,7 +47,6 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -102,6 +101,23 @@ public class WifiNetworkSuggestionsManager {
@VisibleForTesting
public static final String EXTRA_UID =
"com.android.server.wifi.extra.NetworkSuggestion.UID";
+
+ @VisibleForTesting
+ public static final String EXTRA_CARRIER_NAME =
+ "com.android.server.wifi.extra.NetworkSuggestion.CARRIER_NAME";
+ @VisibleForTesting
+ public static final String EXTRA_CARRIER_ID =
+ "com.android.server.wifi.extra.NetworkSuggestion.CARRIER_ID";
+
+ /** Intent when user tapped action button to allow the app. */
+ @VisibleForTesting
+ public static final String NOTIFICATION_USER_ALLOWED_CARRIER_INTENT_ACTION =
+ "com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_CARRIER";
+ /** Intent when user tapped action button to disallow the app. */
+ @VisibleForTesting
+ public static final String NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION =
+ "com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_CARRIER";
+
/**
* Limit number of hidden networks attach to scan
*/
@@ -295,6 +311,8 @@ public class WifiNetworkSuggestionsManager {
private final HashMap<String, ExternalCallbackTracker<ISuggestionConnectionStatusListener>>
mSuggestionStatusListenerPerApp = new HashMap<>();
+ private final Map<Integer, Boolean> mImsiPrivacyProtectionExemptionMap = new HashMap<>();
+
/**
* Intent filter for processing notification actions.
*/
@@ -403,27 +421,61 @@ public class WifiNetworkSuggestionsManager {
}
}
+ /**
+ * Module to interact with the wifi config store.
+ */
+ private class ImsiProtectionExemptionDataSource implements
+ ImsiPrivacyProtectionExemptionStoreData.DataSource {
+ @Override
+ public Map<Integer, Boolean> toSerialize() {
+ // Clear the flag after writing to disk.
+ // TODO(b/115504887): Don't reset the flag on write failure.
+ mHasNewDataToSerialize = false;
+ return mImsiPrivacyProtectionExemptionMap;
+ }
+
+ @Override
+ public void fromDeserialized(Map<Integer, Boolean> imsiProtectionExemptionMap) {
+ mImsiPrivacyProtectionExemptionMap.putAll(imsiProtectionExemptionMap);
+ }
+
+ @Override
+ public void reset() {
+ mImsiPrivacyProtectionExemptionMap.clear();
+ }
+
+ @Override
+ public boolean hasNewDataToSerialize() {
+ return mHasNewDataToSerialize;
+ }
+ }
+
+
+
private final BroadcastReceiver mBroadcastReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
- if (packageName == null) {
- Log.e(TAG, "No package name found in intent");
- return;
- }
+ String carrierName = intent.getStringExtra(EXTRA_CARRIER_NAME);
int uid = intent.getIntExtra(EXTRA_UID, -1);
- if (uid == -1) {
- Log.e(TAG, "No uid found in intent");
- return;
- }
+ int carrierId = intent.getIntExtra(EXTRA_CARRIER_ID, -1);
+
switch (intent.getAction()) {
case NOTIFICATION_USER_ALLOWED_APP_INTENT_ACTION:
+ if (packageName == null || uid == -1) {
+ Log.e(TAG, "No package name or uid found in intent");
+ return;
+ }
Log.i(TAG, "User clicked to allow app");
// Set the user approved flag.
setHasUserApprovedForApp(true, packageName);
break;
case NOTIFICATION_USER_DISALLOWED_APP_INTENT_ACTION:
+ if (packageName == null || uid == -1) {
+ Log.e(TAG, "No package name or uid found in intent");
+ return;
+ }
Log.i(TAG, "User clicked to disallow app");
// Set the user approved flag.
setHasUserApprovedForApp(false, packageName);
@@ -431,6 +483,22 @@ public class WifiNetworkSuggestionsManager {
mAppOps.setMode(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, uid, packageName,
MODE_IGNORED);
break;
+ case NOTIFICATION_USER_ALLOWED_CARRIER_INTENT_ACTION:
+ if (carrierName == null || carrierId == -1) {
+ Log.e(TAG, "No carrier name or carrier id found in intent");
+ return;
+ }
+ Log.i(TAG, "User clicked to allow carrier");
+ setHasUserApprovedImsiPrivacyExemptionForCarrier(true, carrierId);
+ break;
+ case NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION:
+ if (carrierName == null || carrierId == -1) {
+ Log.e(TAG, "No carrier name or carrier id found in intent");
+ return;
+ }
+ Log.i(TAG, "User clicked to disallow carrier");
+ setHasUserApprovedImsiPrivacyExemptionForCarrier(false, carrierId);
+ break;
case NOTIFICATION_USER_DISMISSED_INTENT_ACTION:
Log.i(TAG, "User dismissed the notification");
mUserApprovalNotificationActive = false;
@@ -469,12 +537,17 @@ public class WifiNetworkSuggestionsManager {
// register the data store for serializing/deserializing data.
wifiConfigStore.registerStoreData(
wifiInjector.makeNetworkSuggestionStoreData(new NetworkSuggestionDataSource()));
+ wifiConfigStore.registerStoreData(wifiInjector.makeImsiProtectionExemptionStoreData(
+ new ImsiProtectionExemptionDataSource()));
// Register broadcast receiver for UI interactions.
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(NOTIFICATION_USER_ALLOWED_APP_INTENT_ACTION);
mIntentFilter.addAction(NOTIFICATION_USER_DISALLOWED_APP_INTENT_ACTION);
mIntentFilter.addAction(NOTIFICATION_USER_DISMISSED_INTENT_ACTION);
+ mIntentFilter.addAction(NOTIFICATION_USER_ALLOWED_CARRIER_INTENT_ACTION);
+ mIntentFilter.addAction(NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION);
+
mContext.registerReceiver(mBroadcastReceiver, mIntentFilter);
}
@@ -709,6 +782,7 @@ public class WifiNetworkSuggestionsManager {
// Start tracking app-op changes from the app if they have active suggestions.
startTrackingAppOpsChange(packageName, uid);
}
+
for (ExtendedWifiNetworkSuggestion ewns: extNetworkSuggestions) {
if (ewns.wns.passpointConfiguration == null) {
if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
@@ -729,6 +803,16 @@ public class WifiNetworkSuggestionsManager {
}
addToPasspointInfoMap(ewns);
}
+ // If network has no IMSI protection and user didn't approve exemption, make it initial
+ // auto join disabled
+ if (isSimBasedSuggestion(ewns)) {
+ int subId = mTelephonyUtil.getMatchingSubId(getCarrierIdFromSuggestion(ewns));
+ if (!(mTelephonyUtil.requiresImsiEncryption(subId)
+ || hasUserApprovedImsiPrivacyExemptionForCarrier(
+ getCarrierIdFromSuggestion(ewns)))) {
+ ewns.isAutoJoinEnabled = false;
+ }
+ }
perAppInfo.extNetworkSuggestions.remove(ewns);
perAppInfo.extNetworkSuggestions.add(ewns);
}
@@ -740,6 +824,22 @@ public class WifiNetworkSuggestionsManager {
return WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
}
+ private int getCarrierIdFromSuggestion(ExtendedWifiNetworkSuggestion ewns) {
+ if (ewns.wns.passpointConfiguration == null) {
+ return ewns.wns.wifiConfiguration.carrierId;
+ }
+ return ewns.wns.passpointConfiguration.getCarrierId();
+ }
+
+ private boolean isSimBasedSuggestion(ExtendedWifiNetworkSuggestion ewns) {
+ if (ewns.wns.passpointConfiguration == null) {
+ return ewns.wns.wifiConfiguration.enterpriseConfig != null
+ && ewns.wns.wifiConfiguration.enterpriseConfig.isAuthenticationSimBased();
+ } else {
+ return ewns.wns.passpointConfiguration.getCredential().getSimCredential() != null;
+ }
+ }
+
private boolean validateNetworkSuggestions(List<WifiNetworkSuggestion> networkSuggestions) {
for (WifiNetworkSuggestion wns : networkSuggestions) {
if (wns.passpointConfiguration == null) {
@@ -900,7 +1000,6 @@ public class WifiNetworkSuggestionsManager {
return networkSuggestionList;
}
-
/**
* Clear all internal state (for network settings reset).
*/
@@ -913,6 +1012,7 @@ public class WifiNetworkSuggestionsManager {
iter.remove();
}
mSuggestionStatusListenerPerApp.clear();
+ mImsiPrivacyProtectionExemptionMap.clear();
saveToStore();
Log.i(TAG, "Cleared all internal state");
}
@@ -935,13 +1035,60 @@ public class WifiNetworkSuggestionsManager {
if (perAppInfo == null) return;
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "Setting the app " + (approved ? "approved" : "not approved"));
+ Log.v(TAG, "Setting the app " + packageName
+ + (approved ? " approved" : " not approved"));
}
perAppInfo.hasUserApproved = approved;
saveToStore();
}
/**
+ * Clear the Imsi Privacy Exemption user approval info the target carrier.
+ */
+ public void clearImsiPrivacyExemptionForCarrier(int carrierId) {
+ mImsiPrivacyProtectionExemptionMap.remove(carrierId);
+ saveToStore();
+ }
+
+ /**
+ * Check if carrier have user approved exemption for IMSI protection
+ */
+ public boolean hasUserApprovedImsiPrivacyExemptionForCarrier(int carrierId) {
+ return mImsiPrivacyProtectionExemptionMap.getOrDefault(carrierId, false);
+ }
+
+ /**
+ * Enable or disable exemption on IMSI protection.
+ */
+ public void setHasUserApprovedImsiPrivacyExemptionForCarrier(boolean approved, int carrierId) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Setting Imsi privacy exemption for carrier " + carrierId
+ + (approved ? " approved" : " not approved"));
+ }
+ mImsiPrivacyProtectionExemptionMap.put(carrierId, approved);
+ // If user approved the exemption restore to initial auto join configure.
+ if (approved) {
+ restoreInitialAutojoinForCarrierId(carrierId);
+ }
+ saveToStore();
+ }
+
+ /**
+ * When user approve the IMSI protection exemption for carrier, restore the initial auto join
+ * configure. If user already change it to enabled, keep that choice.
+ */
+ private void restoreInitialAutojoinForCarrierId(int carrierId) {
+ for (PerAppInfo appInfo : mActiveNetworkSuggestionsPerApp.values()) {
+ for (ExtendedWifiNetworkSuggestion ewns : appInfo.extNetworkSuggestions) {
+ if (isSimBasedSuggestion(ewns)
+ && getCarrierIdFromSuggestion(ewns) == carrierId) {
+ ewns.isAutoJoinEnabled |= ewns.wns.isInitialAutoJoinEnabled;
+ }
+ }
+ }
+ }
+
+ /**
* Returns a set of all network suggestions across all apps.
*/
@VisibleForTesting
@@ -960,12 +1107,12 @@ public class WifiNetworkSuggestionsManager {
.collect(Collectors.toList());
}
- private PendingIntent getPrivateBroadcast(@NonNull String action, @NonNull String packageName,
- int uid) {
+ private PendingIntent getPrivateBroadcast(@NonNull String action,
+ @NonNull Pair<String, String> extra1, @NonNull Pair<String, Integer> extra2) {
Intent intent = new Intent(action)
.setPackage(mWifiInjector.getWifiStackPackageName())
- .putExtra(EXTRA_PACKAGE_NAME, packageName)
- .putExtra(EXTRA_UID, uid);
+ .putExtra(extra1.first, extra1.second)
+ .putExtra(extra2.first, extra2.second);
return mFrameworkFacade.getBroadcast(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
@@ -988,13 +1135,15 @@ public class WifiNetworkSuggestionsManager {
new Notification.Action.Builder(null,
mResources.getText(R.string.wifi_suggestion_action_allow_app),
getPrivateBroadcast(NOTIFICATION_USER_ALLOWED_APP_INTENT_ACTION,
- packageName, uid))
+ Pair.create(EXTRA_PACKAGE_NAME, packageName),
+ Pair.create(EXTRA_UID, uid)))
.build();
Notification.Action userDisallowAppNotificationAction =
new Notification.Action.Builder(null,
mResources.getText(R.string.wifi_suggestion_action_disallow_app),
getPrivateBroadcast(NOTIFICATION_USER_DISALLOWED_APP_INTENT_ACTION,
- packageName, uid))
+ Pair.create(EXTRA_PACKAGE_NAME, packageName),
+ Pair.create(EXTRA_UID, uid)))
.build();
CharSequence appName = getAppName(packageName, uid);
@@ -1007,7 +1156,7 @@ public class WifiNetworkSuggestionsManager {
.setStyle(new Notification.BigTextStyle()
.bigText(mResources.getString(R.string.wifi_suggestion_content, appName)))
.setDeleteIntent(getPrivateBroadcast(NOTIFICATION_USER_DISMISSED_INTENT_ACTION,
- packageName, uid))
+ Pair.create(EXTRA_PACKAGE_NAME, packageName), Pair.create(EXTRA_UID, uid)))
.setShowWhen(false)
.setLocalOnly(true)
.setColor(mResources.getColor(android.R.color.system_notification_accent_color,
@@ -1023,6 +1172,50 @@ public class WifiNetworkSuggestionsManager {
mUserApprovalNotificationPackageName = packageName;
}
+ private void sendImsiPrivacyNotification(@NonNull String carrierName, int carrierId) {
+ Notification.Action userAllowAppNotificationAction =
+ new Notification.Action.Builder(null,
+ mResources.getText(R.string
+ .wifi_suggestion_action_allow_imsi_privacy_exemption_carrier),
+ getPrivateBroadcast(NOTIFICATION_USER_ALLOWED_CARRIER_INTENT_ACTION,
+ Pair.create(EXTRA_CARRIER_NAME, carrierName),
+ Pair.create(EXTRA_CARRIER_ID, carrierId)))
+ .build();
+ Notification.Action userDisallowAppNotificationAction =
+ new Notification.Action.Builder(null,
+ mResources.getText(R.string
+ .wifi_suggestion_action_disallow_imsi_privacy_exemption_carrier),
+ getPrivateBroadcast(NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION,
+ Pair.create(EXTRA_CARRIER_NAME, carrierName),
+ Pair.create(EXTRA_CARRIER_ID, carrierId)))
+ .build();
+
+ Notification notification = new Notification.Builder(
+ mContext, WifiService.NOTIFICATION_NETWORK_STATUS)
+ .setSmallIcon(Icon.createWithResource(WifiContext.WIFI_OVERLAY_APK_PKG_NAME,
+ com.android.wifi.resources.R.drawable.stat_notify_wifi_in_range))
+ .setTicker(mResources.getString(R.string.wifi_suggestion_imsi_privacy_title))
+ .setContentTitle(mResources.getString(R.string.wifi_suggestion_imsi_privacy_title))
+ .setStyle(new Notification.BigTextStyle()
+ .bigText(mResources.getString(R.string.wifi_suggestion_imsi_privacy_content,
+ carrierName)))
+ .setDeleteIntent(getPrivateBroadcast(NOTIFICATION_USER_DISMISSED_INTENT_ACTION,
+ Pair.create(EXTRA_CARRIER_NAME, carrierName),
+ Pair.create(EXTRA_CARRIER_ID, carrierId)))
+ .setShowWhen(false)
+ .setLocalOnly(true)
+ .setColor(mResources.getColor(android.R.color.system_notification_accent_color,
+ mContext.getTheme()))
+ .addAction(userAllowAppNotificationAction)
+ .addAction(userDisallowAppNotificationAction)
+ .build();
+
+ // Post the notification.
+ mNotificationManager.notify(
+ SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE, notification);
+ mUserApprovalNotificationActive = true;
+ }
+
/**
* Send user approval notification if the app is not approved
* @param packageName app package name
@@ -1047,6 +1240,24 @@ public class WifiNetworkSuggestionsManager {
return true;
}
+ /**
+ * Send notification for exemption of IMSI protection if user never made choice before.
+ */
+ private void sendImsiProtectionExemptionNotificationIfRequired(int carrierId) {
+ int subId = mTelephonyUtil.getMatchingSubId(carrierId);
+ if (mTelephonyUtil.requiresImsiEncryption(subId)) {
+ return;
+ }
+ if (mImsiPrivacyProtectionExemptionMap.containsKey(carrierId)) {
+ return;
+ }
+ if (mUserApprovalNotificationActive) {
+ return;
+ }
+ Log.i(TAG, "Sending IMSI protection notification for " + carrierId);
+ sendImsiPrivacyNotification(mTelephonyUtil.getCarrierNameforSubId(subId), carrierId);
+ }
+
private @Nullable Set<ExtendedWifiNetworkSuggestion>
getNetworkSuggestionsForScanResultMatchInfo(
@NonNull ScanResultMatchInfo scanResultMatchInfo, @Nullable MacAddress bssid) {
@@ -1089,9 +1300,17 @@ public class WifiNetworkSuggestionsManager {
}
Set<ExtendedWifiNetworkSuggestion> approvedExtNetworkSuggestions = new HashSet<>();
for (ExtendedWifiNetworkSuggestion ewns : extNetworkSuggestions) {
- if (isNetworkSuggestionUserApprovedAndAvailableToConnect(ewns)) {
- approvedExtNetworkSuggestions.add(ewns);
+ if (!ewns.perAppInfo.hasUserApproved
+ && ewns.perAppInfo.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
+ sendUserApprovalNotificationIfNotApproved(ewns.perAppInfo.packageName,
+ ewns.perAppInfo.uid);
+ continue;
+ }
+ if (isSimBasedSuggestion(ewns)) {
+ int carrierId = getCarrierIdFromSuggestion(ewns);
+ sendImsiProtectionExemptionNotificationIfRequired(carrierId);
}
+ approvedExtNetworkSuggestions.add(ewns);
}
if (approvedExtNetworkSuggestions.isEmpty()) {
@@ -1128,9 +1347,17 @@ public class WifiNetworkSuggestionsManager {
}
Set<ExtendedWifiNetworkSuggestion> approvedExtNetworkSuggestions = new HashSet<>();
for (ExtendedWifiNetworkSuggestion ewns : extNetworkSuggestions) {
- if (isNetworkSuggestionUserApprovedAndAvailableToConnect(ewns)) {
- approvedExtNetworkSuggestions.add(ewns);
+ if (!ewns.perAppInfo.hasUserApproved
+ && ewns.perAppInfo.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
+ sendUserApprovalNotificationIfNotApproved(ewns.perAppInfo.packageName,
+ ewns.perAppInfo.uid);
+ continue;
+ }
+ if (isSimBasedSuggestion(ewns)) {
+ int carrierId = getCarrierIdFromSuggestion(ewns);
+ sendImsiProtectionExemptionNotificationIfRequired(carrierId);
}
+ approvedExtNetworkSuggestions.add(ewns);
}
if (approvedExtNetworkSuggestions.isEmpty()) {
@@ -1144,57 +1371,6 @@ public class WifiNetworkSuggestionsManager {
return approvedExtNetworkSuggestions;
}
- private boolean isNetworkSuggestionUserApprovedAndAvailableToConnect(
- ExtendedWifiNetworkSuggestion ewns) {
- if (!ewns.perAppInfo.hasUserApproved
- && ewns.perAppInfo.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
- sendUserApprovalNotificationIfNotApproved(ewns.perAppInfo.packageName,
- ewns.perAppInfo.uid);
- return false;
- }
- WifiConfiguration config = ewns.wns.wifiConfiguration;
- PasspointConfiguration passpointConfiguration = ewns.wns.passpointConfiguration;
- int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- if (config == null) {
- Log.e(TAG, "WifiConfiguration is missing for " + ewns);
- return false;
- }
- if (passpointConfiguration != null) {
- // If passpoint config is not SIM based return true.
- if (passpointConfiguration.getCredential().getSimCredential() == null) {
- return true;
- }
- subId = mTelephonyUtil.getMatchingSubId(passpointConfiguration.getCarrierId());
- } else {
- // If Wifi Config is not SIM based return true.
- if (config.enterpriseConfig == null
- || !config.enterpriseConfig.isAuthenticationSimBased()) {
- return true;
- }
- subId = mTelephonyUtil.getBestMatchSubscriptionId(config);
- }
-
- if (!mTelephonyUtil.isSimPresent(subId)) {
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, "SIM is not present for subId: " + subId);
- }
- return false;
- }
- if (mTelephonyUtil.requiresImsiEncryption(subId)
- && !mTelephonyUtil.isImsiEncryptionInfoAvailable(subId)) {
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, "IMSI encryption is required but info is missing for subId: "
- + subId);
- }
- return false;
- }
- if (!mTelephonyUtil.requiresImsiEncryption(subId)) {
- // TODO(142001564): sendImsiProtectionWarningNotification();
- return false;
- }
- return true;
- }
-
/**
* Returns a set of all network suggestions matching the provided the WifiConfiguration.
*/
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index da207b561..2a5a33e55 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -182,6 +182,63 @@ public class WifiShellCommand extends BasicShellCommandHandler {
pw.println(hasUserApproved ? "yes" : "no");
return 0;
}
+ case "imsi-protection-exemption-set-user-approved-for-carrier": {
+ String arg1 = getNextArgRequired();
+ String arg2 = getNextArgRequired();
+ int carrierId = -1;
+ boolean approved;
+ try {
+ carrierId = Integer.parseInt(arg1);
+ } catch (NumberFormatException e) {
+ pw.println("Invalid argument to "
+ + "'imsi-protection-exemption-set-user-approved-for-carrier' "
+ + "- carrierId must be an Integer");
+ return -1;
+ }
+ if ("yes".equals(arg2)) {
+ approved = true;
+ } else if ("no".equals(arg2)) {
+ approved = false;
+ } else {
+ pw.println("Invalid argument to "
+ + "'imsi-protection-exemption-set-user-approved-for-carrier' "
+ + "- must be 'yes' or 'no'");
+ return -1;
+ }
+ mWifiNetworkSuggestionsManager
+ .setHasUserApprovedImsiPrivacyExemptionForCarrier(approved, carrierId);
+ return 0;
+ }
+ case "imsi-protection-exemption-has-user-approved-for-carrier": {
+ String arg1 = getNextArgRequired();
+ int carrierId = -1;
+ try {
+ carrierId = Integer.parseInt(arg1);
+ } catch (NumberFormatException e) {
+ pw.println("Invalid argument to "
+ + "'imsi-protection-exemption-has-user-approved-for-carrier' "
+ + "- 'carrierId' must be an Integer");
+ return -1;
+ }
+ boolean hasUserApproved = mWifiNetworkSuggestionsManager
+ .hasUserApprovedImsiPrivacyExemptionForCarrier(carrierId);
+ pw.println(hasUserApproved ? "yes" : "no");
+ return 0;
+ }
+ case "imsi-protection-exemption-clear-user-approved-for-carrier": {
+ String arg1 = getNextArgRequired();
+ int carrierId = -1;
+ try {
+ carrierId = Integer.parseInt(arg1);
+ } catch (NumberFormatException e) {
+ pw.println("Invalid argument to "
+ + "'imsi-protection-exemption-clear-user-approved-for-carrier' "
+ + "- 'carrierId' must be an Integer");
+ return -1;
+ }
+ mWifiNetworkSuggestionsManager.clearImsiPrivacyExemptionForCarrier(carrierId);
+ return 0;
+ }
case "network-requests-remove-user-approved-access-points": {
String packageName = getNextArgRequired();
mClientModeImpl.removeNetworkRequestUserApprovedAccessPointsForApp(packageName);
@@ -398,6 +455,12 @@ public class WifiShellCommand extends BasicShellCommandHandler {
pw.println(" Sets whether network suggestions from the app is approved or not.");
pw.println(" network-suggestions-has-user-approved <package name>");
pw.println(" Queries whether network suggestions from the app is approved or not.");
+ pw.println(" imsi-protection-exemption-set-user-approved-for-carrier <carrier id> yes|no");
+ pw.println(" Sets whether Imsi protection exemption for carrier is approved or not");
+ pw.println(" imsi-protection-exemption-has-user-approved-for-carrier <carrier id>");
+ pw.println(" Queries whether Imsi protection exemption for carrier is approved or not");
+ pw.println(" imsi-protection-exemption-clear-user-approved-for-carrier <carrier id>");
+ pw.println(" Clear the user choice on Imsi protection exemption for carrier");
pw.println(" network-requests-remove-user-approved-access-points <package name>");
pw.println(" Removes all user approved network requests for the app.");
pw.println(" clear-deleted-ephemeral-networks");
diff --git a/service/java/com/android/server/wifi/util/TelephonyUtil.java b/service/java/com/android/server/wifi/util/TelephonyUtil.java
index 95f01a8bc..1dfa3812b 100644
--- a/service/java/com/android/server/wifi/util/TelephonyUtil.java
+++ b/service/java/com/android/server/wifi/util/TelephonyUtil.java
@@ -1142,4 +1142,20 @@ public class TelephonyUtil {
}
return TelephonyManager.UNKNOWN_CARRIER_ID;
}
+
+ /**
+ * Get the carrier name for target subscription id.
+ * @param subId Subscription id
+ * @return String of carrier name.
+ */
+ public String getCarrierNameforSubId(int subId) {
+ TelephonyManager specifiedTm =
+ mTelephonyManager.createForSubscriptionId(subId);
+
+ CharSequence name = specifiedTm.getSimCarrierIdName();
+ if (name == null) {
+ return null;
+ }
+ return name.toString();
+ }
}
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
index 266c3c8fc..56562dddb 100644
--- a/service/res/values/overlayable.xml
+++ b/service/res/values/overlayable.xml
@@ -142,6 +142,10 @@
<item type="string" name="wifi_suggestion_content" />
<item type="string" name="wifi_suggestion_action_allow_app" />
<item type="string" name="wifi_suggestion_action_disallow_app" />
+ <item type="string" name="wifi_suggestion_imsi_privacy_title" />
+ <item type="string" name="wifi_suggestion_imsi_privacy_content" />
+ <item type="string" name="wifi_suggestion_action_allow_imsi_privacy_exemption_carrier" />
+ <item type="string" name="wifi_suggestion_action_disallow_imsi_privacy_exemption_carrier" />
<item type="string" name="wifi_wakeup_onboarding_title" />
<item type="string" name="wifi_wakeup_onboarding_subtext" />
<item type="string" name="wifi_wakeup_onboarding_action_disable" />
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 1040260d6..df49c4bc8 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -59,6 +59,15 @@
<!-- Notification action for disallowing app specified in the notification body.-->
<string name="wifi_suggestion_action_disallow_app">No thanks</string>
+ <!-- Notification title for a connection to a SIM-based carrier network without IMSI privacy protection. -->
+ <string name="wifi_suggestion_imsi_privacy_title">Privacy warning for IMSI protection</string>
+ <!-- Notification content for a connection to a SIM-based carrier network without IMSI privacy protection.-->
+ <string name="wifi_suggestion_imsi_privacy_content"><xliff:g id="carrierName" example="xxxMobile">%s</xliff:g> suggested networks using your SIM card info without without privacy protection, allow network to be connected automatically? </string>
+ <!-- Notification action for allowing carrier specified in the notification body.-->
+ <string name="wifi_suggestion_action_allow_imsi_privacy_exemption_carrier">Allow</string>
+ <!-- Notification action for disallowing carrier specified in the notification body.-->
+ <string name="wifi_suggestion_action_disallow_imsi_privacy_exemption_carrier">Disallow</string>
+
<!--Notification title for Wi-Fi Wake onboarding. This is displayed the first time a user disables Wi-Fi with the feature enabled. -->
<string name="wifi_wakeup_onboarding_title">Wi\u2011Fi will turn on automatically</string>
<!--Notification subtext for Wi-Fi Wake onboarding.-->
diff --git a/tests/wifitests/src/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreDataTest.java
new file mode 100644
index 000000000..f9e05cb32
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/ImsiPrivacyProtectionExemptionStoreDataTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 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 static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ImsiPrivacyProtectionExemptionStoreDataTest {
+ private static final int TEST_CARRIER_ID = 1911;
+
+ private @Mock ImsiPrivacyProtectionExemptionStoreData.DataSource mDataSource;
+ private ImsiPrivacyProtectionExemptionStoreData mImsiPrivacyProtectionExemptionStoreData;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mImsiPrivacyProtectionExemptionStoreData =
+ new ImsiPrivacyProtectionExemptionStoreData(mDataSource);
+ }
+
+ /**
+ * Helper function for serializing configuration data to a XML block.
+ */
+ private byte[] serializeData() throws Exception {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ mImsiPrivacyProtectionExemptionStoreData.serializeData(out, null);
+ out.flush();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Helper function for parsing configuration data from a XML block.
+ */
+ private void deserializeData(byte[] data) throws Exception {
+ final XmlPullParser in = Xml.newPullParser();
+ final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ in.setInput(inputStream, StandardCharsets.UTF_8.name());
+ mImsiPrivacyProtectionExemptionStoreData.deserializeData(in, in.getDepth(),
+ WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, null);
+ }
+
+ /**
+ * Verify store file Id.
+ */
+ @Test
+ public void verifyStoreFileId() throws Exception {
+ assertEquals(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS,
+ mImsiPrivacyProtectionExemptionStoreData.getStoreFileId());
+ }
+
+ /**
+ * Verify serialize and deserialize Protection exemption map.
+ */
+ @Test
+ public void testSerializeDeserialize() throws Exception {
+ Map<Integer, Boolean> imsiPrivacyProtectionExemptionMap = new HashMap<>();
+ imsiPrivacyProtectionExemptionMap.put(TEST_CARRIER_ID, true);
+ assertSerializeDeserialize(imsiPrivacyProtectionExemptionMap);
+ }
+
+ /**
+ * Verify serialize and deserialize empty protection exemption map.
+ */
+ @Test
+ public void testSerializeDeserializeEmpty() throws Exception {
+ Map<Integer, Boolean> imsiPrivacyProtectionExemptionMap = new HashMap<>();
+ assertSerializeDeserialize(imsiPrivacyProtectionExemptionMap);
+ }
+
+ private Map<Integer, Boolean> assertSerializeDeserialize(
+ Map<Integer, Boolean> mImsiPrivacyProtectionExemptionMap) throws Exception {
+ // Setup the data to serialize.
+ when(mDataSource.toSerialize()).thenReturn(mImsiPrivacyProtectionExemptionMap);
+
+ // Serialize/deserialize data.
+ deserializeData(serializeData());
+
+ // Verify the deserialized data.
+ ArgumentCaptor<HashMap> deserializedNetworkSuggestionsMap =
+ ArgumentCaptor.forClass(HashMap.class);
+ verify(mDataSource).fromDeserialized(deserializedNetworkSuggestionsMap.capture());
+ assertEquals(mImsiPrivacyProtectionExemptionMap,
+ deserializedNetworkSuggestionsMap.getValue());
+ return deserializedNetworkSuggestionsMap.getValue();
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
index e47b2bcf7..01cdee812 100644
--- a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
@@ -20,6 +20,7 @@ import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus
.NETWORK_SELECTION_TEMPORARY_DISABLED;
+import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_EAP;
import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK;
import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig;
@@ -27,6 +28,7 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiNetworkSuggestion;
import android.net.wifi.WifiSsid;
import android.util.LocalLog;
@@ -37,6 +39,7 @@ import androidx.test.filters.SmallTest;
import com.android.server.wifi.WifiNetworkSuggestionsManager.ExtendedWifiNetworkSuggestion;
import com.android.server.wifi.WifiNetworkSuggestionsManager.PerAppInfo;
import com.android.server.wifi.hotspot2.PasspointNetworkNominateHelper;
+import com.android.server.wifi.util.TelephonyUtil;
import org.junit.Before;
import org.junit.Test;
@@ -62,11 +65,16 @@ public class NetworkSuggestionNominatorTest extends WifiBaseTest {
private static final String TEST_PACKAGE = "com.test";
private static final String TEST_PACKAGE_OTHER = "com.test.other";
private static final String TEST_FQDN = "fqdn";
+ private static final int TEST_CARRIER_ID = 1911;
+ private static final String TEST_CARRIER_NAME = "testCarrier";
+ private static final int TEST_SUB_ID = 2020;
+
private @Mock WifiConfigManager mWifiConfigManager;
private @Mock WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
private @Mock PasspointNetworkNominateHelper mPasspointNetworkNominateHelper;
private @Mock Clock mClock;
+ private @Mock TelephonyUtil mTelephonyUtil;
private NetworkSuggestionNominator mNetworkSuggestionNominator;
/** Sets up test. */
@@ -75,7 +83,7 @@ public class NetworkSuggestionNominatorTest extends WifiBaseTest {
MockitoAnnotations.initMocks(this);
mNetworkSuggestionNominator = new NetworkSuggestionNominator(
mWifiNetworkSuggestionsManager, mWifiConfigManager, mPasspointNetworkNominateHelper,
- new LocalLog(100));
+ new LocalLog(100), mTelephonyUtil);
}
/**
@@ -752,6 +760,98 @@ public class NetworkSuggestionNominatorTest extends WifiBaseTest {
suggestions[1].wns.wifiConfiguration)), anyInt(), anyString());
}
+ @Test
+ public void testSelectNetworkSuggestionForOneMatchSimBasedWithNoSim() {
+ String[] scanSsids = {"test1"};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {2470};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {-67};
+ String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
+ int[] securities = {SECURITY_EAP};
+ boolean[] appInteractions = {true};
+ boolean[] meteredness = {true};
+ int[] priorities = {-1};
+ int[] uids = {TEST_UID};
+ String[] packageNames = {TEST_PACKAGE};
+ boolean[] autojoin = {true};
+ boolean[] shareWithUser = {true};
+
+ ScanDetail[] scanDetails =
+ buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
+ ExtendedWifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids,
+ securities, appInteractions, meteredness, priorities, uids,
+ packageNames, autojoin, shareWithUser);
+ WifiConfiguration eapSimConfig = suggestions[0].wns.wifiConfiguration;
+ eapSimConfig.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+ eapSimConfig.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+ eapSimConfig.carrierId = TEST_CARRIER_ID;
+ when(mTelephonyUtil.getBestMatchSubscriptionId(eapSimConfig)).thenReturn(TEST_SUB_ID);
+ when(mTelephonyUtil.isSimPresent(TEST_SUB_ID)).thenReturn(false);
+ // Link the scan result with suggestions.
+ linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
+ // setup config manager interactions.
+ setupAddToWifiConfigManager(suggestions[0].wns.wifiConfiguration);
+
+ List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
+ mNetworkSuggestionNominator.nominateNetworks(
+ Arrays.asList(scanDetails), null, null, true, false,
+ (ScanDetail scanDetail, WifiConfiguration configuration) -> {
+ connectableNetworks.add(Pair.create(scanDetail, configuration));
+ });
+
+ // Verify no network is nominated.
+ assertTrue(connectableNetworks.isEmpty());
+ verifyAddToWifiConfigManager(suggestions[0].wns.wifiConfiguration);
+ }
+
+ @Test
+ public void testSelectNetworkSuggestionForOneMatchSimBasedWithEncryptionInfoNotAvailabele() {
+ String[] scanSsids = {"test1"};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {2470};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {-67};
+ String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
+ int[] securities = {SECURITY_EAP};
+ boolean[] appInteractions = {true};
+ boolean[] meteredness = {true};
+ int[] priorities = {-1};
+ int[] uids = {TEST_UID};
+ String[] packageNames = {TEST_PACKAGE};
+ boolean[] autojoin = {true};
+ boolean[] shareWithUser = {true};
+
+ ScanDetail[] scanDetails =
+ buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
+ ExtendedWifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids,
+ securities, appInteractions, meteredness, priorities, uids,
+ packageNames, autojoin, shareWithUser);
+ WifiConfiguration eapSimConfig = suggestions[0].wns.wifiConfiguration;
+ eapSimConfig.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+ eapSimConfig.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+ eapSimConfig.carrierId = TEST_CARRIER_ID;
+ when(mTelephonyUtil.getBestMatchSubscriptionId(eapSimConfig)).thenReturn(TEST_SUB_ID);
+ when(mTelephonyUtil.isSimPresent(TEST_SUB_ID)).thenReturn(true);
+ when(mTelephonyUtil.requiresImsiEncryption(TEST_SUB_ID)).thenReturn(true);
+ when(mTelephonyUtil.isImsiEncryptionInfoAvailable(TEST_SUB_ID)).thenReturn(false);
+ // Link the scan result with suggestions.
+ linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
+ // setup config manager interactions.
+ setupAddToWifiConfigManager(suggestions[0].wns.wifiConfiguration);
+
+ List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
+ mNetworkSuggestionNominator.nominateNetworks(
+ Arrays.asList(scanDetails), null, null, true, false,
+ (ScanDetail scanDetail, WifiConfiguration configuration) -> {
+ connectableNetworks.add(Pair.create(scanDetail, configuration));
+ });
+
+ // Verify no network is nominated.
+ assertTrue(connectableNetworks.isEmpty());
+ verifyAddToWifiConfigManager(suggestions[0].wns.wifiConfiguration);
+ }
+
private void setupAddToWifiConfigManager(WifiConfiguration...candidates) {
for (int i = 0; i < candidates.length; i++) {
WifiConfiguration candidate = candidates[i];
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
index e623e7573..874b5240a 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
@@ -24,7 +24,9 @@ import static android.app.Notification.EXTRA_BIG_TEXT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wifi.WifiNetworkSuggestionsManager.NOTIFICATION_USER_ALLOWED_APP_INTENT_ACTION;
+import static com.android.server.wifi.WifiNetworkSuggestionsManager.NOTIFICATION_USER_ALLOWED_CARRIER_INTENT_ACTION;
import static com.android.server.wifi.WifiNetworkSuggestionsManager.NOTIFICATION_USER_DISALLOWED_APP_INTENT_ACTION;
+import static com.android.server.wifi.WifiNetworkSuggestionsManager.NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION;
import static com.android.server.wifi.WifiNetworkSuggestionsManager.NOTIFICATION_USER_DISMISSED_INTENT_ACTION;
import static org.junit.Assert.assertEquals;
@@ -126,6 +128,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
private @Mock WifiConfigStore mWifiConfigStore;
private @Mock WifiConfigManager mWifiConfigManager;
private @Mock NetworkSuggestionStoreData mNetworkSuggestionStoreData;
+ private @Mock ImsiPrivacyProtectionExemptionStoreData mImsiPrivacyProtectionExemptionStoreData;
private @Mock WifiMetrics mWifiMetrics;
private @Mock TelephonyUtil mTelephonyUtil;
private @Mock PasspointManager mPasspointManager;
@@ -142,6 +145,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
private NetworkSuggestionStoreData.DataSource mDataSource;
+ private ImsiPrivacyProtectionExemptionStoreData.DataSource mImsiDataSource;
/**
* Setup the mocks.
@@ -155,6 +159,8 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
when(mWifiInjector.makeNetworkSuggestionStoreData(any()))
.thenReturn(mNetworkSuggestionStoreData);
+ when(mWifiInjector.makeImsiProtectionExemptionStoreData(any()))
+ .thenReturn(mImsiPrivacyProtectionExemptionStoreData);
when(mWifiInjector.getFrameworkFacade()).thenReturn(mFrameworkFacade);
when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
when(mFrameworkFacade.getBroadcast(any(), anyInt(), any(), anyInt()))
@@ -177,6 +183,18 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
when(mResources.getText(eq(R.string.wifi_suggestion_action_disallow_app)))
.thenReturn("blah");
+ // setup resource strings for IMSI protection notification.
+ when(mResources.getString(eq(R.string.wifi_suggestion_imsi_privacy_title)))
+ .thenReturn("blah");
+ when(mResources.getString(eq(R.string.wifi_suggestion_imsi_privacy_content), anyString()))
+ .thenAnswer(s -> "blah" + s.getArguments()[1]);
+ when(mResources.getText(
+ eq(R.string.wifi_suggestion_action_allow_imsi_privacy_exemption_carrier)))
+ .thenReturn("blah");
+ when(mResources.getText(
+ eq(R.string.wifi_suggestion_action_disallow_imsi_privacy_exemption_carrier)))
+ .thenReturn("blah");
+
// Our app Info. Needed for notification builder.
ApplicationInfo ourAppInfo = new ApplicationInfo();
when(mContext.getApplicationInfo()).thenReturn(ourAppInfo);
@@ -209,6 +227,14 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
mDataSource = dataSourceArgumentCaptor.getValue();
assertNotNull(mDataSource);
+ ArgumentCaptor<ImsiPrivacyProtectionExemptionStoreData.DataSource>
+ imsiDataSourceArgumentCaptor =
+ ArgumentCaptor.forClass(ImsiPrivacyProtectionExemptionStoreData.DataSource.class);
+ verify(mWifiInjector).makeImsiProtectionExemptionStoreData(imsiDataSourceArgumentCaptor
+ .capture());
+ mImsiDataSource = imsiDataSourceArgumentCaptor.getValue();
+ assertNotNull(mImsiDataSource);
+
mWifiNetworkSuggestionsManager.enableVerboseLogging(1);
}
@@ -538,39 +564,6 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
}
/**
- * Do not evaluate the suggested network which requires SIM card, but the SIM is absent.
- */
- @Test
- public void testGetNetworkSuggestionsForScanDtailIgnoreEapSimNetworkForAbsentSim() {
- WifiConfiguration config = WifiConfigurationTestUtil.createEapNetwork(
- WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE);
- config.carrierId = VALID_CARRIER_ID;
- WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
- config, null, false, false, true, true, false);
- List<WifiNetworkSuggestion> networkSuggestionList1 =
- new ArrayList<WifiNetworkSuggestion>() {{
- add(networkSuggestion);
- }};
- when(mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(eq(TEST_UID_1)))
- .thenReturn(true);
- assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
- mWifiNetworkSuggestionsManager.add(networkSuggestionList1, TEST_UID_1,
- TEST_PACKAGE_1, TEST_FEATURE));
- mWifiNetworkSuggestionsManager.setHasUserApprovedForApp(true, TEST_PACKAGE_1);
-
- ScanDetail scanDetail = createScanDetailForNetwork(networkSuggestion.wifiConfiguration);
-
- when(mTelephonyUtil.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
- .thenReturn(TEST_SUBID);
- when(mTelephonyUtil.isSimPresent(eq(TEST_SUBID))).thenReturn(false);
-
- Set<ExtendedWifiNetworkSuggestion> matchingExtNetworkSuggestions =
- mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(scanDetail);
-
- assertNull(matchingExtNetworkSuggestions);
- }
-
- /**
* Verify a successful lookup of a single network suggestion matching the provided scan detail.
*/
@Test
@@ -1209,7 +1202,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
* {@link WifiNetworkSuggestion#isAppInteractionRequired} flag set.
* b) The app holds location permission.
* c) App has not been approved by the user.
- * This should trigger a broadcast to the app.
+ * This should not trigger a broadcast to the app.
*/
@Test
public void testOnNetworkConnectionWhenAppNotApproved() {
@@ -2038,7 +2031,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
TEST_PACKAGE_1, TEST_FEATURE));
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user dismissal notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
reset(mNotificationManger);
@@ -2049,7 +2042,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user dismissal notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
reset(mNotificationManger);
@@ -2080,7 +2073,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user dismissal notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
reset(mNotificationManger);
@@ -2091,7 +2084,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user clicking on allow in the notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_ALLOWED_APP_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
// Cancel the notification.
verify(mNotificationManger).cancel(SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE);
@@ -2128,7 +2121,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user dismissal notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
reset(mNotificationManger);
@@ -2139,7 +2132,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user clicking on disallow in the notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_DISALLOWED_APP_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
// Ensure we turn off CHANGE_WIFI_STATE app-ops.
verify(mAppOpsManager).setMode(
@@ -2313,7 +2306,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user clicking on allow in the notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_ALLOWED_APP_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
// Cancel the notification.
verify(mNotificationManger).cancel(SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE);
@@ -2350,7 +2343,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
validateUserApprovalNotification(TEST_APP_NAME_1);
// Simulate user clicking on disallow in the notification.
- sendBroadcastForUserAction(
+ sendBroadcastForUserActionOnApp(
NOTIFICATION_USER_DISALLOWED_APP_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
// Ensure we turn off CHANGE_WIFI_STATE app-ops.
verify(mAppOpsManager).setMode(
@@ -2461,8 +2454,22 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
private boolean checkUserApprovalNotificationParams(
Notification notification, String expectedAppName) {
- if (!notification.extras.getString(EXTRA_BIG_TEXT).contains(expectedAppName)) return false;
- return true;
+ return notification.extras.getString(EXTRA_BIG_TEXT).contains(expectedAppName);
+ }
+
+ private boolean checkImsiProtectionNotificationParams(
+ Notification notification, String carrierName) {
+ return notification.extras.getString(EXTRA_BIG_TEXT).contains(carrierName);
+ }
+
+ private void validateImsiProtectionNotification(String carrierName) {
+ ArgumentCaptor<Notification> notificationArgumentCaptor =
+ ArgumentCaptor.forClass(Notification.class);
+ verify(mNotificationManger).notify(eq(SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE),
+ notificationArgumentCaptor.capture());
+ Notification notification = notificationArgumentCaptor.getValue();
+ assertNotNull(notification);
+ assertTrue(checkImsiProtectionNotificationParams(notification, carrierName));
}
private void validateUserApprovalNotification(String... anyOfExpectedAppNames) {
@@ -2482,7 +2489,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
assertTrue(foundMatch);
}
- private void sendBroadcastForUserAction(String action, String packageName, int uid) {
+ private void sendBroadcastForUserActionOnApp(String action, String packageName, int uid) {
Intent intent = new Intent()
.setAction(action)
.putExtra(WifiNetworkSuggestionsManager.EXTRA_PACKAGE_NAME, packageName)
@@ -2491,6 +2498,16 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent);
}
+ private void sendBroadcastForUserActionOnImsi(String action, String carrierName,
+ int carrierId) {
+ Intent intent = new Intent()
+ .setAction(action)
+ .putExtra(WifiNetworkSuggestionsManager.EXTRA_CARRIER_NAME, carrierName)
+ .putExtra(WifiNetworkSuggestionsManager.EXTRA_CARRIER_ID, carrierId);
+ assertNotNull(mBroadcastReceiverCaptor.getValue());
+ mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent);
+ }
+
@Test
public void testAddSuggestionWithValidCarrierIdWithCarrierProvisionPermission() {
WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
@@ -2803,7 +2820,7 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
.thenReturn(false);
when(mTelephonyUtil.getCarrierIdForPackageWithCarrierPrivileges(TEST_PACKAGE_1))
.thenReturn(VALID_CARRIER_ID);
- when(mTelephonyUtil.getBestMatchSubscriptionId(config)).thenReturn(TEST_SUBID);
+ when(mTelephonyUtil.getMatchingSubId(VALID_CARRIER_ID)).thenReturn(TEST_SUBID);
when(mTelephonyUtil.isSimPresent(TEST_SUBID)).thenReturn(true);
when(mTelephonyUtil.requiresImsiEncryption(TEST_SUBID)).thenReturn(true);
when(mTelephonyUtil.isImsiEncryptionInfoAvailable(TEST_SUBID)).thenReturn(true);
@@ -2823,38 +2840,6 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
}
/**
- * Verify matched SIM-based network won't return when imsi protection isn't available.
- * Todo(142001564): verify user approval notification.
- */
- @Test
- public void testMatchSimBasedNetworkWithoutImsiProtection() {
- WifiConfiguration config =
- WifiConfigurationTestUtil.createEapNetwork(WifiEnterpriseConfig.Eap.SIM,
- WifiEnterpriseConfig.Phase2.NONE);
- WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
- config, null, true, false, true, true, false);
- List<WifiNetworkSuggestion> networkSuggestionList = new ArrayList<>();
- networkSuggestionList.add(networkSuggestion);
- when(mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(TEST_UID_1))
- .thenReturn(false);
- when(mTelephonyUtil.getCarrierIdForPackageWithCarrierPrivileges(TEST_PACKAGE_1))
- .thenReturn(VALID_CARRIER_ID);
- when(mTelephonyUtil.getBestMatchSubscriptionId(config)).thenReturn(TEST_SUBID);
- when(mTelephonyUtil.isSimPresent(TEST_SUBID)).thenReturn(true);
- when(mTelephonyUtil.requiresImsiEncryption(TEST_SUBID)).thenReturn(false);
- when(mTelephonyUtil.isImsiEncryptionInfoAvailable(TEST_SUBID)).thenReturn(false);
- ScanDetail scanDetail = createScanDetailForNetwork(config);
- int status = mWifiNetworkSuggestionsManager
- .add(networkSuggestionList, TEST_UID_1, TEST_PACKAGE_1, TEST_FEATURE);
- assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, status);
-
- Set<ExtendedWifiNetworkSuggestion> matchingExtNetworkSuggestions =
- mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(scanDetail);
- //Todo(142001564): should send out user notification.
- assertNull(matchingExtNetworkSuggestions);
- }
-
- /**
* Verify when SIM changes, the app loses carrier privilege. Suggestions from this app will be
* removed. If this app suggests again, it will be considered as normal suggestor.
*/
@@ -3108,6 +3093,132 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
}
/**
+ * Test the IMSI protection notification and user click on the allow.
+ */
+ @Test
+ public void testSendImsiProtectionNotificationOnUserAllowed() {
+ when(mTelephonyUtil.getCarrierIdForPackageWithCarrierPrivileges(TEST_PACKAGE_1))
+ .thenReturn(TEST_CARRIER_ID);
+ when(mTelephonyUtil.getMatchingSubId(TEST_CARRIER_ID)).thenReturn(TEST_SUBID);
+ when(mTelephonyUtil.getCarrierNameforSubId(TEST_SUBID)).thenReturn(TEST_CARRIER_NAME);
+ when(mTelephonyUtil.requiresImsiEncryption(TEST_SUBID)).thenReturn(false);
+ WifiConfiguration eapSimConfig = WifiConfigurationTestUtil.createEapNetwork(
+ WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE);
+ WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+ eapSimConfig, null, true, false, true, true,
+ false);
+ List<WifiNetworkSuggestion> networkSuggestionList =
+ new ArrayList<WifiNetworkSuggestion>() {{
+ add(networkSuggestion);
+ }};
+ assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+ mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+ TEST_PACKAGE_1, TEST_FEATURE));
+ verifyNoMoreInteractions(mNotificationManger);
+ Set<ExtendedWifiNetworkSuggestion> matchedSuggestion = mWifiNetworkSuggestionsManager
+ .getNetworkSuggestionsForScanDetail(createScanDetailForNetwork(eapSimConfig));
+ validateImsiProtectionNotification(TEST_CARRIER_NAME);
+ for (ExtendedWifiNetworkSuggestion ewns : matchedSuggestion) {
+ assertFalse(ewns.isAutoJoinEnabled);
+ }
+ sendBroadcastForUserActionOnImsi(NOTIFICATION_USER_ALLOWED_CARRIER_INTENT_ACTION,
+ TEST_CARRIER_NAME, TEST_CARRIER_ID);
+ verify(mNotificationManger).cancel(SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE);
+
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+ assertTrue(mImsiDataSource.hasNewDataToSerialize());
+ matchedSuggestion = mWifiNetworkSuggestionsManager
+ .getNetworkSuggestionsForScanDetail(createScanDetailForNetwork(eapSimConfig));
+ verifyNoMoreInteractions(mNotificationManger);
+ assertTrue(mWifiNetworkSuggestionsManager
+ .hasUserApprovedImsiPrivacyExemptionForCarrier(TEST_CARRIER_ID));
+
+ for (ExtendedWifiNetworkSuggestion ewns : matchedSuggestion) {
+ assertTrue(ewns.isAutoJoinEnabled);
+ }
+ }
+
+ /**
+ * Test the IMSI protection notification and user click on the disallow.
+ */
+ @Test
+ public void testSendImsiProtectionNotificationOnUserDisallowed() {
+ when(mTelephonyUtil.getCarrierIdForPackageWithCarrierPrivileges(TEST_PACKAGE_1))
+ .thenReturn(TEST_CARRIER_ID);
+ when(mTelephonyUtil.getMatchingSubId(TEST_CARRIER_ID)).thenReturn(TEST_SUBID);
+ when(mTelephonyUtil.getCarrierNameforSubId(TEST_SUBID)).thenReturn(TEST_CARRIER_NAME);
+ when(mTelephonyUtil.requiresImsiEncryption(TEST_SUBID)).thenReturn(false);
+ WifiConfiguration eapSimConfig = WifiConfigurationTestUtil.createEapNetwork(
+ WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE);
+ WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+ eapSimConfig, null, true, false, true, true,
+ false);
+ List<WifiNetworkSuggestion> networkSuggestionList =
+ new ArrayList<WifiNetworkSuggestion>() {{
+ add(networkSuggestion);
+ }};
+ assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+ mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+ TEST_PACKAGE_1, TEST_FEATURE));
+ Set<ExtendedWifiNetworkSuggestion> matchedSuggestion = mWifiNetworkSuggestionsManager
+ .getNetworkSuggestionsForScanDetail(createScanDetailForNetwork(eapSimConfig));
+ validateImsiProtectionNotification(TEST_CARRIER_NAME);
+ for (ExtendedWifiNetworkSuggestion ewns : matchedSuggestion) {
+ assertFalse(ewns.isAutoJoinEnabled);
+ }
+ sendBroadcastForUserActionOnImsi(NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION,
+ TEST_CARRIER_NAME, TEST_CARRIER_ID);
+ verify(mNotificationManger).cancel(SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE);
+
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+ assertTrue(mImsiDataSource.hasNewDataToSerialize());
+ matchedSuggestion = mWifiNetworkSuggestionsManager
+ .getNetworkSuggestionsForScanDetail(createScanDetailForNetwork(eapSimConfig));
+ verifyNoMoreInteractions(mNotificationManger);
+ assertFalse(mWifiNetworkSuggestionsManager
+ .hasUserApprovedImsiPrivacyExemptionForCarrier(TEST_CARRIER_ID));
+
+ for (ExtendedWifiNetworkSuggestion ewns : matchedSuggestion) {
+ assertFalse(ewns.isAutoJoinEnabled);
+ }
+ }
+
+ /**
+ * Test when carrier start to support IMSI protection, imsiExemptionMap will update too.
+ */
+ @Test
+ public void testUpdateImsiExemptionMapWhenCarrierFromWithoutProtectionToWithProtection() {
+ // Simulate user click on disallow before.
+ mWifiNetworkSuggestionsManager
+ .setHasUserApprovedImsiPrivacyExemptionForCarrier(false, TEST_CARRIER_ID);
+ verifyNoMoreInteractions(mNotificationManger);
+ // Now carrier upgrade to support Imsi protection
+ when(mTelephonyUtil.getCarrierIdForPackageWithCarrierPrivileges(TEST_PACKAGE_1))
+ .thenReturn(TEST_CARRIER_ID);
+ when(mTelephonyUtil.getMatchingSubId(TEST_CARRIER_ID)).thenReturn(TEST_SUBID);
+ when(mTelephonyUtil.requiresImsiEncryption(TEST_SUBID)).thenReturn(true);
+ WifiConfiguration eapSimConfig = WifiConfigurationTestUtil.createEapNetwork(
+ WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE);
+ WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+ eapSimConfig, null, true, false, true, true,
+ false);
+ List<WifiNetworkSuggestion> networkSuggestionList =
+ new ArrayList<WifiNetworkSuggestion>() {{
+ add(networkSuggestion);
+ }};
+ assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+ mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+ TEST_PACKAGE_1, TEST_FEATURE));
+ Set<ExtendedWifiNetworkSuggestion> matchedSuggestion = mWifiNetworkSuggestionsManager
+ .getNetworkSuggestionsForScanDetail(createScanDetailForNetwork(eapSimConfig));
+ // Should be no more notification and suggestion restore to the initial auto join configure.
+ verifyNoMoreInteractions(mNotificationManger);
+ for (ExtendedWifiNetworkSuggestion ewns : matchedSuggestion) {
+ assertTrue(ewns.isAutoJoinEnabled);
+ }
+ }
+
+ /**
* Verify adding invalid suggestions will return right error reason code.
*/
@Test
diff --git a/tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java
index 26db7cc30..794eb8423 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java
@@ -95,6 +95,7 @@ public class TelephonyUtilTest extends WifiBaseTest {
private static final String NO_MATCH_OPERATOR_NUMERIC = "654321";
private static final String TEST_PACKAGE = "com.test12345";
private static final String ANONYMOUS_IDENTITY = "anonymous@wlan.mnc456.mcc123.3gppnetwork.org";
+ private static final String CARRIER_NAME = "Google";
@Mock
CarrierConfigManager mCarrierConfigManager;
@@ -153,6 +154,8 @@ public class TelephonyUtilTest extends WifiBaseTest {
when(mDataTelephonyManager.getSubscriberId()).thenReturn(DATA_FULL_IMSI);
when(mNonDataTelephonyManager.getSubscriberId()).thenReturn(NON_DATA_FULL_IMSI);
when(mDataTelephonyManager.getSimOperator()).thenReturn(DATA_OPERATOR_NUMERIC);
+ when(mDataTelephonyManager.getSimCarrierIdName()).thenReturn(CARRIER_NAME);
+ when(mNonDataTelephonyManager.getSimCarrierIdName()).thenReturn(null);
when(mNonDataTelephonyManager.getSimOperator())
.thenReturn(NON_DATA_OPERATOR_NUMERIC);
when(mDataTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
@@ -1376,4 +1379,13 @@ public class TelephonyUtilTest extends WifiBaseTest {
assertEquals(DATA_CARRIER_ID,
mTelephonyUtil.getCarrierIdForPackageWithCarrierPrivileges(TEST_PACKAGE));
}
+
+ /**
+ * Verify getCarrierNameforSubId returns right value.
+ */
+ @Test
+ public void getCarrierNameFromSubId() {
+ assertEquals(CARRIER_NAME, mTelephonyUtil.getCarrierNameforSubId(DATA_SUBID));
+ assertNull(mTelephonyUtil.getCarrierNameforSubId(NON_DATA_SUBID));
+ }
}