summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2017-11-10 14:39:24 -0800
committerXin Li <delphij@google.com>2017-11-10 14:39:24 -0800
commit45574b17b4443c13f70c7c62b2bcb0c0ef2969d4 (patch)
treee45bf40318808b7ce83e3536c7e351d1021dc635
parent091e23fb0c93886b83335fac9596330a4ae06804 (diff)
parent456a25e50b2fa4c85f14b74801edf6d84b650b20 (diff)
downloadwifi-45574b17b4443c13f70c7c62b2bcb0c0ef2969d4.tar.gz
Merge commit '456a25e50b2fa4c85f14b74801edf6d84b650b20' from
oc-mr1-dev-plus-aosp-without-vendor into stage-aosp-master. Change-Id: I55c4a4a736e1cdbfd579bd0529ed8d8966eb9e2a
-rw-r--r--libwifi_system/Android.bp2
-rw-r--r--libwifi_system/tests/hostapd_manager_unittest.cpp79
-rw-r--r--libwifi_system_iface/Android.bp5
-rw-r--r--service/Android.mk5
-rw-r--r--service/java/com/android/server/wifi/CarrierNetworkConfig.java198
-rw-r--r--service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java146
-rw-r--r--service/java/com/android/server/wifi/NetworkListStoreData.java21
-rw-r--r--service/java/com/android/server/wifi/OpenNetworkNotifier.java498
-rw-r--r--service/java/com/android/server/wifi/OpenNetworkRecommender.java58
-rw-r--r--service/java/com/android/server/wifi/RttService.java166
-rw-r--r--service/java/com/android/server/wifi/ScanDetailCache.java7
-rw-r--r--service/java/com/android/server/wifi/SelfRecovery.java2
-rw-r--r--service/java/com/android/server/wifi/SsidSetStoreData.java131
-rw-r--r--service/java/com/android/server/wifi/SupplicantStaNetworkHal.java4
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java118
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStoreLegacy.java358
-rw-r--r--service/java/com/android/server/wifi/WifiConfigurationUtil.java2
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java57
-rw-r--r--service/java/com/android/server/wifi/WifiController.java6
-rw-r--r--service/java/com/android/server/wifi/WifiCountryCode.java21
-rw-r--r--service/java/com/android/server/wifi/WifiDiagnostics.java2
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java25
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java264
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java31
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkHistory.java634
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkSelector.java10
-rw-r--r--service/java/com/android/server/wifi/WifiNotificationController.java252
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java157
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java350
-rw-r--r--service/java/com/android/server/wifi/WificondControl.java67
-rw-r--r--service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java458
-rw-r--r--service/java/com/android/server/wifi/aware/WifiAwareMetrics.java5
-rw-r--r--service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java5
-rw-r--r--service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java7
-rw-r--r--service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java1
-rw-r--r--service/java/com/android/server/wifi/aware/WifiAwareStateManager.java2
-rw-r--r--service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java513
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java7
-rw-r--r--service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallback.java7
-rw-r--r--service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java28
-rw-r--r--service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java11
-rw-r--r--service/java/com/android/server/wifi/scanner/WificondScannerImpl.java24
-rw-r--r--service/java/com/android/server/wifi/util/Matrix.java340
-rw-r--r--service/java/com/android/server/wifi/util/NativeUtil.java31
-rw-r--r--service/java/com/android/server/wifi/util/WifiPermissionsUtil.java179
-rw-r--r--service/java/com/android/server/wifi/util/XmlUtil.java5
-rw-r--r--tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java172
-rw-r--r--tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java121
-rw-r--r--tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java702
-rw-r--r--tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java102
-rw-r--r--tests/wifitests/src/com/android/server/wifi/RttServiceTest.java24
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java202
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java4
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java145
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigStoreLegacyTest.java273
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java18
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java117
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java27
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java132
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java95
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java208
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java15
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java16
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java703
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WificondControlTest.java133
-rw-r--r--tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java533
-rw-r--r--tests/wifitests/src/com/android/server/wifi/aware/WifiAwareMetricsTest.java3
-rw-r--r--tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java2
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/LegacyPasspointConfigParserTest.java204
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java68
-rw-r--r--tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackTest.java8
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java3
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java34
-rw-r--r--tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java122
-rw-r--r--tests/wifitests/src/com/android/server/wifi/util/NativeUtilTest.java25
-rw-r--r--tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java442
76 files changed, 6359 insertions, 3593 deletions
diff --git a/libwifi_system/Android.bp b/libwifi_system/Android.bp
index 877d05f1d..f5ea184f3 100644
--- a/libwifi_system/Android.bp
+++ b/libwifi_system/Android.bp
@@ -29,7 +29,7 @@ cc_defaults {
// Device independent wifi system logic.
// ============================================================
-cc_library_shared {
+cc_library {
name: "libwifi-system",
defaults: ["libwifi-system-defaults"],
export_include_dirs: ["include"],
diff --git a/libwifi_system/tests/hostapd_manager_unittest.cpp b/libwifi_system/tests/hostapd_manager_unittest.cpp
index 048d4732d..b25dd8ec7 100644
--- a/libwifi_system/tests/hostapd_manager_unittest.cpp
+++ b/libwifi_system/tests/hostapd_manager_unittest.cpp
@@ -24,6 +24,8 @@
using std::string;
using std::vector;
+using testing::HasSubstr;
+using testing::Not;
namespace android {
namespace wifi_system {
@@ -34,46 +36,10 @@ const char kTestSsidStr[] = "helloisitme";
const char kTestPassphraseStr[] = "yourelookingfor";
const int kTestChannel = 2;
-#define CONFIG_COMMON_PREFIX \
- "interface=foobar0\n" \
- "driver=nl80211\n" \
- "ctrl_interface=/data/misc/wifi/hostapd/ctrl\n" \
- "ssid2=68656c6c6f" "6973" "6974" "6d65\n" \
- "channel=2\n" \
- "ieee80211n=1\n" \
- "hw_mode=g\n"
-
// If you generate your config file with both the test ssid
// and the test passphrase, you'll get this line in the config.
-#define CONFIG_PSK_LINE \
- "wpa_psk=dffa36815281e5a6eca1910f254717fa2528681335e3bbec5966d2aa9221a66e\n"
-
-#define CONFIG_WPA_SUFFIX \
- "wpa=3\n" \
- "wpa_pairwise=TKIP CCMP\n" \
- CONFIG_PSK_LINE
-
-#define CONFIG_WPA2_SUFFIX \
- "wpa=2\n" \
- "rsn_pairwise=CCMP\n" \
- CONFIG_PSK_LINE
-
-const char kExpectedOpenConfig[] =
- CONFIG_COMMON_PREFIX
- "ignore_broadcast_ssid=0\n"
- "wowlan_triggers=any\n";
-
-const char kExpectedWpaConfig[] =
- CONFIG_COMMON_PREFIX
- "ignore_broadcast_ssid=0\n"
- "wowlan_triggers=any\n"
- CONFIG_WPA_SUFFIX;
-
-const char kExpectedWpa2Config[] =
- CONFIG_COMMON_PREFIX
- "ignore_broadcast_ssid=0\n"
- "wowlan_triggers=any\n"
- CONFIG_WPA2_SUFFIX;
+const char kConfigPskLine[] =
+ "wpa_psk=dffa36815281e5a6eca1910f254717fa2528681335e3bbec5966d2aa9221a66e\n";
class HostapdManagerTest : public ::testing::Test {
protected:
@@ -93,27 +59,44 @@ class HostapdManagerTest : public ::testing::Test {
}
}; // class HostapdManagerTest
+// This is used to verify config string generated by test helper function
+// |GetConfigForEncryptionType|.
+void VerifyCommonConfigs(const string& config) {
+ EXPECT_THAT(config, HasSubstr("interface=foobar0\n"));
+ EXPECT_THAT(config, HasSubstr("driver=nl80211\n"));
+ EXPECT_THAT(config, HasSubstr("ctrl_interface=/data/misc/wifi/hostapd/ctrl\n"));
+ EXPECT_THAT(config, HasSubstr("ssid2=68656c6c6f" "6973" "6974" "6d65\n"));
+ EXPECT_THAT(config, HasSubstr("channel=2\n"));
+ EXPECT_THAT(config, HasSubstr("hw_mode=g\n"));
+ EXPECT_THAT(config, HasSubstr("wowlan_triggers=any\n"));
+ EXPECT_THAT(config, HasSubstr("ignore_broadcast_ssid=0\n"));
+ EXPECT_THAT(config, Not(HasSubstr("ignore_broadcast_ssid=1\n")));
+}
+
} // namespace
TEST_F(HostapdManagerTest, GeneratesCorrectOpenConfig) {
string config = GetConfigForEncryptionType(
HostapdManager::EncryptionType::kOpen);
- EXPECT_FALSE(config.empty());
- EXPECT_EQ(kExpectedOpenConfig, config);
+ VerifyCommonConfigs(config);
}
TEST_F(HostapdManagerTest, GeneratesCorrectWpaConfig) {
string config = GetConfigForEncryptionType(
HostapdManager::EncryptionType::kWpa);
- EXPECT_FALSE(config.empty());
- EXPECT_EQ(kExpectedWpaConfig, config);
+ VerifyCommonConfigs(config);
+ EXPECT_THAT(config, HasSubstr("wpa=3\n"));
+ EXPECT_THAT(config, HasSubstr("wpa_pairwise=TKIP CCMP\n"));
+ EXPECT_THAT(config, HasSubstr(kConfigPskLine));
}
TEST_F(HostapdManagerTest, GeneratesCorrectWpa2Config) {
string config = GetConfigForEncryptionType(
HostapdManager::EncryptionType::kWpa2);
- EXPECT_FALSE(config.empty());
- EXPECT_EQ(kExpectedWpa2Config, config);
+ VerifyCommonConfigs(config);
+ EXPECT_THAT(config, HasSubstr("wpa=2\n"));
+ EXPECT_THAT(config, HasSubstr("rsn_pairwise=CCMP\n"));
+ EXPECT_THAT(config, HasSubstr(kConfigPskLine));
}
TEST_F(HostapdManagerTest, RespectsHiddenSetting) {
@@ -124,8 +107,8 @@ TEST_F(HostapdManagerTest, RespectsHiddenSetting) {
kTestChannel,
HostapdManager::EncryptionType::kOpen,
vector<uint8_t>());
- EXPECT_FALSE(config.find("ignore_broadcast_ssid=1\n") == string::npos);
- EXPECT_TRUE(config.find("ignore_broadcast_ssid=0\n") == string::npos);
+ EXPECT_THAT(config, HasSubstr("ignore_broadcast_ssid=1\n"));
+ EXPECT_THAT(config, Not(HasSubstr("ignore_broadcast_ssid=0\n")));
}
TEST_F(HostapdManagerTest, CorrectlyInfersHwMode) {
@@ -136,8 +119,8 @@ TEST_F(HostapdManagerTest, CorrectlyInfersHwMode) {
44,
HostapdManager::EncryptionType::kOpen,
vector<uint8_t>());
- EXPECT_FALSE(config.find("hw_mode=a\n") == string::npos);
- EXPECT_TRUE(config.find("hw_mode=g\n") == string::npos);
+ EXPECT_THAT(config, HasSubstr("hw_mode=a\n"));
+ EXPECT_THAT(config, Not(HasSubstr("hw_mode=g\n")));
}
diff --git a/libwifi_system_iface/Android.bp b/libwifi_system_iface/Android.bp
index 4be0aa01c..80249ef3c 100644
--- a/libwifi_system_iface/Android.bp
+++ b/libwifi_system_iface/Android.bp
@@ -26,9 +26,12 @@ wifi_system_iface_cflags = [
// Device independent wifi system logic.
// ============================================================
-cc_library_shared {
+cc_library {
name: "libwifi-system-iface",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
cflags: wifi_system_iface_cflags,
local_include_dirs: ["include"],
export_include_dirs: ["include"],
diff --git a/service/Android.mk b/service/Android.mk
index 155f5b295..5b539e5de 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -70,6 +70,11 @@ LOCAL_MODULE_TAGS :=
LOCAL_MODULE := wifi-service
LOCAL_INIT_RC := wifi-events.rc
+LOCAL_DEX_PREOPT_APP_IMAGE := false
+LOCAL_DEX_PREOPT_GENERATE_PROFILE := true
+LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING := frameworks/base/services/art-profile
+
+
include $(BUILD_JAVA_LIBRARY)
endif # !TARGET_BUILD_PDK
diff --git a/service/java/com/android/server/wifi/CarrierNetworkConfig.java b/service/java/com/android/server/wifi/CarrierNetworkConfig.java
new file mode 100644
index 000000000..c23213e8a
--- /dev/null
+++ b/service/java/com/android/server/wifi/CarrierNetworkConfig.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2017 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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.EAPConstants;
+import android.net.wifi.WifiEnterpriseConfig;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.util.Base64;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class for maintaining/caching carrier Wi-Fi network configurations.
+ */
+public class CarrierNetworkConfig {
+ private static final String TAG = "CarrierNetworkConfig";
+
+ private static final String NETWORK_CONFIG_SEPARATOR = ",";
+ private static final int ENCODED_SSID_INDEX = 0;
+ private static final int EAP_TYPE_INDEX = 1;
+ private static final int CONFIG_ELEMENT_SIZE = 2;
+
+ private final Map<String, NetworkInfo> mCarrierNetworkMap;
+
+ public CarrierNetworkConfig(Context context) {
+ mCarrierNetworkMap = new HashMap<>();
+ updateNetworkConfig(context);
+
+ // Monitor for carrier config changes.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateNetworkConfig(context);
+ }
+ }, filter);
+ }
+
+ /**
+ * @return true if the given SSID is associated with a carrier network
+ */
+ public boolean isCarrierNetwork(String ssid) {
+ return mCarrierNetworkMap.containsKey(ssid);
+ }
+
+ /**
+ * @return the EAP type associated with a carrier AP, or -1 if the specified AP
+ * is not associated with a carrier network
+ */
+ public int getNetworkEapType(String ssid) {
+ NetworkInfo info = mCarrierNetworkMap.get(ssid);
+ return info == null ? -1 : info.mEapType;
+ }
+
+ /**
+ * @return the name of carrier associated with a carrier AP, or null if the specified AP
+ * is not associated with a carrier network.
+ */
+ public String getCarrierName(String ssid) {
+ NetworkInfo info = mCarrierNetworkMap.get(ssid);
+ return info == null ? null : info.mCarrierName;
+ }
+
+ /**
+ * Utility class for storing carrier network information.
+ */
+ private static class NetworkInfo {
+ final int mEapType;
+ final String mCarrierName;
+
+ NetworkInfo(int eapType, String carrierName) {
+ mEapType = eapType;
+ mCarrierName = carrierName;
+ }
+ }
+
+ /**
+ * Update the carrier network map based on the current carrier configuration of the active
+ * subscriptions.
+ *
+ * @param context Current application context
+ */
+ private void updateNetworkConfig(Context context) {
+ // Reset network map.
+ mCarrierNetworkMap.clear();
+
+ CarrierConfigManager carrierConfigManager =
+ (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (carrierConfigManager == null) {
+ return;
+ }
+
+ SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ if (subscriptionManager == null) {
+ return;
+ }
+ List<SubscriptionInfo> subInfoList = subscriptionManager.getActiveSubscriptionInfoList();
+ if (subInfoList == null) {
+ return;
+ }
+
+ // Process the carrier config for each active subscription.
+ for (SubscriptionInfo subInfo : subInfoList) {
+ processNetworkConfig(
+ carrierConfigManager.getConfigForSubId(subInfo.getSubscriptionId()),
+ subInfo.getDisplayName().toString());
+ }
+ }
+
+ /**
+ * Process the carrier network config, the network config string is formatted as follow:
+ *
+ * "[Base64 Encoded SSID],[EAP Type]"
+ * Where EAP Type is the standard EAP method number, refer to
+ * http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml for more info.
+
+ * @param carrierConfig The bundle containing the carrier configuration
+ * @param carrierName The display name of the associated carrier
+ */
+ private void processNetworkConfig(PersistableBundle carrierConfig, String carrierName) {
+ if (carrierConfig == null) {
+ return;
+ }
+ String[] networkConfigs = carrierConfig.getStringArray(
+ CarrierConfigManager.KEY_CARRIER_WIFI_STRING_ARRAY);
+ if (networkConfigs == null) {
+ return;
+ }
+
+ for (String networkConfig : networkConfigs) {
+ String[] configArr = networkConfig.split(NETWORK_CONFIG_SEPARATOR);
+ if (configArr.length != CONFIG_ELEMENT_SIZE) {
+ Log.e(TAG, "Ignore invalid config: " + networkConfig);
+ continue;
+ }
+ try {
+ String ssid = new String(Base64.decode(
+ configArr[ENCODED_SSID_INDEX], Base64.DEFAULT));
+ int eapType = parseEapType(Integer.parseInt(configArr[EAP_TYPE_INDEX]));
+ // Verify EAP type, must be a SIM based EAP type.
+ if (eapType == -1) {
+ Log.e(TAG, "Invalid EAP type: " + configArr[EAP_TYPE_INDEX]);
+ continue;
+ }
+ mCarrierNetworkMap.put(ssid, new NetworkInfo(eapType, carrierName));
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Failed to parse EAP type: " + e.getMessage());
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed to decode SSID: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Convert a standard SIM-based EAP type (SIM, AKA, AKA') to the internal EAP type as defined in
+ * {@link WifiEnterpriseConfig.Eap}. -1 will be returned if the given EAP type is not
+ * SIM-based.
+ *
+ * @return SIM-based EAP type as defined in {@link WifiEnterpriseConfig.Eap}, or -1 if not
+ * SIM-based EAP type
+ */
+ private static int parseEapType(int eapType) {
+ if (eapType == EAPConstants.EAP_SIM) {
+ return WifiEnterpriseConfig.Eap.SIM;
+ } else if (eapType == EAPConstants.EAP_AKA) {
+ return WifiEnterpriseConfig.Eap.AKA;
+ } else if (eapType == EAPConstants.EAP_AKA_PRIME) {
+ return WifiEnterpriseConfig.Eap.AKA_PRIME;
+ }
+ return -1;
+ }
+}
diff --git a/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java b/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java
new file mode 100644
index 000000000..38c0ad058
--- /dev/null
+++ b/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 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.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.wifi.ScanResult;
+
+import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
+
+/**
+ * Helper to create notifications for {@link OpenNetworkNotifier}.
+ */
+public class ConnectToNetworkNotificationBuilder {
+
+ /** Intent when user dismissed the "Connect to Network" notification. */
+ public static final String ACTION_USER_DISMISSED_NOTIFICATION =
+ "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION";
+
+ /** Intent when user tapped action button to connect to recommended network. */
+ public static final String ACTION_CONNECT_TO_NETWORK =
+ "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK";
+
+ /** Intent when user tapped action button to open Wi-Fi Settings. */
+ public static final String ACTION_PICK_WIFI_NETWORK =
+ "com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK";
+
+ /** Intent when user tapped "Failed to connect" notification to open Wi-Fi Settings. */
+ public static final String ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE =
+ "com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE";
+
+ private Context mContext;
+ private Resources mResources;
+ private FrameworkFacade mFrameworkFacade;
+
+ public ConnectToNetworkNotificationBuilder(
+ Context context,
+ FrameworkFacade framework) {
+ mContext = context;
+ mResources = context.getResources();
+ mFrameworkFacade = framework;
+ }
+
+ /**
+ * Creates the connect to network notification that alerts users of a recommended connectable
+ * network.
+ *
+ * There are two actions - "Options" link to the Wi-Fi picker activity, and "Connect" prompts
+ * the connection to the recommended network.
+ *
+ * @param network The network to be recommended
+ */
+ public Notification createConnectToNetworkNotification(ScanResult network) {
+ Notification.Action connectAction = new Notification.Action.Builder(
+ null /* icon */,
+ mResources.getText(R.string.wifi_available_action_connect),
+ getPrivateBroadcast(ACTION_CONNECT_TO_NETWORK)).build();
+ Notification.Action allNetworksAction = new Notification.Action.Builder(
+ null /* icon */,
+ mResources.getText(R.string.wifi_available_action_all_networks),
+ getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK)).build();
+ return createNotificationBuilder(
+ mContext.getText(R.string.wifi_available_title), network.SSID)
+ .addAction(connectAction)
+ .addAction(allNetworksAction)
+ .build();
+ }
+
+ /**
+ * Creates the notification that indicates the controller is attempting to connect to the
+ * recommended network.
+ *
+ * @param network The network to be recommended
+ */
+ public Notification createNetworkConnectingNotification(ScanResult network) {
+ return createNotificationBuilder(
+ mContext.getText(R.string.wifi_available_title_connecting), network.SSID)
+ .setProgress(0 /* max */, 0 /* progress */, true /* indeterminate */)
+ .build();
+ }
+
+ /**
+ * Creates the notification that indicates the controller successfully connected to the
+ * recommended network.
+ *
+ * @param network The network to be recommended
+ */
+ public Notification createNetworkConnectedNotification(ScanResult network) {
+ return createNotificationBuilder(
+ mContext.getText(R.string.wifi_available_title_connected), network.SSID)
+ .build();
+ }
+
+ /**
+ * Creates the notification that indicates the controller failed to connect to the recommended
+ * network. Tapping this notification opens the wifi picker.
+ */
+ public Notification createNetworkFailedNotification() {
+ return createNotificationBuilder(
+ mContext.getText(R.string.wifi_available_title_failed_to_connect),
+ mContext.getText(R.string.wifi_available_content_failed_to_connect))
+ .setContentIntent(
+ getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE))
+ .setAutoCancel(true)
+ .build();
+ }
+
+ private Notification.Builder createNotificationBuilder(
+ CharSequence title, CharSequence content) {
+ return mFrameworkFacade.makeNotificationBuilder(mContext,
+ SystemNotificationChannels.NETWORK_AVAILABLE)
+ .setSmallIcon(R.drawable.stat_notify_wifi_in_range)
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setDeleteIntent(getPrivateBroadcast(ACTION_USER_DISMISSED_NOTIFICATION))
+ .setShowWhen(false)
+ .setLocalOnly(true)
+ .setColor(mResources.getColor(R.color.system_notification_accent_color,
+ mContext.getTheme()));
+ }
+
+ private PendingIntent getPrivateBroadcast(String action) {
+ Intent intent = new Intent(action).setPackage("android");
+ return mFrameworkFacade.getBroadcast(
+ mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+}
diff --git a/service/java/com/android/server/wifi/NetworkListStoreData.java b/service/java/com/android/server/wifi/NetworkListStoreData.java
index 5ddfd4dfb..f287d4b98 100644
--- a/service/java/com/android/server/wifi/NetworkListStoreData.java
+++ b/service/java/com/android/server/wifi/NetworkListStoreData.java
@@ -16,10 +16,12 @@
package com.android.server.wifi;
+import android.content.Context;
import android.net.IpConfiguration;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.net.wifi.WifiEnterpriseConfig;
+import android.os.Process;
import android.util.Log;
import android.util.Pair;
@@ -52,6 +54,8 @@ public class NetworkListStoreData implements WifiConfigStore.StoreData {
private static final String XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION =
"WifiEnterpriseConfiguration";
+ private final Context mContext;
+
/**
* List of saved shared networks visible to all the users to be stored in the shared store file.
*/
@@ -62,7 +66,9 @@ public class NetworkListStoreData implements WifiConfigStore.StoreData {
*/
private List<WifiConfiguration> mUserConfigurations;
- NetworkListStoreData() {}
+ NetworkListStoreData(Context context) {
+ mContext = context;
+ }
@Override
public void serializeData(XmlSerializer out, boolean shared)
@@ -282,6 +288,19 @@ public class NetworkListStoreData implements WifiConfigStore.StoreData {
"Configuration key does not match. Retrieved: " + configKeyParsed
+ ", Calculated: " + configKeyCalculated);
}
+ // Set creatorUid/creatorName for networks which don't have it set to valid value.
+ String creatorName = mContext.getPackageManager().getNameForUid(configuration.creatorUid);
+ if (creatorName == null) {
+ Log.e(TAG, "Invalid creatorUid for saved network " + configuration.configKey()
+ + ", creatorUid=" + configuration.creatorUid);
+ configuration.creatorUid = Process.SYSTEM_UID;
+ configuration.creatorName = creatorName;
+ } else if (!creatorName.equals(configuration.creatorName)) {
+ Log.w(TAG, "Invalid creatorName for saved network " + configuration.configKey()
+ + ", creatorUid=" + configuration.creatorUid
+ + ", creatorName=" + configuration.creatorName);
+ configuration.creatorName = creatorName;
+ }
configuration.setNetworkSelectionStatus(status);
configuration.setIpConfiguration(ipConfiguration);
diff --git a/service/java/com/android/server/wifi/OpenNetworkNotifier.java b/service/java/com/android/server/wifi/OpenNetworkNotifier.java
new file mode 100644
index 000000000..eee4ac53c
--- /dev/null
+++ b/service/java/com/android/server/wifi/OpenNetworkNotifier.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2013 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 com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK;
+import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK;
+import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE;
+import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_USER_DISMISSED_NOTIFICATION;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
+import com.android.server.wifi.util.ScanResultUtil;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Takes care of handling the "open wi-fi network available" notification
+ *
+ * NOTE: These API's are not thread safe and should only be used from WifiStateMachine thread.
+ * @hide
+ */
+public class OpenNetworkNotifier {
+
+ private static final String TAG = "OpenNetworkNotifier";
+
+ /** Time in milliseconds to display the Connecting notification. */
+ private static final int TIME_TO_SHOW_CONNECTING_MILLIS = 10000;
+
+ /** Time in milliseconds to display the Connected notification. */
+ private static final int TIME_TO_SHOW_CONNECTED_MILLIS = 5000;
+
+ /** Time in milliseconds to display the Failed To Connect notification. */
+ private static final int TIME_TO_SHOW_FAILED_MILLIS = 5000;
+
+ /** The state of the notification */
+ @IntDef({
+ STATE_NO_NOTIFICATION,
+ STATE_SHOWING_RECOMMENDATION_NOTIFICATION,
+ STATE_CONNECTING_IN_NOTIFICATION,
+ STATE_CONNECTED_NOTIFICATION,
+ STATE_CONNECT_FAILED_NOTIFICATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface State {}
+
+ /** No recommendation is made and no notifications are shown. */
+ private static final int STATE_NO_NOTIFICATION = 0;
+ /** The initial notification recommending an open network to connect to is shown. */
+ private static final int STATE_SHOWING_RECOMMENDATION_NOTIFICATION = 1;
+ /** The notification of status of connecting to the recommended network is shown. */
+ private static final int STATE_CONNECTING_IN_NOTIFICATION = 2;
+ /** The notification that the connection to the recommended network was successful is shown. */
+ private static final int STATE_CONNECTED_NOTIFICATION = 3;
+ /** The notification to show that connection to the recommended network failed is shown. */
+ private static final int STATE_CONNECT_FAILED_NOTIFICATION = 4;
+
+ /** Current state of the notification. */
+ @State private int mState = STATE_NO_NOTIFICATION;
+
+ /** Identifier of the {@link SsidSetStoreData}. */
+ private static final String STORE_DATA_IDENTIFIER = "OpenNetworkNotifierBlacklist";
+ /**
+ * The {@link Clock#getWallClockMillis()} must be at least this value for us
+ * to show the notification again.
+ */
+ private long mNotificationRepeatTime;
+ /**
+ * When a notification is shown, we wait this amount before possibly showing it again.
+ */
+ private final long mNotificationRepeatDelay;
+ /** Default repeat delay in seconds. */
+ @VisibleForTesting
+ static final int DEFAULT_REPEAT_DELAY_SEC = 900;
+
+ /** Whether the user has set the setting to show the 'available networks' notification. */
+ private boolean mSettingEnabled;
+ /** Whether the screen is on or not. */
+ private boolean mScreenOn;
+
+ /** List of SSIDs blacklisted from recommendation. */
+ private final Set<String> mBlacklistedSsids;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final FrameworkFacade mFrameworkFacade;
+ private final WifiMetrics mWifiMetrics;
+ private final Clock mClock;
+ private final WifiConfigManager mConfigManager;
+ private final WifiStateMachine mWifiStateMachine;
+ private final Messenger mSrcMessenger;
+ private final OpenNetworkRecommender mOpenNetworkRecommender;
+ private final ConnectToNetworkNotificationBuilder mNotificationBuilder;
+
+ private ScanResult mRecommendedNetwork;
+
+ OpenNetworkNotifier(
+ Context context,
+ Looper looper,
+ FrameworkFacade framework,
+ Clock clock,
+ WifiMetrics wifiMetrics,
+ WifiConfigManager wifiConfigManager,
+ WifiConfigStore wifiConfigStore,
+ WifiStateMachine wifiStateMachine,
+ OpenNetworkRecommender openNetworkRecommender,
+ ConnectToNetworkNotificationBuilder connectToNetworkNotificationBuilder) {
+ mContext = context;
+ mHandler = new Handler(looper);
+ mFrameworkFacade = framework;
+ mWifiMetrics = wifiMetrics;
+ mClock = clock;
+ mConfigManager = wifiConfigManager;
+ mWifiStateMachine = wifiStateMachine;
+ mOpenNetworkRecommender = openNetworkRecommender;
+ mNotificationBuilder = connectToNetworkNotificationBuilder;
+ mScreenOn = false;
+ mSrcMessenger = new Messenger(new Handler(looper, mConnectionStateCallback));
+
+ mBlacklistedSsids = new ArraySet<>();
+ wifiConfigStore.registerStoreData(new SsidSetStoreData(
+ STORE_DATA_IDENTIFIER, new OpenNetworkNotifierStoreData()));
+
+ // Setting is in seconds
+ mNotificationRepeatDelay = mFrameworkFacade.getIntegerSetting(context,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ DEFAULT_REPEAT_DELAY_SEC) * 1000L;
+ NotificationEnabledSettingObserver settingObserver = new NotificationEnabledSettingObserver(
+ mHandler);
+ settingObserver.register();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USER_DISMISSED_NOTIFICATION);
+ filter.addAction(ACTION_CONNECT_TO_NETWORK);
+ filter.addAction(ACTION_PICK_WIFI_NETWORK);
+ filter.addAction(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE);
+ mContext.registerReceiver(
+ mBroadcastReceiver, filter, null /* broadcastPermission */, mHandler);
+ }
+
+ private final BroadcastReceiver mBroadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case ACTION_USER_DISMISSED_NOTIFICATION:
+ handleUserDismissedAction();
+ break;
+ case ACTION_CONNECT_TO_NETWORK:
+ handleConnectToNetworkAction();
+ break;
+ case ACTION_PICK_WIFI_NETWORK:
+ handleSeeAllNetworksAction();
+ break;
+ case ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE:
+ handlePickWifiNetworkAfterConnectFailure();
+ break;
+ default:
+ Log.e(TAG, "Unknown action " + intent.getAction());
+ }
+ }
+ };
+
+ private final Handler.Callback mConnectionStateCallback = (Message msg) -> {
+ switch (msg.what) {
+ // Success here means that an attempt to connect to the network has been initiated.
+ // Successful connection updates are received via the
+ // WifiConnectivityManager#handleConnectionStateChanged() callback.
+ case WifiManager.CONNECT_NETWORK_SUCCEEDED:
+ break;
+ case WifiManager.CONNECT_NETWORK_FAILED:
+ handleConnectionAttemptFailedToSend();
+ break;
+ default:
+ Log.e(TAG, "Unknown message " + msg.what);
+ }
+ return true;
+ };
+
+ /**
+ * Clears the pending notification. This is called by {@link WifiConnectivityManager} on stop.
+ *
+ * @param resetRepeatTime resets the time delay for repeated notification if true.
+ */
+ public void clearPendingNotification(boolean resetRepeatTime) {
+ if (resetRepeatTime) {
+ mNotificationRepeatTime = 0;
+ }
+
+ if (mState != STATE_NO_NOTIFICATION) {
+ getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_AVAILABLE);
+
+ if (mRecommendedNetwork != null) {
+ Log.d(TAG, "Notification with state="
+ + mState
+ + " was cleared for recommended network: "
+ + mRecommendedNetwork.SSID);
+ }
+ mState = STATE_NO_NOTIFICATION;
+ mRecommendedNetwork = null;
+ }
+ }
+
+ private boolean isControllerEnabled() {
+ return mSettingEnabled && !UserManager.get(mContext)
+ .hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT);
+ }
+
+ /**
+ * If there are open networks, attempt to post an open network notification.
+ *
+ * @param availableNetworks Available networks from
+ * {@link WifiNetworkSelector.NetworkEvaluator#getFilteredScanDetailsForOpenUnsavedNetworks()}.
+ */
+ public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) {
+ if (!isControllerEnabled()) {
+ clearPendingNotification(true /* resetRepeatTime */);
+ return;
+ }
+ if (availableNetworks.isEmpty()) {
+ clearPendingNotification(false /* resetRepeatTime */);
+ return;
+ }
+
+ // Not enough time has passed to show a recommendation notification again
+ if (mState == STATE_NO_NOTIFICATION
+ && mClock.getWallClockMillis() < mNotificationRepeatTime) {
+ return;
+ }
+
+ // Do nothing when the screen is off and no notification is showing.
+ if (mState == STATE_NO_NOTIFICATION && !mScreenOn) {
+ return;
+ }
+
+ // Only show a new or update an existing recommendation notification.
+ if (mState == STATE_NO_NOTIFICATION
+ || mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) {
+ ScanResult recommendation = mOpenNetworkRecommender.recommendNetwork(
+ availableNetworks, new ArraySet<>(mBlacklistedSsids));
+
+ if (recommendation != null) {
+ postInitialNotification(recommendation);
+ } else {
+ clearPendingNotification(false /* resetRepeatTime */);
+ }
+ }
+ }
+
+ /** Handles screen state changes. */
+ public void handleScreenStateChanged(boolean screenOn) {
+ mScreenOn = screenOn;
+ }
+
+ /**
+ * Called by {@link WifiConnectivityManager} when Wi-Fi is connected. If the notification
+ * was in the connecting state, update the notification to show that it has connected to the
+ * recommended network.
+ */
+ public void handleWifiConnected() {
+ if (mState != STATE_CONNECTING_IN_NOTIFICATION) {
+ clearPendingNotification(true /* resetRepeatTime */);
+ return;
+ }
+
+ postNotification(mNotificationBuilder.createNetworkConnectedNotification(
+ mRecommendedNetwork));
+
+ Log.d(TAG, "User connected to recommended network: " + mRecommendedNetwork.SSID);
+ mWifiMetrics.incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTED_TO_NETWORK);
+ mState = STATE_CONNECTED_NOTIFICATION;
+ mHandler.postDelayed(
+ () -> {
+ if (mState == STATE_CONNECTED_NOTIFICATION) {
+ clearPendingNotification(true /* resetRepeatTime */);
+ }
+ },
+ TIME_TO_SHOW_CONNECTED_MILLIS);
+ }
+
+ /**
+ * Handles when a Wi-Fi connection attempt failed.
+ */
+ public void handleConnectionFailure() {
+ if (mState != STATE_CONNECTING_IN_NOTIFICATION) {
+ return;
+ }
+ postNotification(mNotificationBuilder.createNetworkFailedNotification());
+
+ Log.d(TAG, "User failed to connect to recommended network: " + mRecommendedNetwork.SSID);
+ mWifiMetrics.incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_FAILED_TO_CONNECT);
+ mState = STATE_CONNECT_FAILED_NOTIFICATION;
+ mHandler.postDelayed(
+ () -> {
+ if (mState == STATE_CONNECT_FAILED_NOTIFICATION) {
+ clearPendingNotification(false /* resetRepeatTime */);
+ }
+ },
+ TIME_TO_SHOW_FAILED_MILLIS);
+ }
+
+ private NotificationManager getNotificationManager() {
+ return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ private void postInitialNotification(ScanResult recommendedNetwork) {
+ if (mRecommendedNetwork != null
+ && TextUtils.equals(mRecommendedNetwork.SSID, recommendedNetwork.SSID)) {
+ return;
+ }
+ postNotification(mNotificationBuilder.createConnectToNetworkNotification(
+ recommendedNetwork));
+ if (mState == STATE_NO_NOTIFICATION) {
+ mWifiMetrics.incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ } else {
+ mWifiMetrics.incrementNumOpenNetworkRecommendationUpdates();
+ }
+ mState = STATE_SHOWING_RECOMMENDATION_NOTIFICATION;
+ mRecommendedNetwork = recommendedNetwork;
+ mNotificationRepeatTime = mClock.getWallClockMillis() + mNotificationRepeatDelay;
+ }
+
+ private void postNotification(Notification notification) {
+ getNotificationManager().notify(SystemMessage.NOTE_NETWORK_AVAILABLE, notification);
+ }
+
+ private void handleConnectToNetworkAction() {
+ mWifiMetrics.incrementConnectToNetworkNotificationAction(mState,
+ ConnectToNetworkNotificationAndActionCount.ACTION_CONNECT_TO_NETWORK);
+ if (mState != STATE_SHOWING_RECOMMENDATION_NOTIFICATION) {
+ return;
+ }
+ postNotification(mNotificationBuilder.createNetworkConnectingNotification(
+ mRecommendedNetwork));
+ mWifiMetrics.incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTING_TO_NETWORK);
+
+ Log.d(TAG, "User initiated connection to recommended network: " + mRecommendedNetwork.SSID);
+ WifiConfiguration network = ScanResultUtil.createNetworkFromScanResult(mRecommendedNetwork);
+ Message msg = Message.obtain();
+ msg.what = WifiManager.CONNECT_NETWORK;
+ msg.arg1 = WifiConfiguration.INVALID_NETWORK_ID;
+ msg.obj = network;
+ msg.replyTo = mSrcMessenger;
+ mWifiStateMachine.sendMessage(msg);
+
+ mState = STATE_CONNECTING_IN_NOTIFICATION;
+ mHandler.postDelayed(
+ () -> {
+ if (mState == STATE_CONNECTING_IN_NOTIFICATION) {
+ handleConnectionFailure();
+ }
+ },
+ TIME_TO_SHOW_CONNECTING_MILLIS);
+ }
+
+ private void handleSeeAllNetworksAction() {
+ mWifiMetrics.incrementConnectToNetworkNotificationAction(mState,
+ ConnectToNetworkNotificationAndActionCount.ACTION_PICK_WIFI_NETWORK);
+ startWifiSettings();
+ }
+
+ private void startWifiSettings() {
+ // Close notification drawer before opening the picker.
+ mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ mContext.startActivity(
+ new Intent(Settings.ACTION_WIFI_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ clearPendingNotification(false /* resetRepeatTime */);
+ }
+
+ private void handleConnectionAttemptFailedToSend() {
+ handleConnectionFailure();
+ mWifiMetrics.incrementNumOpenNetworkConnectMessageFailedToSend();
+ }
+
+ private void handlePickWifiNetworkAfterConnectFailure() {
+ mWifiMetrics.incrementConnectToNetworkNotificationAction(mState,
+ ConnectToNetworkNotificationAndActionCount
+ .ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE);
+ startWifiSettings();
+ }
+
+ private void handleUserDismissedAction() {
+ Log.d(TAG, "User dismissed notification with state=" + mState);
+ mWifiMetrics.incrementConnectToNetworkNotificationAction(mState,
+ ConnectToNetworkNotificationAndActionCount.ACTION_USER_DISMISSED_NOTIFICATION);
+ if (mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) {
+ // blacklist dismissed network
+ mBlacklistedSsids.add(mRecommendedNetwork.SSID);
+ mWifiMetrics.setOpenNetworkRecommenderBlacklistSize(mBlacklistedSsids.size());
+ mConfigManager.saveToStore(false /* forceWrite */);
+ Log.d(TAG, "Network is added to the open network notification blacklist: "
+ + mRecommendedNetwork.SSID);
+ }
+ resetStateAndDelayNotification();
+ }
+
+ private void resetStateAndDelayNotification() {
+ mState = STATE_NO_NOTIFICATION;
+ mNotificationRepeatTime = System.currentTimeMillis() + mNotificationRepeatDelay;
+ mRecommendedNetwork = null;
+ }
+
+ /** Dump ONA controller state. */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("OpenNetworkNotifier: ");
+ pw.println("mSettingEnabled " + mSettingEnabled);
+ pw.println("currentTime: " + mClock.getWallClockMillis());
+ pw.println("mNotificationRepeatTime: " + mNotificationRepeatTime);
+ pw.println("mState: " + mState);
+ pw.println("mBlacklistedSsids: " + mBlacklistedSsids.toString());
+ }
+
+ private class OpenNetworkNotifierStoreData implements SsidSetStoreData.DataSource {
+ @Override
+ public Set<String> getSsids() {
+ return new ArraySet<>(mBlacklistedSsids);
+ }
+
+ @Override
+ public void setSsids(Set<String> ssidList) {
+ mBlacklistedSsids.addAll(ssidList);
+ mWifiMetrics.setOpenNetworkRecommenderBlacklistSize(mBlacklistedSsids.size());
+ }
+ }
+
+ private class NotificationEnabledSettingObserver extends ContentObserver {
+ NotificationEnabledSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register() {
+ mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
+ mSettingEnabled = getValue();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ mSettingEnabled = getValue();
+ clearPendingNotification(true /* resetRepeatTime */);
+ }
+
+ private boolean getValue() {
+ boolean enabled = mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
+ mWifiMetrics.setIsWifiNetworksAvailableNotificationEnabled(enabled);
+ return enabled;
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/OpenNetworkRecommender.java b/service/java/com/android/server/wifi/OpenNetworkRecommender.java
new file mode 100644
index 000000000..5ceeddded
--- /dev/null
+++ b/service/java/com/android/server/wifi/OpenNetworkRecommender.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.net.wifi.ScanResult;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helps recommend the best available network for {@link OpenNetworkNotifier}.
+ *
+ * NOTE: These API's are not thread safe and should only be used from WifiStateMachine thread.
+ * @hide
+ */
+public class OpenNetworkRecommender {
+
+ /**
+ * Recommends the network with the best signal strength.
+ *
+ * @param networks List of scan details to pick a recommendation. This list should not be null
+ * or empty.
+ * @param blacklistedSsids The list of SSIDs that should not be recommended.
+ */
+ public ScanResult recommendNetwork(@NonNull List<ScanDetail> networks,
+ @NonNull Set<String> blacklistedSsids) {
+ ScanResult result = null;
+ int highestRssi = Integer.MIN_VALUE;
+ for (ScanDetail scanDetail : networks) {
+ ScanResult scanResult = scanDetail.getScanResult();
+
+ if (scanResult.level > highestRssi) {
+ result = scanResult;
+ highestRssi = scanResult.level;
+ }
+ }
+
+ if (result != null && blacklistedSsids.contains(result.SSID)) {
+ result = null;
+ }
+ return result;
+ }
+}
diff --git a/service/java/com/android/server/wifi/RttService.java b/service/java/com/android/server/wifi/RttService.java
index 7e4648b10..bd2736726 100644
--- a/service/java/com/android/server/wifi/RttService.java
+++ b/service/java/com/android/server/wifi/RttService.java
@@ -6,11 +6,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.net.wifi.IApInterface;
-import android.net.wifi.IClientInterface;
-import android.net.wifi.IInterfaceEventCallback;
import android.net.wifi.IRttManager;
-import android.net.wifi.IWificond;
import android.net.wifi.RttManager;
import android.net.wifi.RttManager.ResponderConfig;
import android.net.wifi.WifiManager;
@@ -26,6 +22,7 @@ import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.AsyncChannel;
@@ -40,22 +37,64 @@ import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
-import java.util.List;
import java.util.Queue;
import java.util.Set;
public final class RttService extends SystemService {
public static final boolean DBG = true;
- private static final String WIFICOND_SERVICE_NAME = "wificond";
static class RttServiceImpl extends IRttManager.Stub {
+ private int mCurrentKey = 100; // increment on each usage
+ private final SparseArray<IBinder> mBinderByKey = new SparseArray<>();
@Override
- public Messenger getMessenger() {
+ public Messenger getMessenger(IBinder binder, int[] key) {
+ if (key != null && key.length != 0) {
+ final int keyToUse = mCurrentKey++;
+ if (binder != null) {
+ try {
+ binder.linkToDeath(() -> {
+ // clean-up here if didn't get final registration
+ Slog.d(TAG, "Binder death on key=" + keyToUse);
+ mBinderByKey.delete(keyToUse);
+ }, 0);
+ mBinderByKey.put(keyToUse, binder);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "getMessenger: can't link to death on binder: " + e);
+ return null;
+ }
+ }
+
+ key[0] = keyToUse;
+ }
return new Messenger(mClientHandler);
}
+ private class RttDeathListener implements IBinder.DeathRecipient {
+ private final IBinder mBinder;
+ private final Messenger mReplyTo;
+
+ RttDeathListener(IBinder binder, Messenger replyTo) {
+ mBinder = binder;
+ mReplyTo = replyTo;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DBG) Slog.d(TAG, "binder death for client mReplyTo=" + mReplyTo);
+ synchronized (mLock) {
+ ClientInfo ci = mClients.remove(mReplyTo);
+ if (ci != null) {
+ ci.cleanup();
+ } else {
+ Slog.w(TAG,
+ "ClientInfo not found for terminated app -- mReplyTo=" + mReplyTo);
+ }
+ }
+ }
+ }
+
private class ClientHandler extends Handler {
ClientHandler(android.os.Looper looper) {
@@ -86,13 +125,30 @@ public final class RttService extends SystemService {
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
AsyncChannel ac = new AsyncChannel();
ac.connected(mContext, this, msg.replyTo);
- ClientInfo client = new ClientInfo(ac, msg.sendingUid);
+ String packageName = msg.obj != null
+ ? ((RttManager.RttClient) msg.obj).getPackageName() : null;
+ ClientInfo client = new ClientInfo(ac, msg.sendingUid, packageName);
synchronized (mLock) {
mClients.put(msg.replyTo, client);
}
ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
AsyncChannel.STATUS_SUCCESSFUL);
return;
+ case RttManager.CMD_OP_REG_BINDER: {
+ int key = msg.arg1;
+ IBinder binder = mBinderByKey.get(key);
+ if (binder == null) {
+ Slog.e(TAG, "Can't find binder registered with key=" + key + " - no "
+ + "death listener!");
+ return;
+ }
+ try {
+ binder.linkToDeath(new RttDeathListener(binder, msg.replyTo), 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Can't link to death for binder on key=" + key);
+ }
+ return;
+ }
}
ClientInfo ci;
@@ -109,6 +165,12 @@ public final class RttService extends SystemService {
"Client doesn't have LOCATION_HARDWARE permission");
return;
}
+ if (!checkLocationPermission(ci)) {
+ replyFailed(msg, RttManager.REASON_PERMISSION_DENIED,
+ "Client doesn't have ACCESS_COARSE_LOCATION or "
+ + "ACCESS_FINE_LOCATION permission");
+ return;
+ }
final int validCommands[] = {
RttManager.CMD_OP_START_RANGING,
RttManager.CMD_OP_STOP_RANGING,
@@ -141,9 +203,10 @@ public final class RttService extends SystemService {
private final WifiNative mWifiNative;
private final Context mContext;
private final Looper mLooper;
+ private final WifiInjector mWifiInjector;
+
private RttStateMachine mStateMachine;
private ClientHandler mClientHandler;
- private WifiInjector mWifiInjector;
RttServiceImpl(Context context, Looper looper, WifiInjector wifiInjector) {
mContext = context;
@@ -192,14 +255,16 @@ public final class RttService extends SystemService {
private class ClientInfo {
private final AsyncChannel mChannel;
private final int mUid;
+ private final String mPackageName;
ArrayMap<Integer, RttRequest> mRequests = new ArrayMap<>();
// Client keys of all outstanding responders.
Set<Integer> mResponderRequests = new HashSet<>();
- ClientInfo(AsyncChannel channel, int uid) {
+ ClientInfo(AsyncChannel channel, int uid, String packageName) {
mChannel = channel;
mUid = uid;
+ mPackageName = packageName;
}
void addResponderRequest(int key) {
@@ -293,37 +358,11 @@ public final class RttService extends SystemService {
private static final int CMD_DRIVER_UNLOADED = BASE + 1;
private static final int CMD_ISSUE_NEXT_REQUEST = BASE + 2;
private static final int CMD_RTT_RESPONSE = BASE + 3;
- private static final int CMD_CLIENT_INTERFACE_READY = BASE + 4;
- private static final int CMD_CLIENT_INTERFACE_DOWN = BASE + 5;
// Maximum duration for responder role.
private static final int MAX_RESPONDER_DURATION_SECONDS = 60 * 10;
- private static class InterfaceEventHandler extends IInterfaceEventCallback.Stub {
- InterfaceEventHandler(RttStateMachine rttStateMachine) {
- mRttStateMachine = rttStateMachine;
- }
- @Override
- public void OnClientTorndownEvent(IClientInterface networkInterface) {
- mRttStateMachine.sendMessage(CMD_CLIENT_INTERFACE_DOWN, networkInterface);
- }
- @Override
- public void OnClientInterfaceReady(IClientInterface networkInterface) {
- mRttStateMachine.sendMessage(CMD_CLIENT_INTERFACE_READY, networkInterface);
- }
- @Override
- public void OnApTorndownEvent(IApInterface networkInterface) { }
- @Override
- public void OnApInterfaceReady(IApInterface networkInterface) { }
-
- private RttStateMachine mRttStateMachine;
- }
-
class RttStateMachine extends StateMachine {
- private IWificond mWificond;
- private InterfaceEventHandler mInterfaceEventHandler;
- private IClientInterface mClientInterface;
-
DefaultState mDefaultState = new DefaultState();
EnabledState mEnabledState = new EnabledState();
InitiatorEnabledState mInitiatorEnabledState = new InitiatorEnabledState();
@@ -385,39 +424,9 @@ public final class RttService extends SystemService {
class EnabledState extends State {
@Override
public void enter() {
- // This allows us to tolerate wificond restarts.
- // When wificond restarts WifiStateMachine is supposed to go
- // back to initial state and restart.
- // 1) RttService watches for WIFI_STATE_ENABLED broadcasts
- // 2) WifiStateMachine sends these broadcasts in the SupplicantStarted state
- // 3) Since WSM will only be in SupplicantStarted for as long as wificond is
- // alive, we refresh our wificond handler here and we don't subscribe to
- // wificond's death explicitly.
- mWificond = mWifiInjector.makeWificond();
- if (mWificond == null) {
- Log.w(TAG, "Failed to get wificond binder handler");
- transitionTo(mDefaultState);
- }
- mInterfaceEventHandler = new InterfaceEventHandler(mStateMachine);
- try {
- mWificond.RegisterCallback(mInterfaceEventHandler);
- // Get the current client interface, assuming there is at most
- // one client interface for now.
- List<IBinder> interfaces = mWificond.GetClientInterfaces();
- if (interfaces.size() > 0) {
- mStateMachine.sendMessage(
- CMD_CLIENT_INTERFACE_READY,
- IClientInterface.Stub.asInterface(interfaces.get(0)));
- }
- } catch (RemoteException e1) { }
-
}
@Override
public void exit() {
- try {
- mWificond.UnregisterCallback(mInterfaceEventHandler);
- } catch (RemoteException e1) { }
- mInterfaceEventHandler = null;
}
@Override
public boolean processMessage(Message msg) {
@@ -481,14 +490,6 @@ public final class RttService extends SystemService {
break;
case RttManager.CMD_OP_DISABLE_RESPONDER:
break;
- case CMD_CLIENT_INTERFACE_DOWN:
- if (mClientInterface == (IClientInterface) msg.obj) {
- mClientInterface = null;
- }
- break;
- case CMD_CLIENT_INTERFACE_READY:
- mClientInterface = (IClientInterface) msg.obj;
- break;
default:
return NOT_HANDLED;
}
@@ -534,8 +535,10 @@ public final class RttService extends SystemService {
break;
case CMD_RTT_RESPONSE:
if (DBG) Log.d(TAG, "Received an RTT response from: " + msg.arg2);
- mOutstandingRequest.ci.reportResult(
- mOutstandingRequest, (RttManager.RttResult[])msg.obj);
+ if (checkLocationPermission(mOutstandingRequest.ci)) {
+ mOutstandingRequest.ci.reportResult(
+ mOutstandingRequest, (RttManager.RttResult[]) msg.obj);
+ }
mOutstandingRequest = null;
sendMessage(CMD_ISSUE_NEXT_REQUEST);
break;
@@ -659,7 +662,7 @@ public final class RttService extends SystemService {
}
}
- boolean enforcePermissionCheck(Message msg) {
+ private boolean enforcePermissionCheck(Message msg) {
try {
mContext.enforcePermission(Manifest.permission.LOCATION_HARDWARE,
-1, msg.sendingUid, "LocationRTT");
@@ -670,6 +673,12 @@ public final class RttService extends SystemService {
return true;
}
+ // Returns whether the client has location permission.
+ private boolean checkLocationPermission(ClientInfo clientInfo) {
+ return mWifiInjector.getWifiPermissionsUtil().checkCallersLocationPermission(
+ clientInfo.mPackageName, clientInfo.mUid);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -717,8 +726,11 @@ public final class RttService extends SystemService {
if (DBG) Log.d(TAG, "No more requests left");
return null;
}
+
@Override
public RttManager.RttCapabilities getRttCapabilities() {
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access rtt capabilities");
return mWifiNative.getRttCapabilities();
}
}
diff --git a/service/java/com/android/server/wifi/ScanDetailCache.java b/service/java/com/android/server/wifi/ScanDetailCache.java
index 3b69a641b..abb6ad8b0 100644
--- a/service/java/com/android/server/wifi/ScanDetailCache.java
+++ b/service/java/com/android/server/wifi/ScanDetailCache.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.os.SystemClock;
@@ -73,7 +74,7 @@ public class ScanDetailCache {
* @param bssid provided BSSID
* @return {@code null} if no match ScanResult is found.
*/
- public ScanResult get(String bssid) {
+ public ScanResult getScanResult(String bssid) {
ScanDetail scanDetail = getScanDetail(bssid);
return scanDetail == null ? null : scanDetail.getScanResult();
}
@@ -84,11 +85,11 @@ public class ScanDetailCache {
* @param bssid provided BSSID
* @return {@code null} if no match ScanDetail is found.
*/
- public ScanDetail getScanDetail(String bssid) {
+ public ScanDetail getScanDetail(@NonNull String bssid) {
return mMap.get(bssid);
}
- void remove(String bssid) {
+ void remove(@NonNull String bssid) {
mMap.remove(bssid);
}
diff --git a/service/java/com/android/server/wifi/SelfRecovery.java b/service/java/com/android/server/wifi/SelfRecovery.java
index 21a3e0ac7..e39e0d5b0 100644
--- a/service/java/com/android/server/wifi/SelfRecovery.java
+++ b/service/java/com/android/server/wifi/SelfRecovery.java
@@ -72,7 +72,7 @@ public class SelfRecovery {
Log.e(TAG, "Invalid trigger reason. Ignoring...");
return;
}
- Log.wtf(TAG, "Triggering recovery for reason: " + REASON_STRINGS[reason]);
+ Log.e(TAG, "Triggering recovery for reason: " + REASON_STRINGS[reason]);
if (reason == REASON_WIFICOND_CRASH || reason == REASON_HAL_CRASH) {
trimPastRestartTimes();
// Ensure there haven't been too many restarts within MAX_RESTARTS_TIME_WINDOW
diff --git a/service/java/com/android/server/wifi/SsidSetStoreData.java b/service/java/com/android/server/wifi/SsidSetStoreData.java
new file mode 100644
index 000000000..daed26a6a
--- /dev/null
+++ b/service/java/com/android/server/wifi/SsidSetStoreData.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 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.text.TextUtils;
+
+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.HashSet;
+import java.util.Set;
+
+/**
+ * Store data for network notifiers.
+ *
+ * Below are the current configuration data for each respective store file:
+ *
+ * Share Store (system wide configurations)
+ * - No data
+ *
+ * User Store (user specific configurations)
+ * - Set of blacklisted SSIDs
+ */
+public class SsidSetStoreData implements WifiConfigStore.StoreData {
+ private static final String XML_TAG_SECTION_HEADER_SUFFIX = "ConfigData";
+ private static final String XML_TAG_SSID_SET = "SSIDSet";
+
+ private final String mTagName;
+ private final DataSource mDataSource;
+
+ /**
+ * Interface define the data source for the notifier store data.
+ */
+ public interface DataSource {
+ /**
+ * Retrieve the SSID set from the data source.
+ *
+ * @return Set of SSIDs
+ */
+ Set<String> getSsids();
+
+ /**
+ * Update the SSID set in the data source.
+ *
+ * @param ssidSet The set of SSIDs
+ */
+ void setSsids(Set<String> ssidSet);
+ }
+
+ /**
+ * Creates the SSID Set store data.
+ *
+ * @param name Identifier of the SSID set.
+ * @param dataSource The DataSource that implements the update and retrieval of the SSID set.
+ */
+ SsidSetStoreData(String name, DataSource dataSource) {
+ mTagName = name + XML_TAG_SECTION_HEADER_SUFFIX;
+ mDataSource = dataSource;
+ }
+
+ @Override
+ public void serializeData(XmlSerializer out, boolean shared)
+ throws XmlPullParserException, IOException {
+ if (shared) {
+ throw new XmlPullParserException("Share data not supported");
+ }
+ Set<String> ssidSet = mDataSource.getSsids();
+ if (ssidSet != null && !ssidSet.isEmpty()) {
+ XmlUtil.writeNextValue(out, XML_TAG_SSID_SET, mDataSource.getSsids());
+ }
+ }
+
+ @Override
+ public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared)
+ throws XmlPullParserException, IOException {
+ if (shared) {
+ throw new XmlPullParserException("Share data not supported");
+ }
+
+ while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
+ String[] valueName = new String[1];
+ Object value = XmlUtil.readCurrentValue(in, valueName);
+ if (TextUtils.isEmpty(valueName[0])) {
+ throw new XmlPullParserException("Missing value name");
+ }
+ switch (valueName[0]) {
+ case XML_TAG_SSID_SET:
+ mDataSource.setSsids((Set<String>) value);
+ break;
+ default:
+ throw new XmlPullParserException("Unknown tag under "
+ + mTagName + ": " + valueName[0]);
+ }
+ }
+ }
+
+ @Override
+ public void resetData(boolean shared) {
+ if (!shared) {
+ mDataSource.setSsids(new HashSet<>());
+ }
+ }
+
+ @Override
+ public String getName() {
+ return mTagName;
+ }
+
+ @Override
+ public boolean supportShareData() {
+ return false;
+ }
+}
diff --git a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java
index 61ec9b3ab..b35989797 100644
--- a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java
+++ b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java
@@ -199,7 +199,7 @@ public class SupplicantStaNetworkHal {
for (int i = 0; i < 4; i++) {
config.wepKeys[i] = null;
if (getWepKey(i) && !ArrayUtils.isEmpty(mWepKey)) {
- config.wepKeys[i] = NativeUtil.bytesToHexOrQuotedAsciiString(mWepKey);
+ config.wepKeys[i] = NativeUtil.bytesToHexOrQuotedString(mWepKey);
}
}
/** PSK pass phrase */
@@ -293,7 +293,7 @@ public class SupplicantStaNetworkHal {
for (int i = 0; i < config.wepKeys.length; i++) {
if (config.wepKeys[i] != null) {
if (!setWepKey(
- i, NativeUtil.hexOrQuotedAsciiStringToBytes(config.wepKeys[i]))) {
+ i, NativeUtil.hexOrQuotedStringToBytes(config.wepKeys[i]))) {
Log.e(TAG, "failed to set wep_key " + i);
return false;
}
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 72c044f5b..f2563968a 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -47,7 +47,6 @@ import android.util.Log;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
-import com.android.server.wifi.WifiConfigStoreLegacy.WifiConfigStoreDataLegacy;
import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.util.TelephonyUtil;
import com.android.server.wifi.util.WifiPermissionsUtil;
@@ -248,7 +247,6 @@ public class WifiConfigManager {
private final TelephonyManager mTelephonyManager;
private final WifiKeyStore mWifiKeyStore;
private final WifiConfigStore mWifiConfigStore;
- private final WifiConfigStoreLegacy mWifiConfigStoreLegacy;
private final WifiPermissionsUtil mWifiPermissionsUtil;
private final WifiPermissionsWrapper mWifiPermissionsWrapper;
/**
@@ -342,7 +340,7 @@ public class WifiConfigManager {
WifiConfigManager(
Context context, Clock clock, UserManager userManager,
TelephonyManager telephonyManager, WifiKeyStore wifiKeyStore,
- WifiConfigStore wifiConfigStore, WifiConfigStoreLegacy wifiConfigStoreLegacy,
+ WifiConfigStore wifiConfigStore,
WifiPermissionsUtil wifiPermissionsUtil,
WifiPermissionsWrapper wifiPermissionsWrapper,
NetworkListStoreData networkListStoreData,
@@ -354,7 +352,6 @@ public class WifiConfigManager {
mTelephonyManager = telephonyManager;
mWifiKeyStore = wifiKeyStore;
mWifiConfigStore = wifiConfigStore;
- mWifiConfigStoreLegacy = wifiConfigStoreLegacy;
mWifiPermissionsUtil = wifiPermissionsUtil;
mWifiPermissionsWrapper = wifiPermissionsWrapper;
@@ -652,6 +649,12 @@ public class WifiConfigManager {
* @param ignoreLockdown Ignore the configuration lockdown checks for connection attempts.
*/
private boolean canModifyNetwork(WifiConfiguration config, int uid, boolean ignoreLockdown) {
+ // System internals can always update networks; they're typically only
+ // making meteredHint or meteredOverride changes
+ if (uid == Process.SYSTEM_UID) {
+ return true;
+ }
+
// Passpoint configurations are generated and managed by PasspointManager. They can be
// added by either PasspointNetworkEvaluator (for auto connection) or Settings app
// (for manual connection), and need to be removed once the connection is completed.
@@ -711,16 +714,24 @@ public class WifiConfigManager {
}
/**
- * Method to check if the provided UID belongs to the current foreground user or some other
- * app (only SysUI today) running on behalf of the user.
- * This is used to prevent any background user apps from modifying network configurations.
+ * Check if the given UID belongs to the current foreground user. This is
+ * used to prevent apps running in background users from modifying network
+ * configurations.
+ * <p>
+ * UIDs belonging to system internals (such as SystemUI) are always allowed,
+ * since they always run as {@link UserHandle#USER_SYSTEM}.
*
* @param uid uid of the app.
- * @return true if the UID belongs to the current foreground app or SystemUI, false otherwise.
+ * @return true if the given UID belongs to the current foreground user,
+ * otherwise false.
*/
private boolean doesUidBelongToCurrentUser(int uid) {
- return (WifiConfigurationUtil.doesUidBelongToAnyProfile(
- uid, mUserManager.getProfiles(mCurrentUserId)) || (uid == mSystemUiUid));
+ if (uid == android.os.Process.SYSTEM_UID || uid == mSystemUiUid) {
+ return true;
+ } else {
+ return WifiConfigurationUtil.doesUidBelongToAnyProfile(
+ uid, mUserManager.getProfiles(mCurrentUserId));
+ }
}
/**
@@ -829,6 +840,10 @@ public class WifiConfigManager {
internalConfig.enterpriseConfig.copyFromExternal(
externalConfig.enterpriseConfig, PASSWORD_MASK);
}
+
+ // Copy over any metered information.
+ internalConfig.meteredHint = externalConfig.meteredHint;
+ internalConfig.meteredOverride = externalConfig.meteredOverride;
}
/**
@@ -891,7 +906,6 @@ public class WifiConfigManager {
newInternalConfig.requirePMF = externalConfig.requirePMF;
newInternalConfig.noInternetAccessExpected = externalConfig.noInternetAccessExpected;
newInternalConfig.ephemeral = externalConfig.ephemeral;
- newInternalConfig.meteredHint = externalConfig.meteredHint;
newInternalConfig.useExternalScores = externalConfig.useExternalScores;
newInternalConfig.shared = externalConfig.shared;
@@ -1910,7 +1924,7 @@ public class WifiConfigManager {
}
// Adding a new BSSID
- ScanResult result = scanDetailCache.get(scanResult.BSSID);
+ ScanResult result = scanDetailCache.getScanResult(scanResult.BSSID);
if (result != null) {
// transfer the black list status
scanResult.blackListTimestamp = result.blackListTimestamp;
@@ -2316,12 +2330,13 @@ public class WifiConfigManager {
public List<WifiScanner.PnoSettings.PnoNetwork> retrievePnoNetworkList() {
List<WifiScanner.PnoSettings.PnoNetwork> pnoList = new ArrayList<>();
List<WifiConfiguration> networks = new ArrayList<>(getInternalConfiguredNetworks());
- // Remove any permanently disabled networks.
+ // Remove any permanently or temporarily disabled networks.
Iterator<WifiConfiguration> iter = networks.iterator();
while (iter.hasNext()) {
WifiConfiguration config = iter.next();
if (config.ephemeral || config.isPasspoint()
- || config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()) {
+ || config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
+ || config.getNetworkSelectionStatus().isNetworkTemporaryDisabled()) {
iter.remove();
}
}
@@ -2557,10 +2572,12 @@ public class WifiConfigManager {
* @param userId The identifier of the user that stopped.
*/
public void handleUserStop(int userId) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Handling user stop for " + userId);
+ }
if (userId == mCurrentUserId && mUserManager.isUserUnlockingOrUnlocked(mCurrentUserId)) {
saveToStore(true);
- clearInternalData();
- mCurrentUserId = UserHandle.USER_SYSTEM;
+ clearInternalUserData(mCurrentUserId);
}
}
@@ -2572,6 +2589,7 @@ public class WifiConfigManager {
* - List of deleted ephemeral networks.
*/
private void clearInternalData() {
+ localLog("clearInternalData: Clearing all internal data");
mConfiguredNetworks.clear();
mDeletedEphemeralSSIDs.clear();
mScanDetailCaches.clear();
@@ -2590,12 +2608,16 @@ public class WifiConfigManager {
* removed from memory.
*/
private Set<Integer> clearInternalUserData(int userId) {
+ localLog("clearInternalUserData: Clearing user internal data for " + userId);
Set<Integer> removedNetworkIds = new HashSet<>();
// Remove any private networks of the old user before switching the userId.
for (WifiConfiguration config : getInternalConfiguredNetworks()) {
if (!config.shared && WifiConfigurationUtil.doesUidBelongToAnyProfile(
config.creatorUid, mUserManager.getProfiles(userId))) {
removedNetworkIds.add(config.networkId);
+ localLog("clearInternalUserData: removed config."
+ + " netId=" + config.networkId
+ + " configKey=" + config.configKey());
mConfiguredNetworks.remove(config.networkId);
}
}
@@ -2680,40 +2702,6 @@ public class WifiConfigManager {
}
/**
- * Migrate data from legacy store files. The function performs the following operations:
- * 1. Check if the legacy store files are present.
- * 2. If yes, read all the data from the store files.
- * 3. Save it to the new store files.
- * 4. Delete the legacy store file.
- *
- * @return true if migration was successful or not needed (fresh install), false if it failed.
- */
- public boolean migrateFromLegacyStore() {
- if (!mWifiConfigStoreLegacy.areStoresPresent()) {
- Log.d(TAG, "Legacy store files not found. No migration needed!");
- return true;
- }
- WifiConfigStoreDataLegacy storeData = mWifiConfigStoreLegacy.read();
- Log.d(TAG, "Reading from legacy store completed");
- loadInternalData(storeData.getConfigurations(), new ArrayList<WifiConfiguration>(),
- storeData.getDeletedEphemeralSSIDs());
-
- // Setup user store for the current user in case it have not setup yet, so that data
- // owned by the current user will be backed to the user store.
- if (mDeferredUserUnlockRead) {
- mWifiConfigStore.setUserStore(WifiConfigStore.createUserFile(mCurrentUserId));
- mDeferredUserUnlockRead = false;
- }
-
- if (!saveToStore(true)) {
- return false;
- }
- mWifiConfigStoreLegacy.removeStores();
- Log.d(TAG, "Migration from legacy store completed");
- return true;
- }
-
- /**
* Read the config store and load the in-memory lists from the store data retrieved and sends
* out the networks changed broadcast.
*
@@ -2727,10 +2715,7 @@ public class WifiConfigManager {
public boolean loadFromStore() {
if (!mWifiConfigStore.areStoresPresent()) {
Log.d(TAG, "New store files not found. No saved networks loaded!");
- if (!mWifiConfigStoreLegacy.areStoresPresent()) {
- // No legacy store files either, so reset the pending store read flag.
- mPendingStoreRead = false;
- }
+ mPendingStoreRead = false;
return true;
}
// If the user unlock comes in before we load from store, which means the user store have
@@ -2908,4 +2893,29 @@ public class WifiConfigManager {
public void setOnSavedNetworkUpdateListener(OnSavedNetworkUpdateListener listener) {
mListener = listener;
}
+
+ /**
+ * Set extra failure reason for given config. Used to surface extra failure details to the UI
+ * @param netId The network ID of the config to set the extra failure reason for
+ * @param reason the WifiConfiguration.ExtraFailureReason failure code representing the most
+ * recent failure reason
+ */
+ public void setRecentFailureAssociationStatus(int netId, int reason) {
+ WifiConfiguration config = getInternalConfiguredNetwork(netId);
+ if (config == null) {
+ return;
+ }
+ config.recentFailure.setAssociationStatus(reason);
+ }
+
+ /**
+ * @param netId The network ID of the config to clear the extra failure reason from
+ */
+ public void clearRecentFailureReason(int netId) {
+ WifiConfiguration config = getInternalConfiguredNetwork(netId);
+ if (config == null) {
+ return;
+ }
+ config.recentFailure.clear();
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiConfigStoreLegacy.java b/service/java/com/android/server/wifi/WifiConfigStoreLegacy.java
deleted file mode 100644
index 867775511..000000000
--- a/service/java/com/android/server/wifi/WifiConfigStoreLegacy.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2016 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.net.IpConfiguration;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiEnterpriseConfig;
-import android.os.Environment;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.server.net.IpConfigStore;
-import com.android.server.wifi.hotspot2.LegacyPasspointConfig;
-import com.android.server.wifi.hotspot2.LegacyPasspointConfigParser;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * This class provides the API's to load network configurations from legacy store
- * mechanism (Pre O release).
- * This class loads network configurations from:
- * 1. /data/misc/wifi/networkHistory.txt
- * 2. /data/misc/wifi/wpa_supplicant.conf
- * 3. /data/misc/wifi/ipconfig.txt
- * 4. /data/misc/wifi/PerProviderSubscription.conf
- *
- * The order of invocation of the public methods during migration is the following:
- * 1. Check if legacy stores are present using {@link #areStoresPresent()}.
- * 2. Load all the store data using {@link #read()}
- * 3. Write the store data to the new store.
- * 4. Remove all the legacy stores using {@link #removeStores()}
- *
- * NOTE: This class should only be used from WifiConfigManager and is not thread-safe!
- *
- * TODO(b/31065385): Passpoint config store data migration & deletion.
- */
-public class WifiConfigStoreLegacy {
- /**
- * Log tag.
- */
- private static final String TAG = "WifiConfigStoreLegacy";
- /**
- * NetworkHistory config store file path.
- */
- private static final File NETWORK_HISTORY_FILE =
- new File(WifiNetworkHistory.NETWORK_HISTORY_CONFIG_FILE);
- /**
- * Passpoint config store file path.
- */
- private static final File PPS_FILE =
- new File(Environment.getDataMiscDirectory(), "wifi/PerProviderSubscription.conf");
- /**
- * IpConfig config store file path.
- */
- private static final File IP_CONFIG_FILE =
- new File(Environment.getDataMiscDirectory(), "wifi/ipconfig.txt");
- /**
- * List of external dependencies for WifiConfigManager.
- */
- private final WifiNetworkHistory mWifiNetworkHistory;
- private final WifiNative mWifiNative;
- private final IpConfigStore mIpconfigStore;
-
- private final LegacyPasspointConfigParser mPasspointConfigParser;
-
- WifiConfigStoreLegacy(WifiNetworkHistory wifiNetworkHistory,
- WifiNative wifiNative, IpConfigStore ipConfigStore,
- LegacyPasspointConfigParser passpointConfigParser) {
- mWifiNetworkHistory = wifiNetworkHistory;
- mWifiNative = wifiNative;
- mIpconfigStore = ipConfigStore;
- mPasspointConfigParser = passpointConfigParser;
- }
-
- /**
- * Helper function to lookup the WifiConfiguration object from configKey to WifiConfiguration
- * object map using the hashcode of the configKey.
- *
- * @param configurationMap Map of configKey to WifiConfiguration object.
- * @param hashCode hash code of the configKey to match.
- * @return
- */
- private static WifiConfiguration lookupWifiConfigurationUsingConfigKeyHash(
- Map<String, WifiConfiguration> configurationMap, int hashCode) {
- for (Map.Entry<String, WifiConfiguration> entry : configurationMap.entrySet()) {
- if (entry.getKey().hashCode() == hashCode) {
- return entry.getValue();
- }
- }
- return null;
- }
-
- /**
- * Helper function to load {@link IpConfiguration} data from the ip config store file and
- * populate the provided configuration map.
- *
- * @param configurationMap Map of configKey to WifiConfiguration object.
- */
- private void loadFromIpConfigStore(Map<String, WifiConfiguration> configurationMap) {
- // This is a map of the hash code of the network's configKey to the corresponding
- // IpConfiguration.
- SparseArray<IpConfiguration> ipConfigurations =
- mIpconfigStore.readIpAndProxyConfigurations(IP_CONFIG_FILE.getAbsolutePath());
- if (ipConfigurations == null || ipConfigurations.size() == 0) {
- Log.w(TAG, "No ip configurations found in ipconfig store");
- return;
- }
- for (int i = 0; i < ipConfigurations.size(); i++) {
- int id = ipConfigurations.keyAt(i);
- WifiConfiguration config =
- lookupWifiConfigurationUsingConfigKeyHash(configurationMap, id);
- // This is the only place the map is looked up through a (dangerous) hash-value!
- if (config == null || config.ephemeral) {
- Log.w(TAG, "configuration found for missing network, nid=" + id
- + ", ignored, networks.size=" + Integer.toString(ipConfigurations.size()));
- } else {
- config.setIpConfiguration(ipConfigurations.valueAt(i));
- }
- }
- }
-
- /**
- * Helper function to load {@link WifiConfiguration} data from networkHistory file and populate
- * the provided configuration map and deleted ephemeral ssid list.
- *
- * @param configurationMap Map of configKey to WifiConfiguration object.
- * @param deletedEphemeralSSIDs Map of configKey to WifiConfiguration object.
- */
- private void loadFromNetworkHistory(
- Map<String, WifiConfiguration> configurationMap, Set<String> deletedEphemeralSSIDs) {
- // TODO: Need to revisit the scan detail cache persistance. We're not doing it in the new
- // config store, so ignore it here as well.
- Map<Integer, ScanDetailCache> scanDetailCaches = new HashMap<>();
- mWifiNetworkHistory.readNetworkHistory(
- configurationMap, scanDetailCaches, deletedEphemeralSSIDs);
- }
-
- /**
- * Helper function to load {@link WifiConfiguration} data from wpa_supplicant and populate
- * the provided configuration map and network extras.
- *
- * This method needs to manually parse the wpa_supplicant.conf file to retrieve some of the
- * password fields like psk, wep_keys. password, etc.
- *
- * @param configurationMap Map of configKey to WifiConfiguration object.
- * @param networkExtras Map of network extras parsed from wpa_supplicant.
- */
- private void loadFromWpaSupplicant(
- Map<String, WifiConfiguration> configurationMap,
- SparseArray<Map<String, String>> networkExtras) {
- if (!mWifiNative.migrateNetworksFromSupplicant(configurationMap, networkExtras)) {
- Log.wtf(TAG, "Failed to load wifi configurations from wpa_supplicant");
- return;
- }
- if (configurationMap.isEmpty()) {
- Log.w(TAG, "No wifi configurations found in wpa_supplicant");
- return;
- }
- }
-
- /**
- * Helper function to update {@link WifiConfiguration} that represents a Passpoint
- * configuration.
- *
- * This method will manually parse PerProviderSubscription.conf file to retrieve missing
- * fields: provider friendly name, roaming consortium OIs, realm, IMSI.
- *
- * @param configurationMap Map of configKey to WifiConfiguration object.
- * @param networkExtras Map of network extras parsed from wpa_supplicant.
- */
- private void loadFromPasspointConfigStore(
- Map<String, WifiConfiguration> configurationMap,
- SparseArray<Map<String, String>> networkExtras) {
- Map<String, LegacyPasspointConfig> passpointConfigMap = null;
- try {
- passpointConfigMap = mPasspointConfigParser.parseConfig(PPS_FILE.getAbsolutePath());
- } catch (IOException e) {
- Log.w(TAG, "Failed to read/parse Passpoint config file: " + e.getMessage());
- }
-
- List<String> entriesToBeRemoved = new ArrayList<>();
- for (Map.Entry<String, WifiConfiguration> entry : configurationMap.entrySet()) {
- WifiConfiguration wifiConfig = entry.getValue();
- // Ignore non-Enterprise network since enterprise configuration is required for
- // Passpoint.
- if (wifiConfig.enterpriseConfig == null || wifiConfig.enterpriseConfig.getEapMethod()
- == WifiEnterpriseConfig.Eap.NONE) {
- continue;
- }
- // Ignore configuration without FQDN.
- Map<String, String> extras = networkExtras.get(wifiConfig.networkId);
- if (extras == null || !extras.containsKey(SupplicantStaNetworkHal.ID_STRING_KEY_FQDN)) {
- continue;
- }
- String fqdn = networkExtras.get(wifiConfig.networkId).get(
- SupplicantStaNetworkHal.ID_STRING_KEY_FQDN);
-
- // Remove the configuration if failed to find the matching configuration in the
- // Passpoint configuration file.
- if (passpointConfigMap == null || !passpointConfigMap.containsKey(fqdn)) {
- entriesToBeRemoved.add(entry.getKey());
- continue;
- }
-
- // Update the missing Passpoint configuration fields to this WifiConfiguration.
- LegacyPasspointConfig passpointConfig = passpointConfigMap.get(fqdn);
- wifiConfig.isLegacyPasspointConfig = true;
- wifiConfig.FQDN = fqdn;
- wifiConfig.providerFriendlyName = passpointConfig.mFriendlyName;
- if (passpointConfig.mRoamingConsortiumOis != null) {
- wifiConfig.roamingConsortiumIds = Arrays.copyOf(
- passpointConfig.mRoamingConsortiumOis,
- passpointConfig.mRoamingConsortiumOis.length);
- }
- if (passpointConfig.mImsi != null) {
- wifiConfig.enterpriseConfig.setPlmn(passpointConfig.mImsi);
- }
- if (passpointConfig.mRealm != null) {
- wifiConfig.enterpriseConfig.setRealm(passpointConfig.mRealm);
- }
- }
-
- // Remove any incomplete Passpoint configurations. Should never happen, in case it does
- // remove them to avoid maintaining any invalid Passpoint configurations.
- for (String key : entriesToBeRemoved) {
- Log.w(TAG, "Remove incomplete Passpoint configuration: " + key);
- configurationMap.remove(key);
- }
- }
-
- /**
- * Helper function to load from the different legacy stores:
- * 1. Read the network configurations from wpa_supplicant using {@link WifiNative}.
- * 2. Read the network configurations from networkHistory.txt using {@link WifiNetworkHistory}.
- * 3. Read the Ip configurations from ipconfig.txt using {@link IpConfigStore}.
- * 4. Read all the passpoint info from PerProviderSubscription.conf using
- * {@link LegacyPasspointConfigParser}.
- */
- public WifiConfigStoreDataLegacy read() {
- final Map<String, WifiConfiguration> configurationMap = new HashMap<>();
- final SparseArray<Map<String, String>> networkExtras = new SparseArray<>();
- final Set<String> deletedEphemeralSSIDs = new HashSet<>();
-
- loadFromWpaSupplicant(configurationMap, networkExtras);
- loadFromNetworkHistory(configurationMap, deletedEphemeralSSIDs);
- loadFromIpConfigStore(configurationMap);
- loadFromPasspointConfigStore(configurationMap, networkExtras);
-
- // Now create config store data instance to be returned.
- return new WifiConfigStoreDataLegacy(
- new ArrayList<>(configurationMap.values()), deletedEphemeralSSIDs);
- }
-
- /**
- * Function to check if the legacy store files are present and hence load from those stores and
- * then delete them.
- *
- * @return true if legacy store files are present, false otherwise.
- */
- public boolean areStoresPresent() {
- // We may have to keep the wpa_supplicant.conf file around. So, just use networkhistory.txt
- // as a check to see if we have not yet migrated or not. This should be the last file
- // that is deleted after migration.
- File file = new File(WifiNetworkHistory.NETWORK_HISTORY_CONFIG_FILE);
- return file.exists();
- }
-
- /**
- * Method to remove all the legacy store files. This should only be invoked once all
- * the data has been migrated to the new store file.
- * 1. Removes all networks from wpa_supplicant and saves it to wpa_supplicant.conf
- * 2. Deletes ipconfig.txt
- * 3. Deletes networkHistory.txt
- *
- * @return true if all the store files were deleted successfully, false otherwise.
- */
- public boolean removeStores() {
- // TODO(b/29352330): Delete wpa_supplicant.conf file instead.
- // First remove all networks from wpa_supplicant and save configuration.
- if (!mWifiNative.removeAllNetworks()) {
- Log.e(TAG, "Removing networks from wpa_supplicant failed");
- return false;
- }
-
- // Now remove the ipconfig.txt file.
- if (!IP_CONFIG_FILE.delete()) {
- Log.e(TAG, "Removing ipconfig.txt failed");
- return false;
- }
-
- // Now finally remove network history.txt
- if (!NETWORK_HISTORY_FILE.delete()) {
- Log.e(TAG, "Removing networkHistory.txt failed");
- return false;
- }
-
- if (!PPS_FILE.delete()) {
- Log.e(TAG, "Removing PerProviderSubscription.conf failed");
- return false;
- }
-
- Log.i(TAG, "All legacy stores removed!");
- return true;
- }
-
- /**
- * Interface used to set a masked value in the provided configuration. The masked value is
- * retrieved by parsing the wpa_supplicant.conf file.
- */
- private interface MaskedWpaSupplicantFieldSetter {
- void setValue(WifiConfiguration config, String value);
- }
-
- /**
- * Class used to encapsulate all the store data retrieved from the legacy (Pre O) store files.
- */
- public static class WifiConfigStoreDataLegacy {
- private List<WifiConfiguration> mConfigurations;
- private Set<String> mDeletedEphemeralSSIDs;
- // private List<HomeSP> mHomeSps;
-
- WifiConfigStoreDataLegacy(List<WifiConfiguration> configurations,
- Set<String> deletedEphemeralSSIDs) {
- mConfigurations = configurations;
- mDeletedEphemeralSSIDs = deletedEphemeralSSIDs;
- }
-
- public List<WifiConfiguration> getConfigurations() {
- return mConfigurations;
- }
-
- public Set<String> getDeletedEphemeralSSIDs() {
- return mDeletedEphemeralSSIDs;
- }
- }
-}
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index fef78aade..dadc8a4e8 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -345,7 +345,7 @@ public class WifiConfigurationUtil {
}
}
try {
- NativeUtil.hexOrQuotedAsciiStringToBytes(psk);
+ NativeUtil.hexOrQuotedStringToBytes(psk);
} catch (IllegalArgumentException e) {
Log.e(TAG, "validatePsk failed: malformed string: " + psk);
return false;
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 344242a14..458f73ae6 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -30,6 +30,8 @@ import android.net.wifi.WifiScanner.PnoSettings;
import android.net.wifi.WifiScanner.ScanSettings;
import android.os.Handler;
import android.os.Looper;
+import android.os.Process;
+import android.os.WorkSource;
import android.util.LocalLog;
import android.util.Log;
@@ -133,7 +135,7 @@ public class WifiConnectivityManager {
private final WifiConnectivityHelper mConnectivityHelper;
private final WifiNetworkSelector mNetworkSelector;
private final WifiLastResortWatchdog mWifiLastResortWatchdog;
- private final WifiNotificationController mWifiNotificationController;
+ private final OpenNetworkNotifier mOpenNetworkNotifier;
private final WifiMetrics mWifiMetrics;
private final AlarmManager mAlarmManager;
private final Handler mEventHandler;
@@ -214,7 +216,7 @@ public class WifiConnectivityManager {
@Override
public void onAlarm() {
- startSingleScan(mIsFullBandScan);
+ startSingleScan(mIsFullBandScan, WIFI_WORK_SOURCE);
}
}
@@ -270,7 +272,7 @@ public class WifiConnectivityManager {
return true;
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED) {
- mWifiNotificationController.handleScanResults(
+ mOpenNetworkNotifier.handleScanResults(
mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
}
return false;
@@ -467,6 +469,10 @@ public class WifiConnectivityManager {
@Override
public void onPnoNetworkFound(ScanResult[] results) {
for (ScanResult result: results) {
+ if (result.informationElements == null) {
+ localLog("Skipping scan result with null information elements");
+ continue;
+ }
mScanDetails.add(ScanResultUtil.toScanDetail(result));
}
@@ -508,6 +514,8 @@ public class WifiConnectivityManager {
}
@Override
public void onSavedNetworkUpdated(int networkId) {
+ // User might have changed meteredOverride, so update capabilties
+ mStateMachine.updateCapabilities();
updatePnoScan();
}
@Override
@@ -536,7 +544,7 @@ public class WifiConnectivityManager {
WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,
WifiNetworkSelector networkSelector, WifiConnectivityHelper connectivityHelper,
WifiLastResortWatchdog wifiLastResortWatchdog,
- WifiNotificationController wifiNotificationController, WifiMetrics wifiMetrics,
+ OpenNetworkNotifier openNetworkNotifier, WifiMetrics wifiMetrics,
Looper looper, Clock clock, LocalLog localLog, boolean enable,
FrameworkFacade frameworkFacade,
SavedNetworkEvaluator savedNetworkEvaluator,
@@ -550,7 +558,7 @@ public class WifiConnectivityManager {
mConnectivityHelper = connectivityHelper;
mLocalLog = localLog;
mWifiLastResortWatchdog = wifiLastResortWatchdog;
- mWifiNotificationController = wifiNotificationController;
+ mOpenNetworkNotifier = openNetworkNotifier;
mWifiMetrics = wifiMetrics;
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mEventHandler = new Handler(looper);
@@ -558,9 +566,9 @@ public class WifiConnectivityManager {
mConnectionAttemptTimeStamps = new LinkedList<>();
mMin5GHzRssi = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz);
mMin24GHzRssi = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz);
mBand5GHzBonus = context.getResources().getInteger(
R.integer.config_wifi_framework_5GHz_preference_boost_factor);
mCurrentConnectionBonus = context.getResources().getInteger(
@@ -735,7 +743,7 @@ public class WifiConnectivityManager {
localLog("connectToNetwork: Connect to " + targetAssociationId + " from "
+ currentAssociationId);
}
- mStateMachine.startConnectToNetwork(candidate.networkId, targetBssid);
+ mStateMachine.startConnectToNetwork(candidate.networkId, Process.WIFI_UID, targetBssid);
}
}
@@ -788,7 +796,7 @@ public class WifiConnectivityManager {
localLog("start a single scan from watchdogHandler");
scheduleWatchdogTimer();
- startSingleScan(true);
+ startSingleScan(true, WIFI_WORK_SOURCE);
}
}
@@ -817,7 +825,7 @@ public class WifiConnectivityManager {
}
mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
- startSingleScan(isFullBandScan);
+ startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
// Set up the next scan interval in an exponential backoff fashion.
@@ -844,7 +852,7 @@ public class WifiConnectivityManager {
}
// Start a single scan
- private void startSingleScan(boolean isFullBandScan) {
+ private void startSingleScan(boolean isFullBandScan, WorkSource workSource) {
if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
return;
}
@@ -869,7 +877,7 @@ public class WifiConnectivityManager {
SingleScanListener singleScanListener =
new SingleScanListener(isFullBandScan);
- mScanner.startScan(settings, singleScanListener, WIFI_WORK_SOURCE);
+ mScanner.startScan(settings, singleScanListener, workSource);
}
// Start a periodic scan when screen is on
@@ -1037,7 +1045,7 @@ public class WifiConnectivityManager {
mScreenOn = screenOn;
- mWifiNotificationController.handleScreenStateChanged(screenOn);
+ mOpenNetworkNotifier.handleScreenStateChanged(screenOn);
startConnectivityScan(SCAN_ON_SCHEDULE);
}
@@ -1067,7 +1075,7 @@ public class WifiConnectivityManager {
mWifiState = state;
if (mWifiState == WIFI_STATE_CONNECTED) {
- mWifiNotificationController.clearPendingNotification(false /* resetRepeatDelay */);
+ mOpenNetworkNotifier.handleWifiConnected();
}
// Reset BSSID of last connection attempt and kick off
@@ -1082,6 +1090,17 @@ public class WifiConnectivityManager {
}
/**
+ * Handler when a WiFi connection attempt ended.
+ *
+ * @param failureCode {@link WifiMetrics.ConnectionEvent} failure code.
+ */
+ public void handleConnectionAttemptEnded(int failureCode) {
+ if (failureCode != WifiMetrics.ConnectionEvent.FAILURE_NONE) {
+ mOpenNetworkNotifier.handleConnectionFailure();
+ }
+ }
+
+ /**
* Handler when user toggles whether untrusted connection is allowed
*/
public void setUntrustedConnectionAllowed(boolean allowed) {
@@ -1115,11 +1134,11 @@ public class WifiConnectivityManager {
/**
* Handler for on-demand connectivity scan
*/
- public void forceConnectivityScan() {
- localLog("forceConnectivityScan");
+ public void forceConnectivityScan(WorkSource workSource) {
+ localLog("forceConnectivityScan in request of " + workSource);
mWaitForFullBandScanResults = true;
- startSingleScan(true);
+ startSingleScan(true, workSource);
}
/**
@@ -1303,7 +1322,7 @@ public class WifiConnectivityManager {
stopConnectivityScan();
clearBssidBlacklist();
resetLastPeriodicSingleScanTimeStamp();
- mWifiNotificationController.clearPendingNotification(true /* resetRepeatDelay */);
+ mOpenNetworkNotifier.clearPendingNotification(true /* resetRepeatDelay */);
mLastConnectionAttemptBssid = null;
mWaitForFullBandScanResults = false;
}
@@ -1363,6 +1382,6 @@ public class WifiConnectivityManager {
pw.println("WifiConnectivityManager - Log Begin ----");
mLocalLog.dump(fd, pw, args);
pw.println("WifiConnectivityManager - Log End ----");
- mWifiNotificationController.dump(fd, pw, args);
+ mOpenNetworkNotifier.dump(fd, pw, args);
}
}
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index c1b186142..494ce86e5 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -248,9 +248,9 @@ public class WifiController extends StateMachine {
}
private void readWifiSleepPolicy() {
- mSleepPolicy = mFacade.getIntegerSetting(mContext,
- Settings.Global.WIFI_SLEEP_POLICY,
- Settings.Global.WIFI_SLEEP_POLICY_NEVER);
+ // This should always set to default value because the settings menu to toggle this
+ // has been removed now.
+ mSleepPolicy = Settings.Global.WIFI_SLEEP_POLICY_NEVER;
}
private void readWifiReEnableDelay() {
diff --git a/service/java/com/android/server/wifi/WifiCountryCode.java b/service/java/com/android/server/wifi/WifiCountryCode.java
index e69fb8e1c..66a035f08 100644
--- a/service/java/com/android/server/wifi/WifiCountryCode.java
+++ b/service/java/com/android/server/wifi/WifiCountryCode.java
@@ -83,11 +83,9 @@ public class WifiCountryCode {
public synchronized void simCardRemoved() {
if (DBG) Log.d(TAG, "SIM Card Removed");
// SIM card is removed, we need to reset the country code to phone default.
- if (mRevertCountryCodeOnCellularLoss) {
- mTelephonyCountryCode = null;
- if (mReady) {
- updateCountryCode();
- }
+ mTelephonyCountryCode = null;
+ if (mReady) {
+ updateCountryCode();
}
}
@@ -98,12 +96,9 @@ public class WifiCountryCode {
*/
public synchronized void airplaneModeEnabled() {
if (DBG) Log.d(TAG, "Airplane Mode Enabled");
- mTelephonyCountryCode = null;
// Airplane mode is enabled, we need to reset the country code to phone default.
- if (mRevertCountryCodeOnCellularLoss) {
- mTelephonyCountryCode = null;
- // Country code will be set upon when wpa_supplicant starts next time.
- }
+ // Country code will be set upon when wpa_supplicant starts next time.
+ mTelephonyCountryCode = null;
}
/**
@@ -133,8 +128,10 @@ public class WifiCountryCode {
if (DBG) Log.d(TAG, "Receive set country code request: " + countryCode);
// Empty country code.
if (TextUtils.isEmpty(countryCode)) {
- if (DBG) Log.d(TAG, "Received empty country code, reset to default country code");
- mTelephonyCountryCode = null;
+ if (mRevertCountryCodeOnCellularLoss) {
+ if (DBG) Log.d(TAG, "Received empty country code, reset to default country code");
+ mTelephonyCountryCode = null;
+ }
} else {
mTelephonyCountryCode = countryCode.toUpperCase();
}
diff --git a/service/java/com/android/server/wifi/WifiDiagnostics.java b/service/java/com/android/server/wifi/WifiDiagnostics.java
index 42078ef58..921faa306 100644
--- a/service/java/com/android/server/wifi/WifiDiagnostics.java
+++ b/service/java/com/android/server/wifi/WifiDiagnostics.java
@@ -77,6 +77,8 @@ class WifiDiagnostics extends BaseWifiDiagnostics {
public static final int REPORT_REASON_UNEXPECTED_DISCONNECT = 5;
public static final int REPORT_REASON_SCAN_FAILURE = 6;
public static final int REPORT_REASON_USER_ACTION = 7;
+ public static final int REPORT_REASON_WIFICOND_CRASH = 8;
+ public static final int REPORT_REASON_HAL_CRASH = 9;
/** number of bug reports to hold */
public static final int MAX_BUG_REPORTS = 4;
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 80daaeaa1..4b8e6829e 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -45,7 +45,6 @@ import com.android.server.am.BatteryStatsService;
import com.android.server.net.DelayedDiskWrite;
import com.android.server.net.IpConfigStore;
import com.android.server.wifi.aware.WifiAwareMetrics;
-import com.android.server.wifi.hotspot2.LegacyPasspointConfigParser;
import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.hotspot2.PasspointNetworkEvaluator;
import com.android.server.wifi.hotspot2.PasspointObjectFactory;
@@ -87,7 +86,7 @@ public class WifiInjector {
private final WifiStateMachine mWifiStateMachine;
private final WifiSettingsStore mSettingsStore;
private final WifiCertManager mCertManager;
- private final WifiNotificationController mNotificationController;
+ private final OpenNetworkNotifier mOpenNetworkNotifier;
private final WifiLockManager mLockManager;
private final WifiController mWifiController;
private final WificondControl mWificondControl;
@@ -101,9 +100,7 @@ public class WifiInjector {
private final WifiMulticastLockManager mWifiMulticastLockManager;
private final WifiConfigStore mWifiConfigStore;
private final WifiKeyStore mWifiKeyStore;
- private final WifiNetworkHistory mWifiNetworkHistory;
private final IpConfigStore mIpConfigStore;
- private final WifiConfigStoreLegacy mWifiConfigStoreLegacy;
private final WifiConfigManager mWifiConfigManager;
private final WifiConnectivityHelper mWifiConnectivityHelper;
private final LocalLog mConnectivityLocalLog;
@@ -169,7 +166,8 @@ public class WifiInjector {
mWifiVendorHal =
new WifiVendorHal(mHalDeviceManager, mWifiStateMachineHandlerThread.getLooper());
mSupplicantStaIfaceHal = new SupplicantStaIfaceHal(mContext, mWifiMonitor);
- mWificondControl = new WificondControl(this, mWifiMonitor);
+ mWificondControl = new WificondControl(this, mWifiMonitor,
+ new CarrierNetworkConfig(mContext));
mWifiNative = new WifiNative(SystemProperties.get("wifi.interface", "wlan0"),
mWifiVendorHal, mSupplicantStaIfaceHal, mWificondControl);
mWifiP2pMonitor = new WifiP2pMonitor(this);
@@ -194,16 +192,12 @@ public class WifiInjector {
WifiConfigStore.createSharedFile());
// Legacy config store
DelayedDiskWrite writer = new DelayedDiskWrite();
- mWifiNetworkHistory = new WifiNetworkHistory(mContext, writer);
mIpConfigStore = new IpConfigStore(writer);
- mWifiConfigStoreLegacy = new WifiConfigStoreLegacy(
- mWifiNetworkHistory, mWifiNative, mIpConfigStore,
- new LegacyPasspointConfigParser());
// Config Manager
mWifiConfigManager = new WifiConfigManager(mContext, mClock,
UserManager.get(mContext), TelephonyManager.from(mContext),
- mWifiKeyStore, mWifiConfigStore, mWifiConfigStoreLegacy, mWifiPermissionsUtil,
- mWifiPermissionsWrapper, new NetworkListStoreData(),
+ mWifiKeyStore, mWifiConfigStore, mWifiPermissionsUtil,
+ mWifiPermissionsWrapper, new NetworkListStoreData(mContext),
new DeletedEphemeralSsidsStoreData());
mWifiMetrics.setWifiConfigManager(mWifiConfigManager);
mWifiConnectivityHelper = new WifiConnectivityHelper(mWifiNative);
@@ -230,8 +224,11 @@ public class WifiInjector {
this, mBackupManagerProxy, mCountryCode, mWifiNative,
new WrongPasswordNotifier(mContext, mFrameworkFacade));
mCertManager = new WifiCertManager(mContext);
- mNotificationController = new WifiNotificationController(mContext,
- mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, null);
+ mOpenNetworkNotifier = new OpenNetworkNotifier(mContext,
+ mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, mClock, mWifiMetrics,
+ mWifiConfigManager, mWifiConfigStore, mWifiStateMachine,
+ new OpenNetworkRecommender(),
+ new ConnectToNetworkNotificationBuilder(mContext, mFrameworkFacade));
mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
@@ -430,7 +427,7 @@ public class WifiInjector {
boolean hasConnectionRequests) {
return new WifiConnectivityManager(mContext, mWifiStateMachine, getWifiScanner(),
mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper,
- mWifiLastResortWatchdog, mNotificationController, mWifiMetrics,
+ mWifiLastResortWatchdog, mOpenNetworkNotifier, mWifiMetrics,
mWifiStateMachineHandlerThread.getLooper(), mClock, mConnectivityLocalLog,
hasConnectionRequests, mFrameworkFacade, mSavedNetworkEvaluator,
mScoredNetworkEvaluator, mPasspointNetworkEvaluator);
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 7dfdb86d3..071b4f883 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -37,6 +37,8 @@ import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.hotspot2.PasspointMatch;
import com.android.server.wifi.hotspot2.PasspointProvider;
import com.android.server.wifi.nano.WifiMetricsProto;
+import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
+import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
import com.android.server.wifi.nano.WifiMetricsProto.StaEvent.ConfigInfo;
import com.android.server.wifi.util.InformationElementUtil;
@@ -82,10 +84,12 @@ public class WifiMetrics {
public static final int MAX_CONNECTABLE_BSSID_NETWORK_BUCKET = 50;
public static final int MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET = 100;
public static final int MAX_TOTAL_SCAN_RESULTS_BUCKET = 250;
+ private static final int CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER = 1000;
private Clock mClock;
private boolean mScreenOn;
private int mWifiState;
private WifiAwareMetrics mWifiAwareMetrics;
+ private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics();
private Handler mHandler;
private WifiConfigManager mWifiConfigManager;
private WifiNetworkSelector mWifiNetworkSelector;
@@ -148,6 +152,15 @@ public class WifiMetrics {
private final SparseIntArray mAvailableSavedPasspointProviderBssidsInScanHistogram =
new SparseIntArray();
+ /** Mapping of "Connect to Network" notifications to counts. */
+ private final SparseIntArray mConnectToNetworkNotificationCount = new SparseIntArray();
+ /** Mapping of "Connect to Network" notification user actions to counts. */
+ private final SparseIntArray mConnectToNetworkNotificationActionCount = new SparseIntArray();
+ private int mOpenNetworkRecommenderBlacklistSize = 0;
+ private boolean mIsWifiNetworksAvailableNotificationOn = false;
+ private int mNumOpenNetworkConnectMessageFailedToSend = 0;
+ private int mNumOpenNetworkRecommendationUpdates = 0;
+
class RouterFingerPrint {
private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
RouterFingerPrint() {
@@ -407,6 +420,51 @@ public class WifiMetrics {
mPasspointManager = passpointManager;
}
+ /**
+ * Increment total number of attempts to start a pno scan
+ */
+ public void incrementPnoScanStartAttempCount() {
+ synchronized (mLock) {
+ mPnoScanMetrics.numPnoScanAttempts++;
+ }
+ }
+
+ /**
+ * Increment total number of attempts with pno scan failed
+ */
+ public void incrementPnoScanFailedCount() {
+ synchronized (mLock) {
+ mPnoScanMetrics.numPnoScanFailed++;
+ }
+ }
+
+ /**
+ * Increment number of pno scans started successfully over offload
+ */
+ public void incrementPnoScanStartedOverOffloadCount() {
+ synchronized (mLock) {
+ mPnoScanMetrics.numPnoScanStartedOverOffload++;
+ }
+ }
+
+ /**
+ * Increment number of pno scans failed over offload
+ */
+ public void incrementPnoScanFailedOverOffloadCount() {
+ synchronized (mLock) {
+ mPnoScanMetrics.numPnoScanFailedOverOffload++;
+ }
+ }
+
+ /**
+ * Increment number of times pno scan found a result
+ */
+ public void incrementPnoFoundNetworkEventCount() {
+ synchronized (mLock) {
+ mPnoScanMetrics.numPnoFoundNetworkEvents++;
+ }
+ }
+
// Values used for indexing SystemStateEntries
private static final int SCREEN_ON = 1;
private static final int SCREEN_OFF = 0;
@@ -1190,6 +1248,55 @@ public class WifiMetrics {
}
}
+ /** Increments the occurence of a "Connect to Network" notification. */
+ public void incrementConnectToNetworkNotification(int notificationType) {
+ synchronized (mLock) {
+ int count = mConnectToNetworkNotificationCount.get(notificationType);
+ mConnectToNetworkNotificationCount.put(notificationType, count + 1);
+ }
+ }
+
+ /** Increments the occurence of an "Connect to Network" notification user action. */
+ public void incrementConnectToNetworkNotificationAction(int notificationType, int actionType) {
+ synchronized (mLock) {
+ int key = notificationType * CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER
+ + actionType;
+ int count = mConnectToNetworkNotificationActionCount.get(key);
+ mConnectToNetworkNotificationActionCount.put(key, count + 1);
+ }
+ }
+
+ /**
+ * Sets the number of SSIDs blacklisted from recommendation by the open network notification
+ * recommender.
+ */
+ public void setOpenNetworkRecommenderBlacklistSize(int size) {
+ synchronized (mLock) {
+ mOpenNetworkRecommenderBlacklistSize = size;
+ }
+ }
+
+ /** Sets if the available network notification feature is enabled. */
+ public void setIsWifiNetworksAvailableNotificationEnabled(boolean enabled) {
+ synchronized (mLock) {
+ mIsWifiNetworksAvailableNotificationOn = enabled;
+ }
+ }
+
+ /** Increments the occurence of connection attempts that were initiated unsuccessfully */
+ public void incrementNumOpenNetworkRecommendationUpdates() {
+ synchronized (mLock) {
+ mNumOpenNetworkRecommendationUpdates++;
+ }
+ }
+
+ /** Increments the occurence of connection attempts that were initiated unsuccessfully */
+ public void incrementNumOpenNetworkConnectMessageFailedToSend() {
+ synchronized (mLock) {
+ mNumOpenNetworkConnectMessageFailedToSend++;
+ }
+ }
+
public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
public static final String CLEAN_DUMP_ARG = "clean";
@@ -1388,8 +1495,8 @@ public class WifiMetrics {
pw.println("mWifiLogProto.numWifiOnFailureDueToWificond="
+ mWifiLogProto.numWifiOnFailureDueToWificond);
pw.println("StaEventList:");
- for (StaEvent event : mStaEventList) {
- pw.println(staEventToString(event));
+ for (StaEventWithTime event : mStaEventList) {
+ pw.println(event);
}
pw.println("mWifiLogProto.numPasspointProviders="
@@ -1430,6 +1537,30 @@ public class WifiMetrics {
+ mWifiLogProto.fullBandAllSingleScanListenerResults);
pw.println("mWifiAwareMetrics:");
mWifiAwareMetrics.dump(fd, pw, args);
+
+ pw.println("mPnoScanMetrics.numPnoScanAttempts="
+ + mPnoScanMetrics.numPnoScanAttempts);
+ pw.println("mPnoScanMetrics.numPnoScanFailed="
+ + mPnoScanMetrics.numPnoScanFailed);
+ pw.println("mPnoScanMetrics.numPnoScanStartedOverOffload="
+ + mPnoScanMetrics.numPnoScanStartedOverOffload);
+ pw.println("mPnoScanMetrics.numPnoScanFailedOverOffload="
+ + mPnoScanMetrics.numPnoScanFailedOverOffload);
+ pw.println("mPnoScanMetrics.numPnoFoundNetworkEvents="
+ + mPnoScanMetrics.numPnoFoundNetworkEvents);
+
+ pw.println("mWifiLogProto.connectToNetworkNotificationCount="
+ + mConnectToNetworkNotificationCount.toString());
+ pw.println("mWifiLogProto.connectToNetworkNotificationActionCount="
+ + mConnectToNetworkNotificationActionCount.toString());
+ pw.println("mWifiLogProto.openNetworkRecommenderBlacklistSize="
+ + mOpenNetworkRecommenderBlacklistSize);
+ pw.println("mWifiLogProto.isWifiNetworksAvailableNotificationOn="
+ + mIsWifiNetworksAvailableNotificationOn);
+ pw.println("mWifiLogProto.numOpenNetworkRecommendationUpdates="
+ + mNumOpenNetworkRecommendationUpdates);
+ pw.println("mWifiLogProto.numOpenNetworkConnectMessageFailedToSend="
+ + mNumOpenNetworkConnectMessageFailedToSend);
}
}
}
@@ -1605,6 +1736,14 @@ public class WifiMetrics {
mWifiLogProto.softApReturnCode[sapCode].count =
mSoftApManagerReturnCodeCounts.valueAt(sapCode);
}
+
+ /**
+ * Convert StaEventList to array of StaEvents
+ */
+ mWifiLogProto.staEventList = new StaEvent[mStaEventList.size()];
+ for (int i = 0; i < mStaEventList.size(); i++) {
+ mWifiLogProto.staEventList[i] = mStaEventList.get(i).staEvent;
+ }
mWifiLogProto.totalSsidsInScanHistogram =
makeNumConnectableNetworksBucketArray(mTotalSsidsInScanHistogram);
mWifiLogProto.totalBssidsInScanHistogram =
@@ -1629,8 +1768,56 @@ public class WifiMetrics {
mWifiLogProto.availableSavedPasspointProviderBssidsInScanHistogram =
makeNumConnectableNetworksBucketArray(
mAvailableSavedPasspointProviderBssidsInScanHistogram);
- mWifiLogProto.staEventList = mStaEventList.toArray(mWifiLogProto.staEventList);
mWifiLogProto.wifiAwareLog = mWifiAwareMetrics.consolidateProto();
+
+ mWifiLogProto.pnoScanMetrics = mPnoScanMetrics;
+
+ /**
+ * Convert the SparseIntArray of "Connect to Network" notification types and counts to
+ * proto's repeated IntKeyVal array.
+ */
+ ConnectToNetworkNotificationAndActionCount[] notificationCountArray =
+ new ConnectToNetworkNotificationAndActionCount[
+ mConnectToNetworkNotificationCount.size()];
+ for (int i = 0; i < mConnectToNetworkNotificationCount.size(); i++) {
+ ConnectToNetworkNotificationAndActionCount keyVal =
+ new ConnectToNetworkNotificationAndActionCount();
+ keyVal.notification = mConnectToNetworkNotificationCount.keyAt(i);
+ keyVal.recommender =
+ ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
+ keyVal.count = mConnectToNetworkNotificationCount.valueAt(i);
+ notificationCountArray[i] = keyVal;
+ }
+ mWifiLogProto.connectToNetworkNotificationCount = notificationCountArray;
+
+ /**
+ * Convert the SparseIntArray of "Connect to Network" notification types and counts to
+ * proto's repeated IntKeyVal array.
+ */
+ ConnectToNetworkNotificationAndActionCount[] notificationActionCountArray =
+ new ConnectToNetworkNotificationAndActionCount[
+ mConnectToNetworkNotificationActionCount.size()];
+ for (int i = 0; i < mConnectToNetworkNotificationActionCount.size(); i++) {
+ ConnectToNetworkNotificationAndActionCount keyVal =
+ new ConnectToNetworkNotificationAndActionCount();
+ int key = mConnectToNetworkNotificationActionCount.keyAt(i);
+ keyVal.notification = key / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
+ keyVal.action = key % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
+ keyVal.recommender =
+ ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
+ keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i);
+ notificationActionCountArray[i] = keyVal;
+ }
+ mWifiLogProto.connectToNetworkNotificationActionCount = notificationActionCountArray;
+
+ mWifiLogProto.openNetworkRecommenderBlacklistSize =
+ mOpenNetworkRecommenderBlacklistSize;
+ mWifiLogProto.isWifiNetworksAvailableNotificationOn =
+ mIsWifiNetworksAvailableNotificationOn;
+ mWifiLogProto.numOpenNetworkRecommendationUpdates =
+ mNumOpenNetworkRecommendationUpdates;
+ mWifiLogProto.numOpenNetworkConnectMessageFailedToSend =
+ mNumOpenNetworkConnectMessageFailedToSend;
}
}
@@ -1649,7 +1836,8 @@ public class WifiMetrics {
}
/**
- * Clear all WifiMetrics, except for currentConnectionEvent.
+ * Clear all WifiMetrics, except for currentConnectionEvent and Open Network Notification
+ * feature enabled state, blacklist size.
*/
private void clear() {
synchronized (mLock) {
@@ -1679,6 +1867,11 @@ public class WifiMetrics {
mAvailableOpenOrSavedBssidsInScanHistogram.clear();
mAvailableSavedPasspointProviderProfilesInScanHistogram.clear();
mAvailableSavedPasspointProviderBssidsInScanHistogram.clear();
+ mPnoScanMetrics.clear();
+ mConnectToNetworkNotificationCount.clear();
+ mConnectToNetworkNotificationActionCount.clear();
+ mNumOpenNetworkRecommendationUpdates = 0;
+ mNumOpenNetworkConnectMessageFailedToSend = 0;
}
}
@@ -1826,7 +2019,7 @@ public class WifiMetrics {
mLastPollRssi = -127;
mLastPollFreq = -1;
mLastPollLinkSpeed = -1;
- mStaEventList.add(staEvent);
+ mStaEventList.add(new StaEventWithTime(staEvent, mClock.getWallClockMillis()));
// Prune StaEventList if it gets too long
if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove();
}
@@ -1903,7 +2096,7 @@ public class WifiMetrics {
private static String supplicantStateChangesBitmaskToString(int mask) {
StringBuilder sb = new StringBuilder();
- sb.append("SUPPLICANT_STATE_CHANGE_EVENTS: {");
+ sb.append("supplicantStateChangeEvents: {");
if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED");
if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED");
if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE");
@@ -1928,58 +2121,56 @@ public class WifiMetrics {
public static String staEventToString(StaEvent event) {
if (event == null) return "<NULL>";
StringBuilder sb = new StringBuilder();
- Long time = event.startTimeMillis;
- sb.append(String.format("%9d ", time.longValue())).append(" ");
switch (event.type) {
case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT:
- sb.append("ASSOCIATION_REJECTION_EVENT:")
+ sb.append("ASSOCIATION_REJECTION_EVENT")
.append(" timedOut=").append(event.associationTimedOut)
.append(" status=").append(event.status).append(":")
.append(ISupplicantStaIfaceCallback.StatusCode.toString(event.status));
break;
case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT:
- sb.append("AUTHENTICATION_FAILURE_EVENT: reason=").append(event.authFailureReason)
+ sb.append("AUTHENTICATION_FAILURE_EVENT reason=").append(event.authFailureReason)
.append(":").append(authFailureReasonToString(event.authFailureReason));
break;
case StaEvent.TYPE_NETWORK_CONNECTION_EVENT:
- sb.append("NETWORK_CONNECTION_EVENT:");
+ sb.append("NETWORK_CONNECTION_EVENT");
break;
case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT:
- sb.append("NETWORK_DISCONNECTION_EVENT:")
+ sb.append("NETWORK_DISCONNECTION_EVENT")
.append(" local_gen=").append(event.localGen)
.append(" reason=").append(event.reason).append(":")
.append(ISupplicantStaIfaceCallback.ReasonCode.toString(
(event.reason >= 0 ? event.reason : -1 * event.reason)));
break;
case StaEvent.TYPE_CMD_ASSOCIATED_BSSID:
- sb.append("CMD_ASSOCIATED_BSSID:");
+ sb.append("CMD_ASSOCIATED_BSSID");
break;
case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
- sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL:");
+ sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL");
break;
case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
- sb.append("CMD_IP_CONFIGURATION_LOST:");
+ sb.append("CMD_IP_CONFIGURATION_LOST");
break;
case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
- sb.append("CMD_IP_REACHABILITY_LOST:");
+ sb.append("CMD_IP_REACHABILITY_LOST");
break;
case StaEvent.TYPE_CMD_TARGET_BSSID:
- sb.append("CMD_TARGET_BSSID:");
+ sb.append("CMD_TARGET_BSSID");
break;
case StaEvent.TYPE_CMD_START_CONNECT:
- sb.append("CMD_START_CONNECT:");
+ sb.append("CMD_START_CONNECT");
break;
case StaEvent.TYPE_CMD_START_ROAM:
- sb.append("CMD_START_ROAM:");
+ sb.append("CMD_START_ROAM");
break;
case StaEvent.TYPE_CONNECT_NETWORK:
- sb.append("CONNECT_NETWORK:");
+ sb.append("CONNECT_NETWORK");
break;
case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
- sb.append("NETWORK_AGENT_VALID_NETWORK:");
+ sb.append("NETWORK_AGENT_VALID_NETWORK");
break;
case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
- sb.append("FRAMEWORK_DISCONNECT:")
+ sb.append("FRAMEWORK_DISCONNECT")
.append(" reason=")
.append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason));
break;
@@ -1991,11 +2182,11 @@ public class WifiMetrics {
if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq);
if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed);
if (event.supplicantStateChangesBitmask != 0) {
- sb.append("\n ").append(supplicantStateChangesBitmaskToString(
+ sb.append(", ").append(supplicantStateChangesBitmaskToString(
event.supplicantStateChangesBitmask));
}
if (event.configInfo != null) {
- sb.append("\n ").append(configInfoToString(event.configInfo));
+ sb.append(", ").append(configInfoToString(event.configInfo));
}
return sb.toString();
@@ -2053,7 +2244,7 @@ public class WifiMetrics {
}
public static final int MAX_STA_EVENTS = 512;
- private LinkedList<StaEvent> mStaEventList = new LinkedList<StaEvent>();
+ private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<StaEventWithTime>();
private int mLastPollRssi = -127;
private int mLastPollLinkSpeed = -1;
private int mLastPollFreq = -1;
@@ -2085,4 +2276,27 @@ public class WifiMetrics {
int count = sia.get(element);
sia.put(element, count + 1);
}
+
+ private static class StaEventWithTime {
+ public StaEvent staEvent;
+ public long wallClockMillis;
+
+ StaEventWithTime(StaEvent event, long wallClockMillis) {
+ staEvent = event;
+ this.wallClockMillis = wallClockMillis;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(wallClockMillis);
+ if (wallClockMillis != 0) {
+ sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
+ } else {
+ sb.append(" ");
+ }
+ sb.append(" ").append(staEventToString(staEvent));
+ return sb.toString();
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 973b659d2..5b12a3648 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -227,7 +227,16 @@ public class WifiNative {
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getScanResults() {
- return mWificondControl.getScanResults();
+ return mWificondControl.getScanResults(WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ }
+
+ /**
+ * Fetch the latest scan result from kernel via wificond.
+ * @return Returns an ArrayList of ScanDetail.
+ * Returns an empty ArrayList on failure.
+ */
+ public ArrayList<ScanDetail> getPnoScanResults() {
+ return mWificondControl.getScanResults(WificondControl.SCAN_TYPE_PNO_SCAN);
}
/**
@@ -1536,26 +1545,6 @@ public class WifiNative {
}
/**
- * Set the PNO settings & the network list in HAL to start PNO.
- * @param settings PNO settings and network list.
- * @param eventHandler Handler to receive notifications back during PNO scan.
- * @return true if success, false otherwise
- */
- public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) {
- Log.e(mTAG, "setPnoList not supported");
- return false;
- }
-
- /**
- * Reset the PNO settings in HAL to stop PNO.
- * @return true if success, false otherwise
- */
- public boolean resetPnoList() {
- Log.e(mTAG, "resetPnoList not supported");
- return false;
- }
-
- /**
* Start sending the specified keep alive packets periodically.
*
* @param slot Integer used to identify each request.
diff --git a/service/java/com/android/server/wifi/WifiNetworkHistory.java b/service/java/com/android/server/wifi/WifiNetworkHistory.java
deleted file mode 100644
index f8457cd8a..000000000
--- a/service/java/com/android/server/wifi/WifiNetworkHistory.java
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright (C) 2016 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.content.Context;
-
-import android.net.wifi.ScanResult;
-
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
-import android.net.wifi.WifiSsid;
-import android.os.Environment;
-import android.os.Process;
-import android.text.TextUtils;
-
-import android.util.Log;
-
-import com.android.server.net.DelayedDiskWrite;
-
-import java.io.BufferedInputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.text.DateFormat;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Provides an API to read and write the network history from WifiConfigurations to file
- * This is largely separate and extra to the supplicant config file.
- */
-public class WifiNetworkHistory {
- public static final String TAG = "WifiNetworkHistory";
- private static final boolean DBG = true;
- private static final boolean VDBG = true;
- static final String NETWORK_HISTORY_CONFIG_FILE = Environment.getDataDirectory()
- + "/misc/wifi/networkHistory.txt";
- /* Network History Keys */
- private static final String SSID_KEY = "SSID";
- static final String CONFIG_KEY = "CONFIG";
- private static final String CONFIG_BSSID_KEY = "CONFIG_BSSID";
- private static final String CHOICE_KEY = "CHOICE";
- private static final String CHOICE_TIME_KEY = "CHOICE_TIME";
- private static final String LINK_KEY = "LINK";
- private static final String BSSID_KEY = "BSSID";
- private static final String BSSID_KEY_END = "/BSSID";
- private static final String RSSI_KEY = "RSSI";
- private static final String FREQ_KEY = "FREQ";
- private static final String DATE_KEY = "DATE";
- private static final String MILLI_KEY = "MILLI";
- private static final String NETWORK_ID_KEY = "ID";
- private static final String PRIORITY_KEY = "PRIORITY";
- private static final String DEFAULT_GW_KEY = "DEFAULT_GW";
- private static final String AUTH_KEY = "AUTH";
- private static final String BSSID_STATUS_KEY = "BSSID_STATUS";
- private static final String SELF_ADDED_KEY = "SELF_ADDED";
- private static final String FAILURE_KEY = "FAILURE";
- private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD";
- private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION";
- static final String CREATOR_UID_KEY = "CREATOR_UID_KEY";
- private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY";
- private static final String UPDATE_UID_KEY = "UPDATE_UID";
- private static final String FQDN_KEY = "FQDN";
- private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE";
- private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH";
- private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS";
- private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS";
- private static final String NO_INTERNET_ACCESS_EXPECTED_KEY = "NO_INTERNET_ACCESS_EXPECTED";
- private static final String EPHEMERAL_KEY = "EPHEMERAL";
- private static final String USE_EXTERNAL_SCORES_KEY = "USE_EXTERNAL_SCORES";
- private static final String METERED_HINT_KEY = "METERED_HINT";
- private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION";
- private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL";
- private static final String CREATOR_NAME_KEY = "CREATOR_NAME";
- private static final String UPDATE_NAME_KEY = "UPDATE_NAME";
- private static final String USER_APPROVED_KEY = "USER_APPROVED";
- private static final String CREATION_TIME_KEY = "CREATION_TIME";
- private static final String UPDATE_TIME_KEY = "UPDATE_TIME";
- static final String SHARED_KEY = "SHARED";
- private static final String NETWORK_SELECTION_STATUS_KEY = "NETWORK_SELECTION_STATUS";
- private static final String NETWORK_SELECTION_DISABLE_REASON_KEY =
- "NETWORK_SELECTION_DISABLE_REASON";
- private static final String HAS_EVER_CONNECTED_KEY = "HAS_EVER_CONNECTED";
-
- private static final String SEPARATOR = ": ";
- private static final String NL = "\n";
-
- protected final DelayedDiskWrite mWriter;
- Context mContext;
- /*
- * Lost config list, whenever we read a config from networkHistory.txt that was not in
- * wpa_supplicant.conf
- */
- HashSet<String> mLostConfigsDbg = new HashSet<String>();
-
- public WifiNetworkHistory(Context c, DelayedDiskWrite writer) {
- mContext = c;
- mWriter = writer;
- }
-
- /**
- * Write network history to file, for configured networks
- *
- * @param networks List of ConfiguredNetworks to write to NetworkHistory
- */
- public void writeKnownNetworkHistory(final List<WifiConfiguration> networks,
- final ConcurrentHashMap<Integer, ScanDetailCache> scanDetailCaches,
- final Set<String> deletedEphemeralSSIDs) {
-
- /* Make a copy */
- //final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
-
- //for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
- // networks.add(new WifiConfiguration(config));
- //}
-
- mWriter.write(NETWORK_HISTORY_CONFIG_FILE, new DelayedDiskWrite.Writer() {
- public void onWriteCalled(DataOutputStream out) throws IOException {
- for (WifiConfiguration config : networks) {
- //loge("onWriteCalled write SSID: " + config.SSID);
- /* if (config.getLinkProperties() != null)
- loge(" lp " + config.getLinkProperties().toString());
- else
- loge("attempt config w/o lp");
- */
- NetworkSelectionStatus status = config.getNetworkSelectionStatus();
- if (VDBG) {
- int numlink = 0;
- if (config.linkedConfigurations != null) {
- numlink = config.linkedConfigurations.size();
- }
- String disableTime;
- if (config.getNetworkSelectionStatus().isNetworkEnabled()) {
- disableTime = "";
- } else {
- disableTime = "Disable time: " + DateFormat.getInstance().format(
- config.getNetworkSelectionStatus().getDisableTime());
- }
- logd("saving network history: " + config.configKey() + " gw: "
- + config.defaultGwMacAddress + " Network Selection-status: "
- + status.getNetworkStatusString()
- + disableTime + " ephemeral=" + config.ephemeral
- + " choice:" + status.getConnectChoice()
- + " link:" + numlink
- + " status:" + config.status
- + " nid:" + config.networkId
- + " hasEverConnected: " + status.getHasEverConnected());
- }
-
- if (!isValid(config)) {
- continue;
- }
-
- if (config.SSID == null) {
- if (VDBG) {
- logv("writeKnownNetworkHistory trying to write config with null SSID");
- }
- continue;
- }
- if (VDBG) {
- logv("writeKnownNetworkHistory write config " + config.configKey());
- }
- out.writeUTF(CONFIG_KEY + SEPARATOR + config.configKey() + NL);
-
- if (config.SSID != null) {
- out.writeUTF(SSID_KEY + SEPARATOR + config.SSID + NL);
- }
- if (config.BSSID != null) {
- out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + config.BSSID + NL);
- } else {
- out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + "null" + NL);
- }
- if (config.FQDN != null) {
- out.writeUTF(FQDN_KEY + SEPARATOR + config.FQDN + NL);
- }
-
- out.writeUTF(PRIORITY_KEY + SEPARATOR + Integer.toString(config.priority) + NL);
- out.writeUTF(NETWORK_ID_KEY + SEPARATOR
- + Integer.toString(config.networkId) + NL);
- out.writeUTF(SELF_ADDED_KEY + SEPARATOR
- + Boolean.toString(config.selfAdded) + NL);
- out.writeUTF(DID_SELF_ADD_KEY + SEPARATOR
- + Boolean.toString(config.didSelfAdd) + NL);
- out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY + SEPARATOR
- + Integer.toString(config.numNoInternetAccessReports) + NL);
- out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY + SEPARATOR
- + Boolean.toString(config.validatedInternetAccess) + NL);
- out.writeUTF(NO_INTERNET_ACCESS_EXPECTED_KEY + SEPARATOR +
- Boolean.toString(config.noInternetAccessExpected) + NL);
- out.writeUTF(EPHEMERAL_KEY + SEPARATOR
- + Boolean.toString(config.ephemeral) + NL);
- out.writeUTF(METERED_HINT_KEY + SEPARATOR
- + Boolean.toString(config.meteredHint) + NL);
- out.writeUTF(USE_EXTERNAL_SCORES_KEY + SEPARATOR
- + Boolean.toString(config.useExternalScores) + NL);
- if (config.creationTime != null) {
- out.writeUTF(CREATION_TIME_KEY + SEPARATOR + config.creationTime + NL);
- }
- if (config.updateTime != null) {
- out.writeUTF(UPDATE_TIME_KEY + SEPARATOR + config.updateTime + NL);
- }
- if (config.peerWifiConfiguration != null) {
- out.writeUTF(PEER_CONFIGURATION_KEY + SEPARATOR
- + config.peerWifiConfiguration + NL);
- }
- out.writeUTF(SCORER_OVERRIDE_KEY + SEPARATOR
- + Integer.toString(config.numScorerOverride) + NL);
- out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY + SEPARATOR
- + Integer.toString(config.numScorerOverrideAndSwitchedNetwork) + NL);
- out.writeUTF(NUM_ASSOCIATION_KEY + SEPARATOR
- + Integer.toString(config.numAssociation) + NL);
- out.writeUTF(CREATOR_UID_KEY + SEPARATOR
- + Integer.toString(config.creatorUid) + NL);
- out.writeUTF(CONNECT_UID_KEY + SEPARATOR
- + Integer.toString(config.lastConnectUid) + NL);
- out.writeUTF(UPDATE_UID_KEY + SEPARATOR
- + Integer.toString(config.lastUpdateUid) + NL);
- out.writeUTF(CREATOR_NAME_KEY + SEPARATOR
- + config.creatorName + NL);
- out.writeUTF(UPDATE_NAME_KEY + SEPARATOR
- + config.lastUpdateName + NL);
- out.writeUTF(USER_APPROVED_KEY + SEPARATOR
- + Integer.toString(config.userApproved) + NL);
- out.writeUTF(SHARED_KEY + SEPARATOR + Boolean.toString(config.shared) + NL);
- String allowedKeyManagementString =
- makeString(config.allowedKeyManagement,
- WifiConfiguration.KeyMgmt.strings);
- out.writeUTF(AUTH_KEY + SEPARATOR
- + allowedKeyManagementString + NL);
- out.writeUTF(NETWORK_SELECTION_STATUS_KEY + SEPARATOR
- + status.getNetworkSelectionStatus() + NL);
- out.writeUTF(NETWORK_SELECTION_DISABLE_REASON_KEY + SEPARATOR
- + status.getNetworkSelectionDisableReason() + NL);
-
- if (status.getConnectChoice() != null) {
- out.writeUTF(CHOICE_KEY + SEPARATOR + status.getConnectChoice() + NL);
- out.writeUTF(CHOICE_TIME_KEY + SEPARATOR
- + status.getConnectChoiceTimestamp() + NL);
- }
-
- if (config.linkedConfigurations != null) {
- log("writeKnownNetworkHistory write linked "
- + config.linkedConfigurations.size());
-
- for (String key : config.linkedConfigurations.keySet()) {
- out.writeUTF(LINK_KEY + SEPARATOR + key + NL);
- }
- }
-
- String macAddress = config.defaultGwMacAddress;
- if (macAddress != null) {
- out.writeUTF(DEFAULT_GW_KEY + SEPARATOR + macAddress + NL);
- }
-
- if (getScanDetailCache(config, scanDetailCaches) != null) {
- for (ScanDetail scanDetail : getScanDetailCache(config,
- scanDetailCaches).values()) {
- ScanResult result = scanDetail.getScanResult();
- out.writeUTF(BSSID_KEY + SEPARATOR
- + result.BSSID + NL);
- out.writeUTF(FREQ_KEY + SEPARATOR
- + Integer.toString(result.frequency) + NL);
-
- out.writeUTF(RSSI_KEY + SEPARATOR
- + Integer.toString(result.level) + NL);
-
- out.writeUTF(BSSID_KEY_END + NL);
- }
- }
- if (config.lastFailure != null) {
- out.writeUTF(FAILURE_KEY + SEPARATOR + config.lastFailure + NL);
- }
- out.writeUTF(HAS_EVER_CONNECTED_KEY + SEPARATOR
- + Boolean.toString(status.getHasEverConnected()) + NL);
- out.writeUTF(NL);
- // Add extra blank lines for clarity
- out.writeUTF(NL);
- out.writeUTF(NL);
- }
- if (deletedEphemeralSSIDs != null && deletedEphemeralSSIDs.size() > 0) {
- for (String ssid : deletedEphemeralSSIDs) {
- out.writeUTF(DELETED_EPHEMERAL_KEY);
- out.writeUTF(ssid);
- out.writeUTF(NL);
- }
- }
- }
- });
- }
-
- /**
- * Adds information stored in networkHistory.txt to the given configs. The configs are provided
- * as a mapping from configKey to WifiConfiguration, because the WifiConfigurations themselves
- * do not contain sufficient information to compute their configKeys until after the information
- * that is stored in networkHistory.txt has been added to them.
- *
- * @param configs mapping from configKey to a WifiConfiguration that contains the information
- * information read from wpa_supplicant.conf
- */
- public void readNetworkHistory(Map<String, WifiConfiguration> configs,
- Map<Integer, ScanDetailCache> scanDetailCaches,
- Set<String> deletedEphemeralSSIDs) {
-
- try (DataInputStream in =
- new DataInputStream(new BufferedInputStream(
- new FileInputStream(NETWORK_HISTORY_CONFIG_FILE)))) {
-
- String bssid = null;
- String ssid = null;
-
- int freq = 0;
- int status = 0;
- long seen = 0;
- int rssi = WifiConfiguration.INVALID_RSSI;
- String caps = null;
-
- WifiConfiguration config = null;
- while (true) {
- String line = in.readUTF();
- if (line == null) {
- break;
- }
- int colon = line.indexOf(':');
- if (colon < 0) {
- continue;
- }
-
- String key = line.substring(0, colon).trim();
- String value = line.substring(colon + 1).trim();
-
- if (key.equals(CONFIG_KEY)) {
- config = configs.get(value);
-
- // skip reading that configuration data
- // since we don't have a corresponding network ID
- if (config == null) {
- Log.e(TAG, "readNetworkHistory didnt find netid for hash="
- + Integer.toString(value.hashCode())
- + " key: " + value);
- mLostConfigsDbg.add(value);
- continue;
- } else {
- // After an upgrade count old connections as owned by system
- if (config.creatorName == null || config.lastUpdateName == null) {
- config.creatorName =
- mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID);
- config.lastUpdateName = config.creatorName;
-
- if (DBG) {
- Log.w(TAG, "Upgrading network " + config.networkId
- + " to " + config.creatorName);
- }
- }
- }
- } else if (config != null) {
- NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
- switch (key) {
- case SSID_KEY:
- if (config.isPasspoint()) {
- break;
- }
- ssid = value;
- if (config.SSID != null && !config.SSID.equals(ssid)) {
- loge("Error parsing network history file, mismatched SSIDs");
- config = null; //error
- ssid = null;
- } else {
- config.SSID = ssid;
- }
- break;
- case CONFIG_BSSID_KEY:
- config.BSSID = value.equals("null") ? null : value;
- break;
- case FQDN_KEY:
- // Check for literal 'null' to be backwards compatible.
- config.FQDN = value.equals("null") ? null : value;
- break;
- case DEFAULT_GW_KEY:
- config.defaultGwMacAddress = value;
- break;
- case SELF_ADDED_KEY:
- config.selfAdded = Boolean.parseBoolean(value);
- break;
- case DID_SELF_ADD_KEY:
- config.didSelfAdd = Boolean.parseBoolean(value);
- break;
- case NO_INTERNET_ACCESS_REPORTS_KEY:
- config.numNoInternetAccessReports = Integer.parseInt(value);
- break;
- case VALIDATED_INTERNET_ACCESS_KEY:
- config.validatedInternetAccess = Boolean.parseBoolean(value);
- break;
- case NO_INTERNET_ACCESS_EXPECTED_KEY:
- config.noInternetAccessExpected = Boolean.parseBoolean(value);
- break;
- case CREATION_TIME_KEY:
- config.creationTime = value;
- break;
- case UPDATE_TIME_KEY:
- config.updateTime = value;
- break;
- case EPHEMERAL_KEY:
- config.ephemeral = Boolean.parseBoolean(value);
- break;
- case METERED_HINT_KEY:
- config.meteredHint = Boolean.parseBoolean(value);
- break;
- case USE_EXTERNAL_SCORES_KEY:
- config.useExternalScores = Boolean.parseBoolean(value);
- break;
- case CREATOR_UID_KEY:
- config.creatorUid = Integer.parseInt(value);
- break;
- case SCORER_OVERRIDE_KEY:
- config.numScorerOverride = Integer.parseInt(value);
- break;
- case SCORER_OVERRIDE_AND_SWITCH_KEY:
- config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(value);
- break;
- case NUM_ASSOCIATION_KEY:
- config.numAssociation = Integer.parseInt(value);
- break;
- case CONNECT_UID_KEY:
- config.lastConnectUid = Integer.parseInt(value);
- break;
- case UPDATE_UID_KEY:
- config.lastUpdateUid = Integer.parseInt(value);
- break;
- case FAILURE_KEY:
- config.lastFailure = value;
- break;
- case PEER_CONFIGURATION_KEY:
- config.peerWifiConfiguration = value;
- break;
- case NETWORK_SELECTION_STATUS_KEY:
- int networkStatusValue = Integer.parseInt(value);
- // Reset temporarily disabled network status
- if (networkStatusValue ==
- NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) {
- networkStatusValue =
- NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
- }
- networkStatus.setNetworkSelectionStatus(networkStatusValue);
- break;
- case NETWORK_SELECTION_DISABLE_REASON_KEY:
- networkStatus.setNetworkSelectionDisableReason(Integer.parseInt(value));
- break;
- case CHOICE_KEY:
- networkStatus.setConnectChoice(value);
- break;
- case CHOICE_TIME_KEY:
- networkStatus.setConnectChoiceTimestamp(Long.parseLong(value));
- break;
- case LINK_KEY:
- if (config.linkedConfigurations == null) {
- config.linkedConfigurations = new HashMap<>();
- } else {
- config.linkedConfigurations.put(value, -1);
- }
- break;
- case BSSID_KEY:
- status = 0;
- ssid = null;
- bssid = null;
- freq = 0;
- seen = 0;
- rssi = WifiConfiguration.INVALID_RSSI;
- caps = "";
- break;
- case RSSI_KEY:
- rssi = Integer.parseInt(value);
- break;
- case FREQ_KEY:
- freq = Integer.parseInt(value);
- break;
- case DATE_KEY:
- /*
- * when reading the configuration from file we don't update the date
- * so as to avoid reading back stale or non-sensical data that would
- * depend on network time.
- * The date of a WifiConfiguration should only come from actual scan
- * result.
- *
- String s = key.replace(FREQ_KEY, "");
- seen = Integer.getInteger(s);
- */
- break;
- case BSSID_KEY_END:
- if ((bssid != null) && (ssid != null)) {
- if (getScanDetailCache(config, scanDetailCaches) != null) {
- WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid);
- ScanDetail scanDetail = new ScanDetail(wssid, bssid,
- caps, rssi, freq, (long) 0, seen);
- getScanDetailCache(config, scanDetailCaches).put(scanDetail);
- }
- }
- break;
- case DELETED_EPHEMERAL_KEY:
- if (!TextUtils.isEmpty(value)) {
- deletedEphemeralSSIDs.add(value);
- }
- break;
- case CREATOR_NAME_KEY:
- config.creatorName = value;
- break;
- case UPDATE_NAME_KEY:
- config.lastUpdateName = value;
- break;
- case USER_APPROVED_KEY:
- config.userApproved = Integer.parseInt(value);
- break;
- case SHARED_KEY:
- config.shared = Boolean.parseBoolean(value);
- break;
- case HAS_EVER_CONNECTED_KEY:
- networkStatus.setHasEverConnected(Boolean.parseBoolean(value));
- break;
- }
- }
- }
- } catch (EOFException e) {
- // do nothing
- } catch (FileNotFoundException e) {
- Log.i(TAG, "readNetworkHistory: no config file, " + e);
- } catch (NumberFormatException e) {
- Log.e(TAG, "readNetworkHistory: failed to parse, " + e, e);
- } catch (IOException e) {
- Log.e(TAG, "readNetworkHistory: failed to read, " + e, e);
- }
- }
-
- /**
- * Ported this out of WifiServiceImpl, I have no idea what it's doing
- * <TODO> figure out what/why this is doing
- * <TODO> Port it into WifiConfiguration, then remove all the silly business from ServiceImpl
- */
- public boolean isValid(WifiConfiguration config) {
- if (config.allowedKeyManagement == null) {
- return false;
- }
- if (config.allowedKeyManagement.cardinality() > 1) {
- if (config.allowedKeyManagement.cardinality() != 2) {
- return false;
- }
- if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
- return false;
- }
- if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
- && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
- return false;
- }
- }
- return true;
- }
-
- private static String makeString(BitSet set, String[] strings) {
- StringBuffer buf = new StringBuffer();
- int nextSetBit = -1;
-
- /* Make sure all set bits are in [0, strings.length) to avoid
- * going out of bounds on strings. (Shouldn't happen, but...) */
- set = set.get(0, strings.length);
-
- while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
- buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
- }
-
- // remove trailing space
- if (set.cardinality() > 0) {
- buf.setLength(buf.length() - 1);
- }
-
- return buf.toString();
- }
-
- protected void logv(String s) {
- Log.v(TAG, s);
- }
- protected void logd(String s) {
- Log.d(TAG, s);
- }
- protected void log(String s) {
- Log.d(TAG, s);
- }
- protected void loge(String s) {
- loge(s, false);
- }
- protected void loge(String s, boolean stack) {
- if (stack) {
- Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
- + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
- + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
- + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
- } else {
- Log.e(TAG, s);
- }
- }
-
- private ScanDetailCache getScanDetailCache(WifiConfiguration config,
- Map<Integer, ScanDetailCache> scanDetailCaches) {
- if (config == null || scanDetailCaches == null) return null;
- ScanDetailCache cache = scanDetailCaches.get(config.networkId);
- if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
- cache =
- new ScanDetailCache(
- config, WifiConfigManager.SCAN_CACHE_ENTRIES_MAX_SIZE,
- WifiConfigManager.SCAN_CACHE_ENTRIES_TRIM_SIZE);
- scanDetailCaches.put(config.networkId, cache);
- }
- return cache;
- }
-}
diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java
index 89068a8cc..071fc07d4 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java
@@ -575,15 +575,15 @@ public class WifiNetworkSelector {
mLocalLog = localLog;
mThresholdQualifiedRssi24 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
mThresholdQualifiedRssi5 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
mThresholdMinimumRssi24 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz);
mThresholdMinimumRssi5 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz);
mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_associated_network_selection);
+ R.bool.config_wifi_framework_enable_associated_network_selection);
mStayOnNetworkMinimumTxRate = context.getResources().getInteger(
R.integer.config_wifi_framework_min_tx_rate_for_staying_on_network);
mStayOnNetworkMinimumRxRate = context.getResources().getInteger(
diff --git a/service/java/com/android/server/wifi/WifiNotificationController.java b/service/java/com/android/server/wifi/WifiNotificationController.java
deleted file mode 100644
index 797fd438b..000000000
--- a/service/java/com/android/server/wifi/WifiNotificationController.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2013 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.Notification;
-import android.app.NotificationManager;
-import android.app.TaskStackBuilder;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-
-import com.android.internal.notification.SystemNotificationChannels;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-
-/**
- * Takes care of handling the "open wi-fi network available" notification
- * @hide
- */
-public class WifiNotificationController {
- /**
- * The icon to show in the 'available networks' notification. This will also
- * be the ID of the Notification given to the NotificationManager.
- */
- private static final int ICON_NETWORKS_AVAILABLE =
- com.android.internal.R.drawable.stat_notify_wifi_in_range;
- /**
- * When a notification is shown, we wait this amount before possibly showing it again.
- */
- private final long NOTIFICATION_REPEAT_DELAY_MS;
-
- /** Whether the user has set the setting to show the 'available networks' notification. */
- private boolean mSettingEnabled;
-
- /**
- * Observes the user setting to keep {@link #mSettingEnabled} in sync.
- */
- private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
-
- /**
- * The {@link System#currentTimeMillis()} must be at least this value for us
- * to show the notification again.
- */
- private long mNotificationRepeatTime;
- /**
- * The Notification object given to the NotificationManager.
- */
- private Notification.Builder mNotificationBuilder;
- /**
- * Whether the notification is being shown, as set by us. That is, if the
- * user cancels the notification, we will not receive the callback so this
- * will still be true. We only guarantee if this is false, then the
- * notification is not showing.
- */
- private boolean mNotificationShown;
- /** Whether the screen is on or not. */
- private boolean mScreenOn;
-
- private final Context mContext;
- private FrameworkFacade mFrameworkFacade;
-
- WifiNotificationController(Context context,
- Looper looper,
- FrameworkFacade framework,
- Notification.Builder builder) {
- mContext = context;
- mFrameworkFacade = framework;
- mNotificationBuilder = builder;
-
- mScreenOn = false;
-
- // Setting is in seconds
- NOTIFICATION_REPEAT_DELAY_MS = mFrameworkFacade.getIntegerSetting(context,
- Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000L;
- mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(
- new Handler(looper));
- mNotificationEnabledSettingObserver.register();
- }
-
- /**
- * Clears the pending notification. This is called by {@link WifiConnectivityManager} on stop.
- *
- * @param resetRepeatDelay resets the time delay for repeated notification if true.
- */
- public void clearPendingNotification(boolean resetRepeatDelay) {
- if (resetRepeatDelay) {
- mNotificationRepeatTime = 0;
- }
- setNotificationVisible(false, 0, false, 0);
- }
-
- private boolean isControllerEnabled() {
- return mSettingEnabled && !UserManager.get(mContext)
- .hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT);
- }
-
- /**
- * If there are open networks, attempt to post an open network notification.
- *
- * @param availableNetworks Available networks from
- * {@link WifiNetworkSelector.NetworkEvaluator#getFilteredScanDetailsForOpenUnsavedNetworks()}.
- */
- public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) {
- if (!isControllerEnabled()) {
- clearPendingNotification(true /* resetRepeatDelay */);
- return;
- }
- if (availableNetworks.isEmpty()) {
- clearPendingNotification(false /* resetRepeatDelay */);
- return;
- }
-
- // Do not show or update the notification if screen is off. We want to avoid a race that
- // could occur between a user picking a network in settings and a network candidate picked
- // through network selection, which will happen because screen on triggers a new
- // connectivity scan.
- if (mNotificationShown || !mScreenOn) {
- return;
- }
-
- setNotificationVisible(true, availableNetworks.size(), false, 0);
- }
-
- /** Handles screen state changes. */
- public void handleScreenStateChanged(boolean screenOn) {
- mScreenOn = screenOn;
- }
-
- /**
- * Display or don't display a notification that there are open Wi-Fi networks.
- * @param visible {@code true} if notification should be visible, {@code false} otherwise
- * @param numNetworks the number networks seen
- * @param force {@code true} to force notification to be shown/not-shown,
- * even if it is already shown/not-shown.
- * @param delay time in milliseconds after which the notification should be made
- * visible or invisible.
- */
- private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
- int delay) {
-
- // Since we use auto cancel on the notification, when the
- // mNetworksAvailableNotificationShown is true, the notification may
- // have actually been canceled. However, when it is false we know
- // for sure that it is not being shown (it will not be shown any other
- // place than here)
-
- // If it should be hidden and it is already hidden, then noop
- if (!visible && !mNotificationShown && !force) {
- return;
- }
-
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
-
- Message message;
- if (visible) {
-
- // Not enough time has passed to show the notification again
- if (System.currentTimeMillis() < mNotificationRepeatTime) {
- return;
- }
-
- if (mNotificationBuilder == null) {
- // Cache the Notification builder object.
- mNotificationBuilder = new Notification.Builder(mContext,
- SystemNotificationChannels.NETWORK_AVAILABLE)
- .setWhen(0)
- .setSmallIcon(ICON_NETWORKS_AVAILABLE)
- .setAutoCancel(true)
- .setContentIntent(TaskStackBuilder.create(mContext)
- .addNextIntentWithParentStack(
- new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
- .getPendingIntent(0, 0, null, UserHandle.CURRENT))
- .setColor(mContext.getResources().getColor(
- com.android.internal.R.color.system_notification_accent_color));
- }
-
- CharSequence title = mContext.getResources().getQuantityText(
- com.android.internal.R.plurals.wifi_available, numNetworks);
- CharSequence details = mContext.getResources().getQuantityText(
- com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
- mNotificationBuilder.setTicker(title);
- mNotificationBuilder.setContentTitle(title);
- mNotificationBuilder.setContentText(details);
-
- mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
-
- notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE,
- mNotificationBuilder.build(), UserHandle.ALL);
- } else {
- notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
- }
-
- mNotificationShown = visible;
- }
-
- /** Dump ONA controller state. */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("WifiNotificationController: ");
- pw.println("mSettingEnabled " + mSettingEnabled);
- pw.println("mNotificationRepeatTime " + mNotificationRepeatTime);
- pw.println("mNotificationShown " + mNotificationShown);
- }
-
- private class NotificationEnabledSettingObserver extends ContentObserver {
- NotificationEnabledSettingObserver(Handler handler) {
- super(handler);
- }
-
- public void register() {
- mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
- Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
- mSettingEnabled = getValue();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- mSettingEnabled = getValue();
- clearPendingNotification(true /* resetRepeatDelay */);
- }
-
- private boolean getValue() {
- return mFrameworkFacade.getIntegerSetting(mContext,
- Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
- }
- }
-}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 63f47587a..d2f90e0f4 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -591,7 +591,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public void startScan(ScanSettings settings, WorkSource workSource, String packageName) {
enforceChangePermission();
- mLog.trace("startScan uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("startScan uid=%").c(Binder.getCallingUid()).flush();
// Check and throttle background apps for wifi scan.
if (isRequestFromBackground(packageName)) {
long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
@@ -683,7 +683,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public String getCurrentNetworkWpsNfcConfigurationToken() {
enforceConnectivityInternalPermission();
- mLog.trace("getCurrentNetworkWpsNfcConfigurationToken uid=%")
+ mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%")
.c(Binder.getCallingUid()).flush();
// TODO Add private logging for netId b/33807876
return mWifiStateMachine.syncGetCurrentNetworkWpsNfcConfigurationToken();
@@ -713,6 +713,11 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}
+ private boolean checkNetworkSettingsPermission(int pid, int uid) {
+ return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
private void enforceNetworkSettingsPermission() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
"WifiService");
@@ -777,15 +782,15 @@ public class WifiServiceImpl extends IWifiManager.Stub {
enforceChangePermission();
Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
- mLog.trace("setWifiEnabled package=% uid=% enable=%").c(packageName)
+ mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
.c(Binder.getCallingUid()).c(enable).flush();
- boolean isFromSettings =
- mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid());
+ boolean isFromSettings = checkNetworkSettingsPermission(
+ Binder.getCallingPid(), Binder.getCallingUid());
// If Airplane mode is enabled, only Settings is allowed to toggle Wifi
if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
- mLog.trace("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
+ mLog.info("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
return false;
}
@@ -794,7 +799,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
if (apEnabled && !isFromSettings) {
- mLog.trace("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
+ mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
return false;
}
@@ -847,7 +852,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public int getWifiEnabledState() {
enforceAccessPermission();
- mLog.trace("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
return mWifiStateMachine.syncGetWifiState();
}
@@ -862,7 +867,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
enforceChangePermission();
mWifiPermissionsUtil.enforceTetherChangePermission(mContext);
- mLog.trace("setWifiApEnabled uid=% enable=%").c(Binder.getCallingUid()).c(enabled).flush();
+ mLog.info("setWifiApEnabled uid=% enable=%").c(Binder.getCallingUid()).c(enabled).flush();
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
@@ -888,7 +893,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public int getWifiApEnabledState() {
enforceAccessPermission();
- mLog.trace("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
return mWifiStateMachine.syncGetWifiApState();
}
@@ -963,7 +968,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
break;
default:
- mLog.trace("updateInterfaceIpStateInternal: unknown mode %").c(mode).flush();
+ mLog.warn("updateInterfaceIpStateInternal: unknown mode %").c(mode).flush();
}
}
}
@@ -979,7 +984,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
// NETWORK_STACK is a signature only permission.
enforceNetworkStackPermission();
- mLog.trace("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
synchronized (mLocalOnlyHotspotRequests) {
// If a tethering request comes in while we have LOHS running (or requested), call stop
@@ -1023,7 +1028,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
// only permitted callers are allowed to this point - they must have gone through
// connectivity service since this method is protected with the NETWORK_STACK PERMISSION
- mLog.trace("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
synchronized (mLocalOnlyHotspotRequests) {
// If a tethering request comes in while we have LOHS running (or requested), call stop
@@ -1212,17 +1217,17 @@ public class WifiServiceImpl extends IWifiManager.Stub {
return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
}
} catch (RemoteException e) {
- mLog.trace("RemoteException during isAppForeground when calling startLOHS");
+ mLog.warn("RemoteException during isAppForeground when calling startLOHS");
return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
}
- mLog.trace("startLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
+ mLog.info("startLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
synchronized (mLocalOnlyHotspotRequests) {
// check if we are currently tethering
if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) {
// Tethering is enabled, cannot start LocalOnlyHotspot
- mLog.trace("Cannot start localOnlyHotspot when WiFi Tethering is active.");
+ mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.");
return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
}
@@ -1272,7 +1277,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
- mLog.trace("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
+ mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
synchronized (mLocalOnlyHotspotRequests) {
// was the caller already registered? check request tracker - return false if not
@@ -1360,7 +1365,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
+ "(uid = " + uid + ")");
}
- mLog.trace("getWifiApConfiguration uid=%").c(uid).flush();
+ mLog.info("getWifiApConfiguration uid=%").c(uid).flush();
return mWifiStateMachine.syncGetWifiApConfiguration();
}
@@ -1379,7 +1384,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
throw new SecurityException("App not allowed to read or update stored WiFi AP config "
+ "(uid = " + uid + ")");
}
- mLog.trace("setWifiApConfiguration uid=%").c(uid).flush();
+ mLog.info("setWifiApConfiguration uid=%").c(uid).flush();
if (wifiConfig == null)
return;
if (isValid(wifiConfig)) {
@@ -1395,7 +1400,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean isScanAlwaysAvailable() {
enforceAccessPermission();
- mLog.trace("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
return mSettingsStore.isScanAlwaysAvailable();
}
@@ -1405,7 +1410,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void disconnect() {
enforceChangePermission();
- mLog.trace("disconnect uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush();
mWifiStateMachine.disconnectCommand();
}
@@ -1415,8 +1420,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void reconnect() {
enforceChangePermission();
- mLog.trace("reconnect uid=%").c(Binder.getCallingUid()).flush();
- mWifiStateMachine.reconnectCommand();
+ mLog.info("reconnect uid=%").c(Binder.getCallingUid()).flush();
+ mWifiStateMachine.reconnectCommand(new WorkSource(Binder.getCallingUid()));
}
/**
@@ -1425,7 +1430,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void reassociate() {
enforceChangePermission();
- mLog.trace("reassociate uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("reassociate uid=%").c(Binder.getCallingUid()).flush();
mWifiStateMachine.reassociateCommand();
}
@@ -1435,7 +1440,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public int getSupportedFeatures() {
enforceAccessPermission();
- mLog.trace("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel != null) {
return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel);
} else {
@@ -1447,7 +1452,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void requestActivityInfo(ResultReceiver result) {
Bundle bundle = new Bundle();
- mLog.trace("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush();
bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo());
result.send(0, bundle);
}
@@ -1458,7 +1463,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public WifiActivityEnergyInfo reportActivityInfo() {
enforceAccessPermission();
- mLog.trace("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush();
if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
return null;
}
@@ -1531,7 +1536,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public ParceledListSlice<WifiConfiguration> getConfiguredNetworks() {
enforceAccessPermission();
- mLog.trace("getConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel != null) {
List<WifiConfiguration> configs = mWifiStateMachine.syncGetConfiguredNetworks(
Binder.getCallingUid(), mWifiStateMachineChannel);
@@ -1552,7 +1557,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks() {
enforceReadCredentialPermission();
enforceAccessPermission();
- mLog.trace("getPrivilegedConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getPrivilegedConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel != null) {
List<WifiConfiguration> configs =
mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
@@ -1574,7 +1579,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
enforceAccessPermission();
- mLog.trace("getMatchingWifiConfig uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getMatchingWifiConfig uid=%").c(Binder.getCallingUid()).flush();
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_PASSPOINT)) {
throw new UnsupportedOperationException("Passpoint not enabled");
@@ -1591,7 +1596,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public List<OsuProvider> getMatchingOsuProviders(ScanResult scanResult) {
enforceAccessPermission();
- mLog.trace("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush();
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_PASSPOINT)) {
throw new UnsupportedOperationException("Passpoint not enabled");
@@ -1607,7 +1612,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public int addOrUpdateNetwork(WifiConfiguration config) {
enforceChangePermission();
- mLog.trace("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
// Previously, this API is overloaded for installing Passpoint profiles. Now
// that we have a dedicated API for doing it, redirect the call to the dedicated API.
@@ -1678,7 +1683,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean removeNetwork(int netId) {
enforceChangePermission();
- mLog.trace("removeNetwork uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("removeNetwork uid=%").c(Binder.getCallingUid()).flush();
// TODO Add private logging for netId b/33807876
if (mWifiStateMachineChannel != null) {
return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
@@ -1699,7 +1704,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public boolean enableNetwork(int netId, boolean disableOthers) {
enforceChangePermission();
// TODO b/33807876 Log netId
- mLog.trace("enableNetwork uid=% disableOthers=%")
+ mLog.info("enableNetwork uid=% disableOthers=%")
.c(Binder.getCallingUid())
.c(disableOthers).flush();
@@ -1722,7 +1727,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public boolean disableNetwork(int netId) {
enforceChangePermission();
// TODO b/33807876 Log netId
- mLog.trace("disableNetwork uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("disableNetwork uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel != null) {
return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
@@ -1737,14 +1742,14 @@ public class WifiServiceImpl extends IWifiManager.Stub {
* @return the Wi-Fi information, contained in {@link WifiInfo}.
*/
@Override
- public WifiInfo getConnectionInfo() {
+ public WifiInfo getConnectionInfo(String callingPackage) {
enforceAccessPermission();
- mLog.trace("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
/*
* Make sure we have the latest information, by sending
* a status request to the supplicant.
*/
- return mWifiStateMachine.syncRequestConnectionInfo();
+ return mWifiStateMachine.syncRequestConnectionInfo(callingPackage);
}
/**
@@ -1780,7 +1785,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
enforceChangePermission();
- mLog.trace("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_PASSPOINT)) {
throw new UnsupportedOperationException("Passpoint not enabled");
@@ -1798,7 +1803,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean removePasspointConfiguration(String fqdn) {
enforceChangePermission();
- mLog.trace("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_PASSPOINT)) {
throw new UnsupportedOperationException("Passpoint not enabled");
@@ -1816,7 +1821,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public List<PasspointConfiguration> getPasspointConfigurations() {
enforceAccessPermission();
- mLog.trace("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_PASSPOINT)) {
throw new UnsupportedOperationException("Passpoint not enabled");
@@ -1832,7 +1837,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void queryPasspointIcon(long bssid, String fileName) {
enforceAccessPermission();
- mLog.trace("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_PASSPOINT)) {
throw new UnsupportedOperationException("Passpoint not enabled");
@@ -1847,7 +1852,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
*/
@Override
public int matchProviderWithCurrentNetwork(String fqdn) {
- mLog.trace("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
return mWifiStateMachine.matchProviderWithCurrentNetwork(mWifiStateMachineChannel, fqdn);
}
@@ -1858,7 +1863,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
*/
@Override
public void deauthenticateNetwork(long holdoff, boolean ess) {
- mLog.trace("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
mWifiStateMachine.deauthenticateNetwork(mWifiStateMachineChannel, holdoff, ess);
}
@@ -1871,7 +1876,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean saveConfiguration() {
enforceChangePermission();
- mLog.trace("saveConfiguration uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("saveConfiguration uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel != null) {
return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
} else {
@@ -1894,7 +1899,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
" with persist set to " + persist);
enforceConnectivityInternalPermission();
- mLog.trace("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
final long token = Binder.clearCallingIdentity();
mCountryCode.setCountryCode(countryCode);
Binder.restoreCallingIdentity(token);
@@ -1909,7 +1914,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public String getCountryCode() {
enforceConnectivityInternalPermission();
- mLog.trace("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
String country = mCountryCode.getCountryCode();
return country;
}
@@ -1917,7 +1922,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean isDualBandSupported() {
//TODO: Should move towards adding a driver API that checks at runtime
- mLog.trace("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush();
return mContext.getResources().getBoolean(
com.android.internal.R.bool.config_wifi_dual_band_support);
}
@@ -1932,7 +1937,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Deprecated
public DhcpInfo getDhcpInfo() {
enforceAccessPermission();
- mLog.trace("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
DhcpInfo info = new DhcpInfo();
@@ -2045,7 +2050,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
if (remoteAddress == null) {
throw new IllegalArgumentException("remoteAddress cannot be null");
}
- mLog.trace("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
+ mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
TdlsTaskParams params = new TdlsTaskParams();
params.remoteIpAddress = remoteAddress;
params.enable = enable;
@@ -2055,7 +2060,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
- mLog.trace("enableTdlsWithMacAddress uid=% enable=%")
+ mLog.info("enableTdlsWithMacAddress uid=% enable=%")
.c(Binder.getCallingUid())
.c(enable)
.flush();
@@ -2074,7 +2079,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public Messenger getWifiServiceMessenger() {
enforceAccessPermission();
enforceChangePermission();
- mLog.trace("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
return new Messenger(mClientHandler);
}
@@ -2085,7 +2090,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public void disableEphemeralNetwork(String SSID) {
enforceAccessPermission();
enforceChangePermission();
- mLog.trace("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
mWifiStateMachine.disableEphemeralNetwork(SSID);
}
@@ -2321,7 +2326,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
- mLog.trace("acquireWifiLock uid=% lockMode=%")
+ mLog.info("acquireWifiLock uid=% lockMode=%")
.c(Binder.getCallingUid())
.c(lockMode).flush();
if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) {
@@ -2333,13 +2338,13 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
- mLog.trace("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
mWifiLockManager.updateWifiLockWorkSource(binder, ws);
}
@Override
public boolean releaseWifiLock(IBinder binder) {
- mLog.trace("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
if (mWifiLockManager.releaseWifiLock(binder)) {
mWifiController.sendMessage(CMD_LOCKS_CHANGED);
return true;
@@ -2350,35 +2355,35 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void initializeMulticastFiltering() {
enforceMulticastChangePermission();
- mLog.trace("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
mWifiMulticastLockManager.initializeFiltering();
}
@Override
public void acquireMulticastLock(IBinder binder, String tag) {
enforceMulticastChangePermission();
- mLog.trace("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
mWifiMulticastLockManager.acquireLock(binder, tag);
}
@Override
public void releaseMulticastLock() {
enforceMulticastChangePermission();
- mLog.trace("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
mWifiMulticastLockManager.releaseLock();
}
@Override
public boolean isMulticastEnabled() {
enforceAccessPermission();
- mLog.trace("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
return mWifiMulticastLockManager.isMulticastEnabled();
}
@Override
public void enableVerboseLogging(int verbose) {
enforceAccessPermission();
- mLog.trace("enableVerboseLogging uid=% verbose=%")
+ mLog.info("enableVerboseLogging uid=% verbose=%")
.c(Binder.getCallingUid())
.c(verbose).flush();
mFacade.setIntegerSetting(
@@ -2398,7 +2403,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public int getVerboseLoggingLevel() {
enforceAccessPermission();
- mLog.trace("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
return mFacade.getIntegerSetting(
mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0);
}
@@ -2406,7 +2411,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void enableAggressiveHandover(int enabled) {
enforceAccessPermission();
- mLog.trace("enableAggressiveHandover uid=% enabled=%")
+ mLog.info("enableAggressiveHandover uid=% enabled=%")
.c(Binder.getCallingUid())
.c(enabled)
.flush();
@@ -2416,14 +2421,14 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public int getAggressiveHandover() {
enforceAccessPermission();
- mLog.trace("getAggressiveHandover uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getAggressiveHandover uid=%").c(Binder.getCallingUid()).flush();
return mWifiStateMachine.getAggressiveHandover();
}
@Override
public void setAllowScansWithTraffic(int enabled) {
enforceAccessPermission();
- mLog.trace("setAllowScansWithTraffic uid=% enabled=%")
+ mLog.info("setAllowScansWithTraffic uid=% enabled=%")
.c(Binder.getCallingUid())
.c(enabled).flush();
mWifiStateMachine.setAllowScansWithTraffic(enabled);
@@ -2432,14 +2437,14 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public int getAllowScansWithTraffic() {
enforceAccessPermission();
- mLog.trace("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
return mWifiStateMachine.getAllowScansWithTraffic();
}
@Override
public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
enforceChangePermission();
- mLog.trace("setEnableAutoJoinWhenAssociated uid=% enabled=%")
+ mLog.info("setEnableAutoJoinWhenAssociated uid=% enabled=%")
.c(Binder.getCallingUid())
.c(enabled).flush();
return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
@@ -2448,7 +2453,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public boolean getEnableAutoJoinWhenAssociated() {
enforceAccessPermission();
- mLog.trace("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
}
@@ -2457,7 +2462,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public WifiConnectionStatistics getConnectionStatistics() {
enforceAccessPermission();
enforceReadCredentialPermission();
- mLog.trace("getConnectionStatistics uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getConnectionStatistics uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel != null) {
return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
} else {
@@ -2469,7 +2474,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void factoryReset() {
enforceConnectivityInternalPermission();
- mLog.trace("factoryReset uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("factoryReset uid=%").c(Binder.getCallingUid()).flush();
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
return;
}
@@ -2543,7 +2548,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public Network getCurrentNetwork() {
enforceAccessPermission();
- mLog.trace("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
return mWifiStateMachine.getCurrentNetwork();
}
@@ -2575,9 +2580,9 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void enableWifiConnectivityManager(boolean enabled) {
enforceConnectivityInternalPermission();
- mLog.trace("enableWifiConnectivityManager uid=% enabled=%")
- .c(Binder.getCallingUid())
- .c(enabled).flush();
+ mLog.info("enableWifiConnectivityManager uid=% enabled=%")
+ .c(Binder.getCallingUid())
+ .c(enabled).flush();
mWifiStateMachine.enableWifiConnectivityManager(enabled);
}
@@ -2589,7 +2594,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public byte[] retrieveBackupData() {
enforceNetworkSettingsPermission();
- mLog.trace("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel == null) {
Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
return null;
@@ -2634,7 +2639,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
@Override
public void restoreBackupData(byte[] data) {
enforceNetworkSettingsPermission();
- mLog.trace("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
+ mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
if (mWifiStateMachineChannel == null) {
Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
return;
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index a8bd578c6..ff3aea952 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -31,6 +31,7 @@ import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
import android.Manifest;
import android.app.ActivityManager;
+import android.app.AppGlobals;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -82,6 +83,7 @@ import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.p2p.IWifiP2pManager;
import android.os.BatteryStats;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -260,7 +262,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
if (mVerboseLoggingEnabled) {
Log.e(TAG, "onRssiThresholdBreach event. Cur Rssi = " + curRssi);
}
- sendMessage(CMD_RSSI_THRESHOLD_BREACH, curRssi);
+ sendMessage(CMD_RSSI_THRESHOLD_BREACHED, curRssi);
}
public void processRssiThreshold(byte curRssi, int reason) {
@@ -278,7 +280,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
// the rssi thresholds and raised event to host. This would be eggregious if this
// value is invalid
mWifiInfo.setRssi(curRssi);
- updateCapabilities(getCurrentWifiConfiguration());
+ updateCapabilities();
int ret = startRssiMonitoringOffload(maxRssi, minRssi);
Log.d(TAG, "Re-program RSSI thresholds for " + smToString(reason) +
": [" + minRssi + ", " + maxRssi + "], curRssi=" + curRssi + " ret=" + ret);
@@ -364,7 +366,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
private final Object mDhcpResultsLock = new Object();
private DhcpResults mDhcpResults;
- // NOTE: Do not return to clients - use #getWiFiInfoForUid(int)
+ // NOTE: Do not return to clients - see syncRequestConnectionInfo()
private final WifiInfo mWifiInfo;
private NetworkInfo mNetworkInfo;
private final NetworkCapabilities mDfltNetworkCapabilities;
@@ -691,7 +693,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
static final int CMD_STOP_RSSI_MONITORING_OFFLOAD = BASE + 163;
/* used to indicated RSSI threshold breach in hw */
- static final int CMD_RSSI_THRESHOLD_BREACH = BASE + 164;
+ static final int CMD_RSSI_THRESHOLD_BREACHED = BASE + 164;
/* Enable/Disable WifiConnectivityManager */
static final int CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER = BASE + 166;
@@ -1320,7 +1322,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
/**
* Initiates connection to a network specified by the user/app. This method checks if the
- * requesting app holds the WIFI_CONFIG_OVERRIDE permission.
+ * requesting app holds the NETWORK_SETTINGS permission.
*
* @param netId Id network to initiate connection.
* @param uid UID of the app requesting the connection.
@@ -1349,7 +1351,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
logi("connectToUserSelectNetwork already connecting/connected=" + netId);
} else {
mWifiConnectivityManager.prepareForForcedConnection(netId);
- startConnectToNetwork(netId, SUPPLICANT_BSSID_ANY);
+ startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY);
}
return true;
}
@@ -1755,8 +1757,38 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
*
* @return a {@link WifiInfo} object containing information about the current connection
*/
- public WifiInfo syncRequestConnectionInfo() {
- return getWiFiInfoForUid(Binder.getCallingUid());
+ public WifiInfo syncRequestConnectionInfo(String callingPackage) {
+ int uid = Binder.getCallingUid();
+ WifiInfo result = new WifiInfo(mWifiInfo);
+ if (uid == Process.myUid()) return result;
+ boolean hideBssidAndSsid = true;
+ result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
+
+ IPackageManager packageManager = AppGlobals.getPackageManager();
+
+ try {
+ if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
+ uid) == PackageManager.PERMISSION_GRANTED) {
+ result.setMacAddress(mWifiInfo.getMacAddress());
+ }
+ final WifiConfiguration currentWifiConfiguration = getCurrentWifiConfiguration();
+ if (mWifiPermissionsUtil.canAccessFullConnectionInfo(
+ currentWifiConfiguration,
+ callingPackage,
+ uid,
+ Build.VERSION_CODES.O)) {
+ hideBssidAndSsid = false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error checking receiver permission", e);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Security exception checking receiver permission", e);
+ }
+ if (hideBssidAndSsid) {
+ result.setBSSID(WifiInfo.DEFAULT_MAC_ADDRESS);
+ result.setSSID(WifiSsid.createFromHex(null));
+ }
+ return result;
}
public WifiInfo getWifiInfo() {
@@ -1844,8 +1876,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
/**
* Initiate a reconnection to AP
*/
- public void reconnectCommand() {
- sendMessage(CMD_RECONNECT);
+ public void reconnectCommand(WorkSource workSource) {
+ sendMessage(CMD_RECONNECT, workSource);
}
/**
@@ -1884,9 +1916,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) {
Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid);
- List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
- resultMsg.recycle();
- return result;
+ if (resultMsg == null) { // an error has occurred
+ return null;
+ } else {
+ List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
+ resultMsg.recycle();
+ return result;
+ }
}
public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) {
@@ -2716,7 +2752,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
break;
case CMD_START_RSSI_MONITORING_OFFLOAD:
case CMD_STOP_RSSI_MONITORING_OFFLOAD:
- case CMD_RSSI_THRESHOLD_BREACH:
+ case CMD_RSSI_THRESHOLD_BREACHED:
sb.append(" rssi=");
sb.append(Integer.toString(msg.arg1));
sb.append(" thresholds=");
@@ -2977,13 +3013,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
*/
int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
if (newSignalLevel != mLastSignalLevel) {
- updateCapabilities(getCurrentWifiConfiguration());
+ updateCapabilities();
sendRssiChangeBroadcast(newRssi);
}
mLastSignalLevel = newSignalLevel;
} else {
mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
- updateCapabilities(getCurrentWifiConfiguration());
+ updateCapabilities();
}
if (newLinkSpeed != null) {
@@ -3139,29 +3175,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private WifiInfo getWiFiInfoForUid(int uid) {
- WifiInfo result = new WifiInfo(mWifiInfo);
- if (Binder.getCallingUid() == Process.myUid()) {
- return result;
- }
-
- result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
-
- IBinder binder = mFacade.getService("package");
- IPackageManager packageManager = IPackageManager.Stub.asInterface(binder);
-
- try {
- if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
- uid) == PackageManager.PERMISSION_GRANTED) {
- result.setMacAddress(mWifiInfo.getMacAddress());
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error checking receiver permission", e);
- }
-
- return result;
- }
-
private void sendLinkConfigurationChangedBroadcast() {
Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -3257,12 +3270,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
mWifiInfo.setBSSID(stateChangeResult.BSSID);
-
mWifiInfo.setSSID(stateChangeResult.wifiSsid);
- WifiConfiguration config = getCurrentWifiConfiguration();
+
+ final WifiConfiguration config = getCurrentWifiConfiguration();
if (config != null) {
- // Set meteredHint to true if the access network type of the connecting/connected AP
- // is a chargeable public network.
+ mWifiInfo.setEphemeral(config.ephemeral);
+
+ // Set meteredHint if scan result says network is expensive
ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork(
config.networkId);
if (scanDetailCache != null) {
@@ -3276,15 +3290,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
}
}
-
- mWifiInfo.setEphemeral(config.ephemeral);
- if (!mWifiInfo.getMeteredHint()) { // don't override the value if already set.
- mWifiInfo.setMeteredHint(config.meteredHint);
- }
}
mSupplicantStateTracker.sendMessage(Message.obtain(message));
-
return state;
}
@@ -3424,11 +3432,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
/**
- * Inform other components (WifiMetrics, WifiDiagnostics, etc.) that the current connection attempt
- * has concluded.
+ * Inform other components (WifiMetrics, WifiDiagnostics, WifiConnectivityManager, etc.) that
+ * the current connection attempt has concluded.
*/
private void reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode) {
mWifiMetrics.endConnectionEvent(level2FailureCode, connectivityFailureCode);
+ mWifiConnectivityManager.handleConnectionAttemptEnded(level2FailureCode);
switch (level2FailureCode) {
case WifiMetrics.ConnectionEvent.FAILURE_NONE:
// Ideally, we'd wait until IP reachability has been confirmed. this code falls
@@ -3475,11 +3484,20 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiInfo + " got: " + addr);
}
}
+
mWifiInfo.setInetAddress(addr);
- if (!mWifiInfo.getMeteredHint()) { // don't override the value if already set.
- mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
- updateCapabilities(getCurrentWifiConfiguration());
+
+ final WifiConfiguration config = getCurrentWifiConfiguration();
+ if (config != null) {
+ mWifiInfo.setEphemeral(config.ephemeral);
+ }
+
+ // Set meteredHint if DHCP result says network is metered
+ if (dhcpResults.hasMeteredHint()) {
+ mWifiInfo.setMeteredHint(true);
}
+
+ updateCapabilities(config);
}
private void handleSuccessfulIpConfiguration() {
@@ -3965,9 +3983,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
deleteNetworkConfigAndSendReply(message, true);
break;
case WifiManager.SAVE_NETWORK:
- messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
- replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
- WifiManager.BUSY);
+ saveNetworkConfigAndSendReply(message);
break;
case WifiManager.START_WPS:
replyToMessage(message, WifiManager.WPS_FAILED,
@@ -4103,11 +4119,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
case CMD_CLIENT_INTERFACE_BINDER_DEATH:
Log.e(TAG, "wificond died unexpectedly. Triggering recovery");
mWifiMetrics.incrementNumWificondCrashes();
+ mWifiDiagnostics.captureBugReportData(
+ WifiDiagnostics.REPORT_REASON_WIFICOND_CRASH);
mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFICOND_CRASH);
break;
case CMD_VENDOR_HAL_HWBINDER_DEATH:
Log.e(TAG, "Vendor HAL died unexpectedly. Triggering recovery");
mWifiMetrics.incrementNumHalCrashes();
+ mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_HAL_CRASH);
mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_HAL_CRASH);
break;
case CMD_DIAGS_CONNECT_TIMEOUT:
@@ -4260,10 +4279,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mLastSignalLevel = -1;
mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
- // Attempt to migrate data out of legacy store.
- if (!mWifiConfigManager.migrateFromLegacyStore()) {
- Log.e(TAG, "Failed to migrate from legacy config store");
- }
initializeWpsDetails();
sendSupplicantConnectionChangedBroadcast(true);
transitionTo(mSupplicantStartedState);
@@ -4523,7 +4538,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mEnableAutoJoinWhenAssociated = allowed;
if (!old_state && allowed && mScreenOn
&& getCurrentState() == mConnectedState) {
- mWifiConnectivityManager.forceConnectivityScan();
+ mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
}
break;
case CMD_SELECT_TX_POWER_SCENARIO:
@@ -4810,7 +4825,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
// Notify PasspointManager of Passpoint network connected event.
WifiConfiguration currentNetwork = getCurrentWifiConfiguration();
- if (currentNetwork.isPasspoint()) {
+ if (currentNetwork != null && currentNetwork.isPasspoint()) {
mPasspointManager.onPasspointNetworkConnected(currentNetwork.FQDN);
}
}
@@ -4851,7 +4866,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
return null;
}
- return scanDetailCache.get(BSSID);
+ return scanDetailCache.getScanResult(BSSID);
}
String getCurrentBSSID() {
@@ -4941,8 +4956,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
WifiConfiguration.NetworkSelectionStatus
.DISABLED_ASSOCIATION_REJECTION);
+ mWifiConfigManager.setRecentFailureAssociationStatus(mTargetNetworkId,
+ reasonCode);
mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
- //If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
+ // If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
@@ -4970,6 +4987,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
mWifiConfigManager.updateNetworkSelectionStatus(
mTargetNetworkId, disableReason);
+ mWifiConfigManager.clearRecentFailureReason(mTargetNetworkId);
//If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
@@ -5143,7 +5161,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mPasspointManager.getMatchingOsuProviders((ScanResult) message.obj));
break;
case CMD_RECONNECT:
- mWifiConnectivityManager.forceConnectivityScan();
+ WorkSource workSource = (WorkSource) message.obj;
+ mWifiConnectivityManager.forceConnectivityScan(workSource);
break;
case CMD_REASSOCIATE:
lastConnectAttemptTimestamp = mClock.getWallClockMillis();
@@ -5163,7 +5182,23 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
case CMD_START_CONNECT:
/* connect command coming from auto-join */
netId = message.arg1;
+ int uid = message.arg2;
bssid = (String) message.obj;
+
+ synchronized (mWifiReqCountLock) {
+ if (!hasConnectionRequests()) {
+ if (mNetworkAgent == null) {
+ loge("CMD_START_CONNECT but no requests and not connected,"
+ + " bailing");
+ break;
+ } else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
+ loge("CMD_START_CONNECT but no requests and connected, but app "
+ + "does not have sufficient permissions, bailing");
+ break;
+ }
+ }
+ }
+
config = mWifiConfigManager.getConfiguredNetworkWithPassword(netId);
logd("CMD_START_CONNECT sup state "
+ mSupplicantStateTracker.getSupplicantStateName()
@@ -5253,41 +5288,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
break;
case WifiManager.SAVE_NETWORK:
- config = (WifiConfiguration) message.obj;
- mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
- if (config == null) {
- loge("SAVE_NETWORK with null configuration"
- + mSupplicantStateTracker.getSupplicantStateName()
- + " my state " + getCurrentState().getName());
- messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
- replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
- WifiManager.ERROR);
- break;
- }
- result = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
- if (!result.isSuccess()) {
- loge("SAVE_NETWORK adding/updating config=" + config + " failed");
- messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
- replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
- WifiManager.ERROR);
- break;
- }
- if (!mWifiConfigManager.enableNetwork(
- result.getNetworkId(), false, message.sendingUid)) {
- loge("SAVE_NETWORK enabling config=" + config + " failed");
- messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
- replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
- WifiManager.ERROR);
- break;
- }
+ result = saveNetworkConfigAndSendReply(message);
netId = result.getNetworkId();
- if (mWifiInfo.getNetworkId() == netId) {
+ if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
+ mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
if (result.hasCredentialChanged()) {
+ config = (WifiConfiguration) message.obj;
// The network credentials changed and we're connected to this network,
// start a new connection with the updated credentials.
logi("SAVE_NETWORK credential changed for config=" + config.configKey()
+ ", Reconnecting.");
- startConnectToNetwork(netId, SUPPLICANT_BSSID_ANY);
+ startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
} else {
if (result.hasProxyChanged()) {
log("Reconfiguring proxy on connection");
@@ -5305,8 +5316,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
}
}
- broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
- replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
break;
case WifiManager.FORGET_NETWORK:
if (!deleteNetworkConfigAndSendReply(message, true)) {
@@ -5389,6 +5398,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
case WifiMonitor.NETWORK_CONNECTION_EVENT:
if (mVerboseLoggingEnabled) log("Network connection established");
mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
+ mWifiConfigManager.clearRecentFailureReason(mLastNetworkId);
mLastBssid = (String) message.obj;
reasonCode = message.arg2;
// TODO: This check should not be needed after WifiStateMachinePrime refactor.
@@ -5405,7 +5415,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
if (scanDetailCache != null && mLastBssid != null) {
- ScanResult scanResult = scanDetailCache.get(mLastBssid);
+ ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
if (scanResult != null) {
mWifiInfo.setFrequency(scanResult.frequency);
}
@@ -5493,28 +5503,34 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
}
+ public void updateCapabilities() {
+ updateCapabilities(getCurrentWifiConfiguration());
+ }
+
private void updateCapabilities(WifiConfiguration config) {
- NetworkCapabilities networkCapabilities = new NetworkCapabilities(mDfltNetworkCapabilities);
- if (config != null) {
- if (config.ephemeral) {
- networkCapabilities.removeCapability(
- NetworkCapabilities.NET_CAPABILITY_TRUSTED);
- } else {
- networkCapabilities.addCapability(
- NetworkCapabilities.NET_CAPABILITY_TRUSTED);
- }
+ final NetworkCapabilities result = new NetworkCapabilities(mDfltNetworkCapabilities);
+
+ if (mWifiInfo != null && !mWifiInfo.isEphemeral()) {
+ result.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
+ } else {
+ result.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
+ }
- networkCapabilities.setSignalStrength(
- (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI)
- ? mWifiInfo.getRssi()
- : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
+ if (mWifiInfo != null && !WifiConfiguration.isMetered(config, mWifiInfo)) {
+ result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ } else {
+ result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
}
- if (mWifiInfo.getMeteredHint()) {
- networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ if (mWifiInfo != null && mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI) {
+ result.setSignalStrength(mWifiInfo.getRssi());
+ } else {
+ result.setSignalStrength(NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
}
- mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(result);
+ }
}
/**
@@ -5807,8 +5823,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_NONE,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
- sendConnectedState();
- transitionTo(mConnectedState);
+ if (getCurrentWifiConfiguration() == null) {
+ // The current config may have been removed while we were connecting,
+ // trigger a disconnect to clear up state.
+ mWifiNative.disconnect();
+ transitionTo(mDisconnectingState);
+ } else {
+ sendConnectedState();
+ transitionTo(mConnectedState);
+ }
break;
case CMD_IP_CONFIGURATION_LOST:
// Get Link layer stats so that we get fresh tx packet counters.
@@ -5958,7 +5981,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
ScanDetailCache scanDetailCache = mWifiConfigManager
.getScanDetailCacheForNetwork(config.networkId);
if (scanDetailCache != null) {
- ScanResult scanResult = scanDetailCache.get(mLastBssid);
+ ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
if (scanResult != null) {
mWifiInfo.setFrequency(scanResult.frequency);
}
@@ -5968,13 +5991,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
break;
case CMD_START_RSSI_MONITORING_OFFLOAD:
- case CMD_RSSI_THRESHOLD_BREACH:
+ case CMD_RSSI_THRESHOLD_BREACHED:
byte currRssi = (byte) message.arg1;
processRssiThreshold(currRssi, message.what);
break;
case CMD_STOP_RSSI_MONITORING_OFFLOAD:
stopRssiMonitoringOffload();
break;
+ case CMD_RECONNECT:
+ log(" Ignore CMD_RECONNECT request because wifi is already connected");
+ break;
case CMD_RESET_SIM_NETWORKS:
if (message.arg1 == 0 // sim was removed
&& mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
@@ -6119,7 +6145,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WifiConfiguration config = getCurrentWifiConfiguration();
if (shouldEvaluateWhetherToSendExplicitlySelected(config)) {
boolean prompt =
- mWifiPermissionsUtil.checkConfigOverridePermission(config.lastConnectUid);
+ mWifiPermissionsUtil.checkNetworkSettingsPermission(config.lastConnectUid);
if (mVerboseLoggingEnabled) {
log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
}
@@ -6130,7 +6156,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
if (mVerboseLoggingEnabled) {
log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
}
- mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
+ if (mNetworkAgent != null) {
+ mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
+ }
}
}
@@ -6502,13 +6530,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
dstMac = NativeUtil.macAddressToByteArray(dstMacStr);
} catch (NullPointerException | IllegalArgumentException e) {
loge("Can't find MAC address for next hop to " + pkt.dstAddress);
- mNetworkAgent.onPacketKeepaliveEvent(slot,
- ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
+ if (mNetworkAgent != null) {
+ mNetworkAgent.onPacketKeepaliveEvent(slot,
+ ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
+ }
break;
}
pkt.dstMac = dstMac;
int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
- mNetworkAgent.onPacketKeepaliveEvent(slot, result);
+ if (mNetworkAgent != null) {
+ mNetworkAgent.onPacketKeepaliveEvent(slot, result);
+ }
break;
}
default:
@@ -6761,7 +6793,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
// Ignore intermediate success, wait for full connection
break;
case WifiMonitor.NETWORK_CONNECTION_EVENT:
- if (loadNetworksFromSupplicantAfterWps()) {
+ Pair<Boolean, Integer> loadResult = loadNetworksFromSupplicantAfterWps();
+ boolean success = loadResult.first;
+ int netId = loadResult.second;
+ if (success) {
+ message.arg1 = netId;
replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
} else {
replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
@@ -6818,6 +6854,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
case WifiManager.CONNECT_NETWORK:
case CMD_ENABLE_NETWORK:
case CMD_RECONNECT:
+ log(" Ignore CMD_RECONNECT request because wps is running");
+ return HANDLED;
case CMD_REASSOCIATE:
deferMessage(message);
break;
@@ -6857,13 +6895,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
/**
* Load network config from wpa_supplicant after WPS is complete.
+ * @return a boolean (true if load was successful) and integer (Network Id of currently
+ * connected network, can be {@link WifiConfiguration#INVALID_NETWORK_ID} despite
+ * successful loading, if multiple networks in supplicant) pair.
*/
- private boolean loadNetworksFromSupplicantAfterWps() {
+ private Pair<Boolean, Integer> loadNetworksFromSupplicantAfterWps() {
Map<String, WifiConfiguration> configs = new HashMap<>();
SparseArray<Map<String, String>> extras = new SparseArray<>();
+ int netId = WifiConfiguration.INVALID_NETWORK_ID;
if (!mWifiNative.migrateNetworksFromSupplicant(configs, extras)) {
loge("Failed to load networks from wpa_supplicant after Wps");
- return false;
+ return Pair.create(false, WifiConfiguration.INVALID_NETWORK_ID);
}
for (Map.Entry<String, WifiConfiguration> entry : configs.entrySet()) {
WifiConfiguration config = entry.getValue();
@@ -6874,15 +6916,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
config, mSourceMessage.sendingUid);
if (!result.isSuccess()) {
loge("Failed to add network after WPS: " + entry.getValue());
- return false;
+ return Pair.create(false, WifiConfiguration.INVALID_NETWORK_ID);
}
if (!mWifiConfigManager.enableNetwork(
result.getNetworkId(), true, mSourceMessage.sendingUid)) {
- loge("Failed to enable network after WPS: " + entry.getValue());
- return false;
+ Log.wtf(TAG, "Failed to enable network after WPS: " + entry.getValue());
+ return Pair.create(false, WifiConfiguration.INVALID_NETWORK_ID);
}
+ netId = result.getNetworkId();
}
- return true;
+ return Pair.create(true,
+ configs.size() == 1 ? netId : WifiConfiguration.INVALID_NETWORK_ID);
}
}
@@ -7079,14 +7123,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
* Automatically connect to the network specified
*
* @param networkId ID of the network to connect to
+ * @param uid UID of the app triggering the connection.
* @param bssid BSSID of the network
*/
- public void startConnectToNetwork(int networkId, String bssid) {
- synchronized (mWifiReqCountLock) {
- if (hasConnectionRequests()) {
- sendMessage(CMD_START_CONNECT, networkId, 0, bssid);
- }
- }
+ public void startConnectToNetwork(int networkId, int uid, String bssid) {
+ sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
}
/**
@@ -7171,6 +7212,43 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
}
+ /**
+ * Private method to handle calling WifiConfigManager to add & enable network configs and reply
+ * to the message from the sender of the outcome.
+ *
+ * @return NetworkUpdateResult with networkId of the added/updated configuration. Will return
+ * {@link WifiConfiguration#INVALID_NETWORK_ID} in case of error.
+ */
+ private NetworkUpdateResult saveNetworkConfigAndSendReply(Message message) {
+ WifiConfiguration config = (WifiConfiguration) message.obj;
+ if (config == null) {
+ loge("SAVE_NETWORK with null configuration "
+ + mSupplicantStateTracker.getSupplicantStateName()
+ + " my state " + getCurrentState().getName());
+ messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
+ replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
+ return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
+ }
+ NetworkUpdateResult result =
+ mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
+ if (!result.isSuccess()) {
+ loge("SAVE_NETWORK adding/updating config=" + config + " failed");
+ messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
+ replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
+ return result;
+ }
+ if (!mWifiConfigManager.enableNetwork(
+ result.getNetworkId(), false, message.sendingUid)) {
+ loge("SAVE_NETWORK enabling config=" + config + " failed");
+ messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
+ replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
+ return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
+ }
+ broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
+ replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
+ return result;
+ }
+
private static String getLinkPropertiesSummary(LinkProperties lp) {
List<String> attributes = new ArrayList<>(6);
if (lp.hasIPv4Address()) {
diff --git a/service/java/com/android/server/wifi/WificondControl.java b/service/java/com/android/server/wifi/WificondControl.java
index a877c092d..b6104a8cd 100644
--- a/service/java/com/android/server/wifi/WificondControl.java
+++ b/service/java/com/android/server/wifi/WificondControl.java
@@ -32,6 +32,7 @@ import android.util.Log;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.util.InformationElementUtil;
import com.android.server.wifi.util.NativeUtil;
+import com.android.server.wifi.util.ScanResultUtil;
import com.android.server.wifi.wificond.ChannelSettings;
import com.android.server.wifi.wificond.HiddenNetwork;
import com.android.server.wifi.wificond.NativeScanResult;
@@ -50,8 +51,16 @@ public class WificondControl {
private boolean mVerboseLoggingEnabled = false;
private static final String TAG = "WificondControl";
+
+ /* Get scan results for a single scan */
+ public static final int SCAN_TYPE_SINGLE_SCAN = 0;
+
+ /* Get scan results for Pno Scan */
+ public static final int SCAN_TYPE_PNO_SCAN = 1;
+
private WifiInjector mWifiInjector;
private WifiMonitor mWifiMonitor;
+ private final CarrierNetworkConfig mCarrierNetworkConfig;
// Cached wificond binder handlers.
private IWificond mWificond;
@@ -78,9 +87,11 @@ public class WificondControl {
}
}
- WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor) {
+ WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor,
+ CarrierNetworkConfig carrierNetworkConfig) {
mWifiInjector = wifiInjector;
mWifiMonitor = wifiMonitor;
+ mCarrierNetworkConfig = carrierNetworkConfig;
}
private class PnoScanEventHandler extends IPnoScanEvent.Stub {
@@ -88,12 +99,25 @@ public class WificondControl {
public void OnPnoNetworkFound() {
Log.d(TAG, "Pno scan result event");
mWifiMonitor.broadcastPnoScanResultEvent(mClientInterfaceName);
+ mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount();
}
@Override
public void OnPnoScanFailed() {
Log.d(TAG, "Pno Scan failed event");
- // Nothing to do for now.
+ mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount();
+ }
+
+ @Override
+ public void OnPnoScanOverOffloadStarted() {
+ Log.d(TAG, "Pno scan over offload started");
+ mWifiInjector.getWifiMetrics().incrementPnoScanStartedOverOffloadCount();
+ }
+
+ @Override
+ public void OnPnoScanOverOffloadFailed(int reason) {
+ Log.d(TAG, "Pno scan over offload failed");
+ mWifiInjector.getWifiMetrics().incrementPnoScanFailedOverOffloadCount();
}
}
@@ -318,14 +342,19 @@ public class WificondControl {
* @return Returns an ArrayList of ScanDetail.
* Returns an empty ArrayList on failure.
*/
- public ArrayList<ScanDetail> getScanResults() {
+ public ArrayList<ScanDetail> getScanResults(int scanType) {
ArrayList<ScanDetail> results = new ArrayList<>();
if (mWificondScanner == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return results;
}
try {
- NativeScanResult[] nativeResults = mWificondScanner.getScanResults();
+ NativeScanResult[] nativeResults;
+ if (scanType == SCAN_TYPE_SINGLE_SCAN) {
+ nativeResults = mWificondScanner.getScanResults();
+ } else {
+ nativeResults = mWificondScanner.getPnoScanResults();
+ }
for (NativeScanResult result : nativeResults) {
WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
String bssid;
@@ -345,15 +374,26 @@ public class WificondControl {
new InformationElementUtil.Capabilities();
capabilities.from(ies, result.capability);
String flags = capabilities.generateCapabilitiesString();
- NetworkDetail networkDetail =
- new NetworkDetail(bssid, ies, null, result.frequency);
-
- if (!wifiSsid.toString().equals(networkDetail.getTrimmedSSID())) {
- Log.e(TAG, "Inconsistent SSID on BSSID: " + bssid);
+ NetworkDetail networkDetail;
+ try {
+ networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
continue;
}
+
ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
result.signalMbm / 100, result.frequency, result.tsf, ies, null);
+ // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi
+ // network and it uses EAP.
+ if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult())
+ && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) {
+ scanDetail.getScanResult().isCarrierAp = true;
+ scanDetail.getScanResult().carrierApEapType =
+ mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString());
+ scanDetail.getScanResult().carrierName =
+ mCarrierNetworkConfig.getCarrierName(wifiSsid.toString());
+ }
results.add(scanDetail);
}
} catch (RemoteException e1) {
@@ -441,9 +481,14 @@ public class WificondControl {
}
try {
- return mWificondScanner.startPnoScan(settings);
+ boolean success = mWificondScanner.startPnoScan(settings);
+ mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount();
+ if (!success) {
+ mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount();
+ }
+ return success;
} catch (RemoteException e1) {
- Log.e(TAG, "Failed to stop pno scan due to remote exception");
+ Log.e(TAG, "Failed to start pno scan due to remote exception");
}
return false;
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
index 04bf2e009..efeca655b 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
@@ -33,6 +33,7 @@ import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.RouteInfo;
+import android.net.wifi.aware.WifiAwareAgentNetworkSpecifier;
import android.net.wifi.aware.WifiAwareManager;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
import android.net.wifi.aware.WifiAwareUtils;
@@ -59,9 +60,11 @@ import java.net.SocketException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* Manages Aware data-path lifetime: interface creation/deletion, data-path setup and tear-down.
@@ -85,8 +88,8 @@ public class WifiAwareDataPathStateManager {
private static final int NETWORK_FACTORY_SIGNAL_STRENGTH_AVAIL = 1;
private final WifiAwareStateManager mMgr;
- private final NetworkInterfaceWrapper mNiWrapper = new NetworkInterfaceWrapper();
- private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
+ public NetworkInterfaceWrapper mNiWrapper = new NetworkInterfaceWrapper();
+ private static final NetworkCapabilities sNetworkCapabilitiesFilter = new NetworkCapabilities();
private final Set<String> mInterfaces = new HashSet<>();
private final Map<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation>
mNetworkRequestsCache = new ArrayMap<>();
@@ -95,7 +98,7 @@ public class WifiAwareDataPathStateManager {
private WifiPermissionsWrapper mPermissionsWrapper;
private Looper mLooper;
private WifiAwareNetworkFactory mNetworkFactory;
- private INetworkManagementService mNwService;
+ public INetworkManagementService mNwService;
public WifiAwareDataPathStateManager(WifiAwareStateManager mgr) {
mMgr = mgr;
@@ -114,19 +117,19 @@ public class WifiAwareDataPathStateManager {
mPermissionsWrapper = permissionsWrapper;
mLooper = looper;
- mNetworkCapabilitiesFilter.clearAll();
- mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
- mNetworkCapabilitiesFilter
+ sNetworkCapabilitiesFilter.clearAll();
+ sNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
+ sNetworkCapabilitiesFilter
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
- mNetworkCapabilitiesFilter.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
- mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
- mNetworkCapabilitiesFilter.setSignalStrength(NETWORK_FACTORY_SIGNAL_STRENGTH_AVAIL);
+ sNetworkCapabilitiesFilter.setNetworkSpecifier(new MatchAllNetworkSpecifier());
+ sNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
+ sNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(NETWORK_FACTORY_BANDWIDTH_AVAIL);
+ sNetworkCapabilitiesFilter.setSignalStrength(NETWORK_FACTORY_SIGNAL_STRENGTH_AVAIL);
- mNetworkFactory = new WifiAwareNetworkFactory(looper, context, mNetworkCapabilitiesFilter);
+ mNetworkFactory = new WifiAwareNetworkFactory(looper, context, sNetworkCapabilitiesFilter);
mNetworkFactory.setScoreFilter(NETWORK_FACTORY_SCORE_AVAIL);
mNetworkFactory.register();
@@ -146,6 +149,18 @@ public class WifiAwareDataPathStateManager {
return null;
}
+ private Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation>
+ getNetworkRequestByCanonicalDescriptor(CanonicalConnectionInfo cci) {
+ for (Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation> entry :
+ mNetworkRequestsCache.entrySet()) {
+ if (entry.getValue().getCanonicalDescriptor().equals(cci)) {
+ return entry;
+ }
+ }
+
+ return null;
+ }
+
/**
* Create all Aware data-path interfaces which are possible on the device - based on the
* capabilities of the firmware.
@@ -247,7 +262,7 @@ public class WifiAwareDataPathStateManager {
return;
}
- nnri.state = AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_CONFIRM;
+ nnri.state = AwareNetworkRequestInformation.STATE_WAIT_FOR_CONFIRM;
nnri.ndpId = ndpId;
}
@@ -309,6 +324,8 @@ public class WifiAwareDataPathStateManager {
* - The discovery session (pub/sub ID) must match.
* - The peer MAC address (if specified - i.e. non-null) must match. A null peer MAC ==
* accept (otherwise matching) requests from any peer MAC.
+ * - The request must be pending (i.e. we could have completed requests for the same
+ * parameters)
*/
if (entry.getValue().pubSubId != 0 && entry.getValue().pubSubId != pubSubId) {
continue;
@@ -319,6 +336,11 @@ public class WifiAwareDataPathStateManager {
continue;
}
+ if (entry.getValue().state
+ != AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_REQUEST) {
+ continue;
+ }
+
networkSpecifier = entry.getKey();
nnri = entry.getValue();
break;
@@ -411,7 +433,7 @@ public class WifiAwareDataPathStateManager {
return;
}
- nnri.state = AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_CONFIRM;
+ nnri.state = AwareNetworkRequestInformation.STATE_WAIT_FOR_CONFIRM;
}
/**
@@ -452,18 +474,8 @@ public class WifiAwareDataPathStateManager {
AwareNetworkRequestInformation nnri = nnriE.getValue();
// validate state
- if (nnri.networkSpecifier.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
- && nnri.state != AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_CONFIRM) {
- Log.w(TAG, "onDataPathConfirm: INITIATOR in invalid state=" + nnri.state);
- mNetworkRequestsCache.remove(networkSpecifier);
- if (accept) {
- mMgr.endDataPath(ndpId);
- }
- return networkSpecifier;
- }
- if (nnri.networkSpecifier.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
- && nnri.state != AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_CONFIRM) {
- Log.w(TAG, "onDataPathConfirm: RESPONDER in invalid state=" + nnri.state);
+ if (nnri.state != AwareNetworkRequestInformation.STATE_WAIT_FOR_CONFIRM) {
+ Log.w(TAG, "onDataPathConfirm: invalid state=" + nnri.state);
mNetworkRequestsCache.remove(networkSpecifier);
if (accept) {
mMgr.endDataPath(ndpId);
@@ -472,38 +484,45 @@ public class WifiAwareDataPathStateManager {
}
if (accept) {
- nnri.state = (nnri.networkSpecifier.role
- == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)
- ? AwareNetworkRequestInformation.STATE_INITIATOR_CONFIRMED
- : AwareNetworkRequestInformation.STATE_RESPONDER_CONFIRMED;
+ nnri.state = AwareNetworkRequestInformation.STATE_CONFIRMED;
nnri.peerDataMac = mac;
- NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0,
+ NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_NONE, 0,
NETWORK_TAG, "");
NetworkCapabilities networkCapabilities = new NetworkCapabilities(
- mNetworkCapabilitiesFilter);
+ sNetworkCapabilitiesFilter);
LinkProperties linkProperties = new LinkProperties();
- try {
- mNwService.setInterfaceUp(nnri.interfaceName);
- mNwService.enableIpv6(nnri.interfaceName);
- } catch (Exception e) { // NwService throws runtime exceptions for errors
- Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri + ": can't configure network - "
- + e);
- mMgr.endDataPath(ndpId);
- return networkSpecifier;
+ boolean interfaceUsedByAnotherNdp = isInterfaceUpAndUsedByAnotherNdp(nnri);
+ if (!interfaceUsedByAnotherNdp) {
+ try {
+ mNwService.setInterfaceUp(nnri.interfaceName);
+ mNwService.enableIpv6(nnri.interfaceName);
+ } catch (Exception e) { // NwService throws runtime exceptions for errors
+ Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
+ + ": can't configure network - "
+ + e);
+ mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
+ return networkSpecifier;
+ }
+ } else {
+ if (VDBG) {
+ Log.v(TAG, "onDataPathConfirm: interface already configured: "
+ + nnri.interfaceName);
+ }
}
- if (!mNiWrapper.configureAgentProperties(nnri, networkSpecifier, ndpId, networkInfo,
- networkCapabilities, linkProperties)) {
+ if (!mNiWrapper.configureAgentProperties(nnri, nnri.equivalentSpecifiers, ndpId,
+ networkInfo, networkCapabilities, linkProperties)) {
return networkSpecifier;
}
nnri.networkAgent = new WifiAwareNetworkAgent(mLooper, mContext,
AGENT_TAG_PREFIX + nnri.ndpId,
- new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORK_TAG, ""),
+ new NetworkInfo(ConnectivityManager.TYPE_NONE, 0, NETWORK_TAG, ""),
networkCapabilities, linkProperties, NETWORK_FACTORY_SCORE_AVAIL,
- networkSpecifier, ndpId);
+ nnri);
nnri.networkAgent.sendNetworkInfo(networkInfo);
mAwareMetrics.recordNdpStatus(NanStatusType.SUCCESS, networkSpecifier.isOutOfBand(),
@@ -541,13 +560,14 @@ public class WifiAwareDataPathStateManager {
return;
}
- tearDownInterface(nnriE.getValue());
- if (nnriE.getValue().state == AwareNetworkRequestInformation.STATE_RESPONDER_CONFIRMED
- || nnriE.getValue().state
- == AwareNetworkRequestInformation.STATE_INITIATOR_CONFIRMED) {
+ tearDownInterfaceIfPossible(nnriE.getValue());
+ if (nnriE.getValue().state == AwareNetworkRequestInformation.STATE_CONFIRMED
+ || nnriE.getValue().state == AwareNetworkRequestInformation.STATE_TERMINATING) {
mAwareMetrics.recordNdpSessionDuration(nnriE.getValue().startTimestamp);
}
mNetworkRequestsCache.remove(nnriE.getKey());
+
+ mNetworkFactory.tickleConnectivityIfWaiting();
}
/**
@@ -557,7 +577,7 @@ public class WifiAwareDataPathStateManager {
if (VDBG) Log.v(TAG, "onAwareDownCleanupDataPaths");
for (AwareNetworkRequestInformation nnri : mNetworkRequestsCache.values()) {
- tearDownInterface(nnri);
+ tearDownInterfaceIfPossible(nnri);
}
mNetworkRequestsCache.clear();
}
@@ -584,13 +604,26 @@ public class WifiAwareDataPathStateManager {
nnri.networkSpecifier.isOutOfBand(), nnri.startTimestamp);
mMgr.endDataPath(nnri.ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
}
private class WifiAwareNetworkFactory extends NetworkFactory {
+ // Request received while waiting for confirmation that a canonically identical data-path
+ // (NDP) is in the process of being terminated
+ private boolean mWaitingForTermination = false;
+
WifiAwareNetworkFactory(Looper looper, Context context, NetworkCapabilities filter) {
super(looper, context, NETWORK_TAG, filter);
}
+ public void tickleConnectivityIfWaiting() {
+ if (mWaitingForTermination) {
+ if (VDBG) Log.v(TAG, "tickleConnectivityIfWaiting: was waiting!");
+ mWaitingForTermination = false;
+ reevaluateAllRequests();
+ }
+ }
+
@Override
public boolean acceptRequest(NetworkRequest request, int score) {
if (VDBG) {
@@ -628,7 +661,12 @@ public class WifiAwareDataPathStateManager {
if (nnri != null) {
if (DBG) {
Log.d(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
- + " - already in cache!?");
+ + " - already in cache with state=" + nnri.state);
+ }
+
+ if (nnri.state == AwareNetworkRequestInformation.STATE_TERMINATING) {
+ mWaitingForTermination = true;
+ return false;
}
// seems to happen after a network agent is created - trying to rematch all
@@ -644,10 +682,22 @@ public class WifiAwareDataPathStateManager {
return false;
}
- // TODO (b/63635780) support more then a single concurrent NDP
- if (mNetworkRequestsCache.size() > 0) {
- Log.e(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
- + " - >1 concurrent NDPs aren't supported (yet).");
+ // check to see if a canonical version exists
+ Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation> primaryRequest =
+ getNetworkRequestByCanonicalDescriptor(nnri.getCanonicalDescriptor());
+ if (primaryRequest != null) {
+ if (VDBG) {
+ Log.v(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
+ + ", already has a primary request=" + primaryRequest.getKey()
+ + " with state=" + primaryRequest.getValue().state);
+ }
+
+ if (primaryRequest.getValue().state
+ == AwareNetworkRequestInformation.STATE_TERMINATING) {
+ mWaitingForTermination = true;
+ } else {
+ primaryRequest.getValue().updateToSupportNewRequest(networkSpecifier);
+ }
return false;
}
@@ -676,18 +726,17 @@ public class WifiAwareDataPathStateManager {
return;
}
+ if (nnri.state != AwareNetworkRequestInformation.STATE_IDLE) {
+ if (DBG) {
+ Log.d(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
+ + networkRequest + " - already in progress");
+ // TODO: understand how/when can be called again/while in progress (seems
+ // to be related to score re-calculation after a network agent is created)
+ }
+ return;
+ }
if (nnri.networkSpecifier.role
== WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (nnri.state != AwareNetworkRequestInformation.STATE_INITIATOR_IDLE) {
- if (DBG) {
- Log.d(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
- + networkRequest + " - already in progress");
- // TODO: understand how/when can be called again/while in progress (seems
- // to be related to score re-calculation after a network agent is created)
- }
- return;
- }
-
nnri.interfaceName = selectInterfaceForRequest(nnri);
if (nnri.interfaceName == null) {
Log.w(TAG, "needNetworkFor: request " + networkSpecifier
@@ -704,16 +753,6 @@ public class WifiAwareDataPathStateManager {
AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE;
nnri.startTimestamp = SystemClock.elapsedRealtime();
} else {
- if (nnri.state != AwareNetworkRequestInformation.STATE_RESPONDER_IDLE) {
- if (DBG) {
- Log.d(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
- + networkRequest + " - already in progress");
- // TODO: understand how/when can be called again/while in progress (seems
- // to be related to score re-calculation after a network agent is created)
- }
- return;
- }
-
nnri.state = AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_REQUEST;
}
}
@@ -749,45 +788,52 @@ public class WifiAwareDataPathStateManager {
return;
}
- if (nnri.networkSpecifier.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
- && nnri.state
- > AwareNetworkRequestInformation.STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE) {
- mMgr.endDataPath(nnri.ndpId);
- }
- if (nnri.networkSpecifier.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER
- && nnri.state
- > AwareNetworkRequestInformation.STATE_RESPONDER_WAIT_FOR_REQUEST) {
- mMgr.endDataPath(nnri.ndpId);
+ /*
+ * Since there's no agent it means we're in the process of setting up the NDP.
+ * However, it is possible that there were other equivalent requests for this NDP. We
+ * should keep going in that case.
+ */
+ nnri.removeSupportForRequest(networkSpecifier);
+ if (nnri.equivalentSpecifiers.isEmpty()) {
+ if (VDBG) {
+ Log.v(TAG, "releaseNetworkFor: there are no further requests, networkRequest="
+ + networkRequest);
+ }
+ if (nnri.ndpId != 0) { // 0 is never a valid ID!
+ if (VDBG) Log.v(TAG, "releaseNetworkFor: in progress NDP being terminated");
+ mMgr.endDataPath(nnri.ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
+ }
+ } else {
+ if (VDBG) {
+ Log.v(TAG, "releaseNetworkFor: equivalent requests exist - not terminating "
+ + "networkRequest=" + networkRequest);
+ }
}
-
- // Will get a callback (on both initiator and responder) when data-path actually
- // terminated. At that point will inform the agent and will clear the cache.
}
}
private class WifiAwareNetworkAgent extends NetworkAgent {
private NetworkInfo mNetworkInfo;
- private WifiAwareNetworkSpecifier mNetworkSpecifier;
- private int mNdpId;
+ private AwareNetworkRequestInformation mAwareNetworkRequestInfo;
WifiAwareNetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score,
- WifiAwareNetworkSpecifier networkSpecifier, int ndpId) {
+ AwareNetworkRequestInformation anri) {
super(looper, context, logTag, ni, nc, lp, score);
mNetworkInfo = ni;
- mNetworkSpecifier = networkSpecifier;
- mNdpId = ndpId;
+ mAwareNetworkRequestInfo = anri;
}
@Override
protected void unwanted() {
if (VDBG) {
- Log.v(TAG, "WifiAwareNetworkAgent.unwanted: networkSpecifier=" + mNetworkSpecifier
- + ", ndpId=" + mNdpId);
+ Log.v(TAG, "WifiAwareNetworkAgent.unwanted: request=" + mAwareNetworkRequestInfo);
}
- mMgr.endDataPath(mNdpId);
+ mMgr.endDataPath(mAwareNetworkRequestInfo.ndpId);
+ mAwareNetworkRequestInfo.state = AwareNetworkRequestInformation.STATE_TERMINATING;
// Will get a callback (on both initiator and responder) when data-path actually
// terminated. At that point will inform the agent and will clear the cache.
@@ -795,8 +841,8 @@ public class WifiAwareDataPathStateManager {
void reconfigureAgentAsDisconnected() {
if (VDBG) {
- Log.v(TAG, "WifiAwareNetworkAgent.reconfigureAgentAsDisconnected: networkSpecifier="
- + mNetworkSpecifier + ", ndpId=" + mNdpId);
+ Log.v(TAG, "WifiAwareNetworkAgent.reconfigureAgentAsDisconnected: request="
+ + mAwareNetworkRequestInfo);
}
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, "");
@@ -804,15 +850,23 @@ public class WifiAwareDataPathStateManager {
}
}
- private void tearDownInterface(AwareNetworkRequestInformation nnri) {
- if (VDBG) Log.v(TAG, "tearDownInterface: nnri=" + nnri);
+ private void tearDownInterfaceIfPossible(AwareNetworkRequestInformation nnri) {
+ if (VDBG) Log.v(TAG, "tearDownInterfaceIfPossible: nnri=" + nnri);
- if (nnri.interfaceName != null && !nnri.interfaceName.isEmpty()) {
- try {
- mNwService.setInterfaceDown(nnri.interfaceName);
- } catch (Exception e) { // NwService throws runtime exceptions for errors
- Log.e(TAG,
- "tearDownInterface: nnri=" + nnri + ": can't bring interface down - " + e);
+ if (!TextUtils.isEmpty(nnri.interfaceName)) {
+ boolean interfaceUsedByAnotherNdp = isInterfaceUpAndUsedByAnotherNdp(nnri);
+ if (interfaceUsedByAnotherNdp) {
+ if (VDBG) {
+ Log.v(TAG, "tearDownInterfaceIfPossible: interfaceName=" + nnri.interfaceName
+ + ", still in use - not turning down");
+ }
+ } else {
+ try {
+ mNwService.setInterfaceDown(nnri.interfaceName);
+ } catch (Exception e) { // NwService throws runtime exceptions for errors
+ Log.e(TAG, "tearDownInterfaceIfPossible: nnri=" + nnri
+ + ": can't bring interface down - " + e);
+ }
}
}
@@ -821,19 +875,60 @@ public class WifiAwareDataPathStateManager {
}
}
+ private boolean isInterfaceUpAndUsedByAnotherNdp(AwareNetworkRequestInformation nri) {
+ for (AwareNetworkRequestInformation lnri : mNetworkRequestsCache.values()) {
+ if (lnri == nri) {
+ continue;
+ }
+
+ if (nri.interfaceName.equals(lnri.interfaceName) && (
+ lnri.state == AwareNetworkRequestInformation.STATE_CONFIRMED
+ || lnri.state == AwareNetworkRequestInformation.STATE_TERMINATING)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
- * Select one of the existing interfaces for the new network request.
+ * Select one of the existing interfaces for the new network request. A request is canonical
+ * (otherwise it wouldn't be executed).
*
- * TODO: for now there is only a single interface - simply pick it.
+ * Construct a list of all interfaces currently used to communicate to the peer. The remaining
+ * interfaces are available for use for this request - if none are left then the request should
+ * fail (signaled to the caller by returning a null).
*/
private String selectInterfaceForRequest(AwareNetworkRequestInformation req) {
- Iterator<String> it = mInterfaces.iterator();
- if (it.hasNext()) {
- return it.next();
+ SortedSet<String> potential = new TreeSet<>(mInterfaces);
+ Set<String> used = new HashSet<>();
+
+ if (VDBG) {
+ Log.v(TAG, "selectInterfaceForRequest: req=" + req + ", mNetworkRequestsCache="
+ + mNetworkRequestsCache);
+ }
+
+ for (AwareNetworkRequestInformation nnri : mNetworkRequestsCache.values()) {
+ if (nnri == req) {
+ continue;
+ }
+
+ if (Arrays.equals(req.peerDiscoveryMac, nnri.peerDiscoveryMac)) {
+ used.add(nnri.interfaceName);
+ }
}
- Log.e(TAG, "selectInterfaceForRequest: req=" + req + " - but no interfaces available!");
+ if (VDBG) {
+ Log.v(TAG, "selectInterfaceForRequest: potential=" + potential + ", used=" + used);
+ }
+ for (String ifName: potential) {
+ if (!used.contains(ifName)) {
+ return ifName;
+ }
+ }
+
+ Log.e(TAG, "selectInterfaceForRequest: req=" + req + " - no interfaces available!");
return null;
}
@@ -853,16 +948,13 @@ public class WifiAwareDataPathStateManager {
*/
@VisibleForTesting
public static class AwareNetworkRequestInformation {
- static final int STATE_INITIATOR_IDLE = 100;
- static final int STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE = 101;
- static final int STATE_INITIATOR_WAIT_FOR_CONFIRM = 102;
- static final int STATE_INITIATOR_CONFIRMED = 103;
-
- static final int STATE_RESPONDER_IDLE = 200;
- static final int STATE_RESPONDER_WAIT_FOR_REQUEST = 201;
- static final int STATE_RESPONDER_WAIT_FOR_RESPOND_RESPONSE = 202;
- static final int STATE_RESPONDER_WAIT_FOR_CONFIRM = 203;
- static final int STATE_RESPONDER_CONFIRMED = 204;
+ static final int STATE_IDLE = 100;
+ static final int STATE_WAIT_FOR_CONFIRM = 101;
+ static final int STATE_CONFIRMED = 102;
+ static final int STATE_INITIATOR_WAIT_FOR_REQUEST_RESPONSE = 103;
+ static final int STATE_RESPONDER_WAIT_FOR_REQUEST = 104;
+ static final int STATE_RESPONDER_WAIT_FOR_RESPOND_RESPONSE = 105;
+ static final int STATE_TERMINATING = 106;
public int state;
@@ -871,13 +963,55 @@ public class WifiAwareDataPathStateManager {
public int pubSubId = 0;
public int peerInstanceId = 0;
public byte[] peerDiscoveryMac = null;
- public int ndpId;
+ public int ndpId = 0; // 0 is never a valid ID!
public byte[] peerDataMac;
public WifiAwareNetworkSpecifier networkSpecifier;
public long startTimestamp = 0; // request is made (initiator) / get request (responder)
public WifiAwareNetworkAgent networkAgent;
+ /* A collection of specifiers which are equivalent to the current request and are
+ * supported by it's agent. This list DOES include the original (first) network specifier
+ * (which is stored separately above).
+ */
+ public Set<WifiAwareNetworkSpecifier> equivalentSpecifiers = new HashSet<>();
+
+ void updateToSupportNewRequest(WifiAwareNetworkSpecifier ns) {
+ if (VDBG) Log.v(TAG, "updateToSupportNewRequest: ns=" + ns);
+ if (equivalentSpecifiers.add(ns) && state == STATE_CONFIRMED) {
+ if (networkAgent == null) {
+ Log.wtf(TAG, "updateToSupportNewRequest: null agent in CONFIRMED state!?");
+ return;
+ }
+
+ networkAgent.sendNetworkCapabilities(getNetworkCapabilities());
+ }
+ }
+
+ void removeSupportForRequest(WifiAwareNetworkSpecifier ns) {
+ if (VDBG) Log.v(TAG, "removeSupportForRequest: ns=" + ns);
+ equivalentSpecifiers.remove(ns);
+
+ // we will not update the agent:
+ // 1. this will only get called before the agent is created
+ // 2. connectivity service does not allow (WTF) updates with reduced capabilities
+ }
+
+ private NetworkCapabilities getNetworkCapabilities() {
+ NetworkCapabilities nc = new NetworkCapabilities(sNetworkCapabilitiesFilter);
+ nc.setNetworkSpecifier(new WifiAwareAgentNetworkSpecifier(equivalentSpecifiers.toArray(
+ new WifiAwareNetworkSpecifier[equivalentSpecifiers.size()])));
+ return nc;
+ }
+
+ /**
+ * Returns a canonical descriptor for the network request.
+ */
+ CanonicalConnectionInfo getCanonicalDescriptor() {
+ return new CanonicalConnectionInfo(peerDiscoveryMac, networkSpecifier.pmk,
+ networkSpecifier.sessionId, networkSpecifier.passphrase);
+ }
+
static AwareNetworkRequestInformation processNetworkSpecifier(WifiAwareNetworkSpecifier ns,
WifiAwareStateManager mgr, WifiPermissionsWrapper permissionWrapper) {
int uid, pubSubId = 0;
@@ -1001,14 +1135,13 @@ public class WifiAwareDataPathStateManager {
// create container and populate
AwareNetworkRequestInformation nnri = new AwareNetworkRequestInformation();
- nnri.state = (ns.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)
- ? AwareNetworkRequestInformation.STATE_INITIATOR_IDLE
- : AwareNetworkRequestInformation.STATE_RESPONDER_IDLE;
+ nnri.state = AwareNetworkRequestInformation.STATE_IDLE;
nnri.uid = uid;
nnri.pubSubId = pubSubId;
nnri.peerInstanceId = peerInstanceId;
nnri.peerDiscoveryMac = peerMac;
nnri.networkSpecifier = ns;
+ nnri.equivalentSpecifiers.add(ns);
return nnri;
}
@@ -1025,7 +1158,69 @@ public class WifiAwareDataPathStateManager {
", ndpId=").append(ndpId).append(", peerDataMac=").append(
peerDataMac == null ? ""
: String.valueOf(HexEncoding.encode(peerDataMac))).append(
- ", startTimestamp=").append(startTimestamp);
+ ", startTimestamp=").append(startTimestamp).append(", equivalentSpecifiers=[");
+ for (WifiAwareNetworkSpecifier ns: equivalentSpecifiers) {
+ sb.append(ns.toString()).append(", ");
+ }
+ return sb.append("]").toString();
+ }
+ }
+
+ /**
+ * A canonical (unique) descriptor of the peer connection.
+ */
+ static class CanonicalConnectionInfo {
+ CanonicalConnectionInfo(byte[] peerDiscoveryMac, byte[] pmk, int sessionId,
+ String passphrase) {
+ this.peerDiscoveryMac = peerDiscoveryMac;
+ this.pmk = pmk;
+ this.sessionId = sessionId;
+ this.passphrase = passphrase;
+ }
+
+ public final byte[] peerDiscoveryMac;
+
+ /*
+ * Security configuration matching:
+ * - open: pmk/passphrase = null
+ * - pmk: pmk != null, passphrase = null
+ * - passphrase: passphrase != null, sessionId used (==0 for OOB), pmk=null
+ */
+ public final byte[] pmk;
+
+ public final int sessionId;
+ public final String passphrase;
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(Arrays.hashCode(peerDiscoveryMac), Arrays.hashCode(pmk), sessionId,
+ passphrase);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof CanonicalConnectionInfo)) {
+ return false;
+ }
+
+ CanonicalConnectionInfo lhs = (CanonicalConnectionInfo) obj;
+
+ return Arrays.equals(peerDiscoveryMac, lhs.peerDiscoveryMac) && Arrays.equals(pmk,
+ lhs.pmk) && TextUtils.equals(passphrase, lhs.passphrase)
+ && sessionId == lhs.sessionId;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("CanonicalConnectionInfo: [");
+ sb.append("peerDiscoveryMac=").append(peerDiscoveryMac == null ? ""
+ : String.valueOf(HexEncoding.encode(peerDiscoveryMac))).append("pmk=").append(
+ pmk == null ? "" : "*").append("sessionId=").append(sessionId).append(
+ "passphrase=").append(passphrase == null ? "" : "*").append("]");
return sb.toString();
}
}
@@ -1040,8 +1235,9 @@ public class WifiAwareDataPathStateManager {
* name. Delegated to enable mocking.
*/
public boolean configureAgentProperties(AwareNetworkRequestInformation nnri,
- WifiAwareNetworkSpecifier networkSpecifier, int ndpId, NetworkInfo networkInfo,
- NetworkCapabilities networkCapabilities, LinkProperties linkProperties) {
+ Set<WifiAwareNetworkSpecifier> networkSpecifiers, int ndpId,
+ NetworkInfo networkInfo, NetworkCapabilities networkCapabilities,
+ LinkProperties linkProperties) {
// find link-local address
InetAddress linkLocal = null;
NetworkInterface ni;
@@ -1051,12 +1247,14 @@ public class WifiAwareDataPathStateManager {
Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
+ ": can't get network interface - " + e);
mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
return false;
}
if (ni == null) {
Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri
+ ": can't get network interface (null)");
mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
return false;
}
Enumeration<InetAddress> addresses = ni.getInetAddresses();
@@ -1071,6 +1269,7 @@ public class WifiAwareDataPathStateManager {
if (linkLocal == null) {
Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri + ": no link local addresses");
mMgr.endDataPath(ndpId);
+ nnri.state = AwareNetworkRequestInformation.STATE_TERMINATING;
return false;
}
@@ -1078,7 +1277,8 @@ public class WifiAwareDataPathStateManager {
networkInfo.setIsAvailable(true);
networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
- networkCapabilities.setNetworkSpecifier(networkSpecifier);
+ networkCapabilities.setNetworkSpecifier(new WifiAwareAgentNetworkSpecifier(
+ networkSpecifiers.toArray(new WifiAwareNetworkSpecifier[0])));
linkProperties.setInterfaceName(nnri.interfaceName);
linkProperties.addLinkAddress(new LinkAddress(linkLocal, 64));
@@ -1095,7 +1295,7 @@ public class WifiAwareDataPathStateManager {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("WifiAwareDataPathStateManager:");
pw.println(" mInterfaces: " + mInterfaces);
- pw.println(" mNetworkCapabilitiesFilter: " + mNetworkCapabilitiesFilter);
+ pw.println(" sNetworkCapabilitiesFilter: " + sNetworkCapabilitiesFilter);
pw.println(" mNetworkRequestsCache: " + mNetworkRequestsCache);
pw.println(" mNetworkFactory:");
mNetworkFactory.dump(fd, pw, args);
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java b/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java
index 02eaf5daa..c45c6dcab 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java
@@ -320,10 +320,7 @@ public class WifiAwareMetrics {
networkRequestCache.values()) {
if (anri.state
!= WifiAwareDataPathStateManager.AwareNetworkRequestInformation
- .STATE_INITIATOR_CONFIRMED
- && anri.state
- != WifiAwareDataPathStateManager.AwareNetworkRequestInformation
- .STATE_RESPONDER_CONFIRMED) {
+ .STATE_CONFIRMED) {
continue; // only count completed (up-and-running) NDPs
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
index 05721afee..2121160bb 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
@@ -167,11 +167,6 @@ public class WifiAwareNativeCallback extends IWifiNanIfaceEventCallback.Stub imp
capabilities.maxSubscribeInterfaceAddresses;
frameworkCapabilities.supportedCipherSuites = capabilities.supportedCipherSuites;
- // TODO (b/63635780, b/63635857): enable framework support of >1 NDI and >1 NDP per NDI
- // Until then: force corresponding capabilities to 1.
- frameworkCapabilities.maxNdiInterfaces = 1;
- frameworkCapabilities.maxNdpSessions = 1;
-
mWifiAwareStateManager.onCapabilitiesUpdateResponse(id, frameworkCapabilities);
} else {
Log.e(TAG, "notifyCapabilitiesResponse: error code=" + status.status + " ("
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java
index 74f34b362..9d0441f12 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java
@@ -50,6 +50,7 @@ public class WifiAwareRttStateManager {
private final SparseArray<WifiAwareClientState> mPendingOperations = new SparseArray<>();
private AsyncChannel mAsyncChannel;
+ private Context mContext;
/**
* Initializes the connection to the RTT service.
@@ -74,7 +75,7 @@ public class WifiAwareRttStateManager {
public void startWithRttService(Context context, Looper looper, IRttManager service) {
Messenger messenger;
try {
- messenger = service.getMessenger();
+ messenger = service.getMessenger(null, new int[1]);
} catch (RemoteException e) {
Log.e(TAG, "start(): not able to getMessenger() of WIFI_RTT_SERVICE");
return;
@@ -82,6 +83,7 @@ public class WifiAwareRttStateManager {
mAsyncChannel = new AsyncChannel();
mAsyncChannel.connect(context, new AwareRttHandler(looper), messenger);
+ mContext = context;
}
private WifiAwareClientState getAndRemovePendingOperationClient(int rangingId) {
@@ -125,7 +127,8 @@ public class WifiAwareRttStateManager {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION,
+ new RttManager.RttClient(mContext.getPackageName()));
} else {
Log.e(TAG, "Failed to set up channel connection to RTT service");
mAsyncChannel = null;
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java b/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java
index 41eef6960..a2f604686 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java
@@ -55,6 +55,7 @@ public class WifiAwareShellCommand extends ShellCommand {
for (DelegatedShellCommand dsc: mDelegatedCommands.values()) {
dsc.onReset();
}
+ return 0;
} else {
DelegatedShellCommand delegatedCmd = null;
if (!TextUtils.isEmpty(cmd)) {
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
index 30aa42a26..6ced9486c 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
@@ -204,7 +204,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe
private volatile Characteristics mCharacteristics = null;
private WifiAwareStateMachine mSm;
private WifiAwareRttStateManager mRtt;
- private WifiAwareDataPathStateManager mDataPathMgr;
+ public WifiAwareDataPathStateManager mDataPathMgr;
private PowerManager mPowerManager;
private final SparseArray<WifiAwareClientState> mClients = new SparseArray<>();
diff --git a/service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java b/service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java
deleted file mode 100644
index 31795f126..000000000
--- a/service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Copyright (C) 2017 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.hotspot2;
-
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Utility class for parsing legacy (N and older) Passpoint configuration file content
- * (/data/misc/wifi/PerProviderSubscription.conf). In N and older, only Release 1 is supported.
- *
- * This class only retrieve the relevant Release 1 configuration fields that are not backed
- * elsewhere. Below are relevant fields:
- * - FQDN (used for linking with configuration data stored elsewhere)
- * - Friendly Name
- * - Roaming Consortium
- * - Realm
- * - IMSI (for SIM credential)
- *
- * Below is an example content of a Passpoint configuration file:
- *
- * tree 3:1.2(urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0)
- * 8:MgmtTree+
- * 17:PerProviderSubscription+
- * 4:r1i1+
- * 6:HomeSP+
- * c:FriendlyName=d:Test Provider
- * 4:FQDN=8:test.net
- * 13:RoamingConsortiumOI=9:1234,5678
- * .
- * a:Credential+
- * 10:UsernamePassword+
- * 8:Username=4:user
- * 8:Password=4:pass
- *
- * 9:EAPMethod+
- * 7:EAPType=2:21
- * b:InnerMethod=3:PAP
- * .
- * .
- * 5:Realm=a:boingo.com
- * .
- * .
- * .
- * .
- *
- * Each string is prefixed with a "|StringBytesInHex|:".
- * '+' indicates start of a new internal node.
- * '.' indicates end of the current internal node.
- * '=' indicates "value" of a leaf node.
- *
- */
-public class LegacyPasspointConfigParser {
- private static final String TAG = "LegacyPasspointConfigParser";
-
- private static final String TAG_MANAGEMENT_TREE = "MgmtTree";
- private static final String TAG_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription";
- private static final String TAG_HOMESP = "HomeSP";
- private static final String TAG_FQDN = "FQDN";
- private static final String TAG_FRIENDLY_NAME = "FriendlyName";
- private static final String TAG_ROAMING_CONSORTIUM_OI = "RoamingConsortiumOI";
- private static final String TAG_CREDENTIAL = "Credential";
- private static final String TAG_REALM = "Realm";
- private static final String TAG_SIM = "SIM";
- private static final String TAG_IMSI = "IMSI";
-
- private static final String LONG_ARRAY_SEPARATOR = ",";
- private static final String END_OF_INTERNAL_NODE_INDICATOR = ".";
- private static final char START_OF_INTERNAL_NODE_INDICATOR = '+';
- private static final char STRING_PREFIX_INDICATOR = ':';
- private static final char STRING_VALUE_INDICATOR = '=';
-
- /**
- * An abstraction for a node within a tree. A node can be an internal node (contained
- * children nodes) or a leaf node (contained a String value).
- */
- private abstract static class Node {
- private final String mName;
- Node(String name) {
- mName = name;
- }
-
- /**
- * @return the name of the node
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Applies for internal node only.
- *
- * @return the list of children nodes.
- */
- public abstract List<Node> getChildren();
-
- /**
- * Applies for leaf node only.
- *
- * @return the string value of the node
- */
- public abstract String getValue();
- }
-
- /**
- * Class representing an internal node of a tree. It contained a list of child nodes.
- */
- private static class InternalNode extends Node {
- private final List<Node> mChildren;
- InternalNode(String name, List<Node> children) {
- super(name);
- mChildren = children;
- }
-
- @Override
- public List<Node> getChildren() {
- return mChildren;
- }
-
- @Override
- public String getValue() {
- return null;
- }
- }
-
- /**
- * Class representing a leaf node of a tree. It contained a String type value.
- */
- private static class LeafNode extends Node {
- private final String mValue;
- LeafNode(String name, String value) {
- super(name);
- mValue = value;
- }
-
- @Override
- public List<Node> getChildren() {
- return null;
- }
-
- @Override
- public String getValue() {
- return mValue;
- }
- }
-
- public LegacyPasspointConfigParser() {}
-
- /**
- * Parse the legacy Passpoint configuration file content, only retrieve the relevant
- * configurations that are not saved elsewhere.
- *
- * For both N and M, only Release 1 is supported. Most of the configurations are saved
- * elsewhere as part of the {@link android.net.wifi.WifiConfiguration} data.
- * The configurations needed from the legacy Passpoint configuration file are:
- *
- * - FQDN - needed to be able to link to the associated {@link WifiConfiguration} data
- * - Friendly Name
- * - Roaming Consortium OIs
- * - Realm
- * - IMSI (for SIM credential)
- *
- * Make this function non-static so that it can be mocked during unit test.
- *
- * @param fileName The file name of the configuration file
- * @return Map of FQDN to {@link LegacyPasspointConfig}
- * @throws IOException
- */
- public Map<String, LegacyPasspointConfig> parseConfig(String fileName)
- throws IOException {
- Map<String, LegacyPasspointConfig> configs = new HashMap<>();
- BufferedReader in = new BufferedReader(new FileReader(fileName));
- in.readLine(); // Ignore the first line which contained the header.
-
- // Convert the configuration data to a management tree represented by a root {@link Node}.
- Node root = buildNode(in);
-
- if (root == null || root.getChildren() == null) {
- Log.d(TAG, "Empty configuration data");
- return configs;
- }
-
- // Verify root node name.
- if (!TextUtils.equals(TAG_MANAGEMENT_TREE, root.getName())) {
- throw new IOException("Unexpected root node: " + root.getName());
- }
-
- // Process and retrieve the configuration from each PPS (PerProviderSubscription) node.
- List<Node> ppsNodes = root.getChildren();
- for (Node ppsNode : ppsNodes) {
- LegacyPasspointConfig config = processPpsNode(ppsNode);
- configs.put(config.mFqdn, config);
- }
- return configs;
- }
-
- /**
- * Build a {@link Node} from the current line in the buffer. A node can be an internal
- * node (ends with '+') or a leaf node.
- *
- * @param in Input buffer to read data from
- * @return {@link Node} representing the current line
- * @throws IOException
- */
- private static Node buildNode(BufferedReader in) throws IOException {
- // Read until non-empty line.
- String currentLine = null;
- while ((currentLine = in.readLine()) != null) {
- if (!currentLine.isEmpty()) {
- break;
- }
- }
-
- // Return null if EOF is reached.
- if (currentLine == null) {
- return null;
- }
-
- // Remove the leading and the trailing whitespaces.
- currentLine = currentLine.trim();
-
- // Check for the internal node terminator.
- if (TextUtils.equals(END_OF_INTERNAL_NODE_INDICATOR, currentLine)) {
- return null;
- }
-
- // Parse the name-value of the current line. The value will be null if the current line
- // is not a leaf node (e.g. line ends with a '+').
- // Each line is encoded in UTF-8.
- Pair<String, String> nameValuePair =
- parseLine(currentLine.getBytes(StandardCharsets.UTF_8));
- if (nameValuePair.second != null) {
- return new LeafNode(nameValuePair.first, nameValuePair.second);
- }
-
- // Parse the children contained under this internal node.
- List<Node> children = new ArrayList<>();
- Node child = null;
- while ((child = buildNode(in)) != null) {
- children.add(child);
- }
- return new InternalNode(nameValuePair.first, children);
- }
-
- /**
- * Process a PPS (PerProviderSubscription) node to retrieve Passpoint configuration data.
- *
- * @param ppsNode The PPS node to process
- * @return {@link LegacyPasspointConfig}
- * @throws IOException
- */
- private static LegacyPasspointConfig processPpsNode(Node ppsNode) throws IOException {
- if (ppsNode.getChildren() == null || ppsNode.getChildren().size() != 1) {
- throw new IOException("PerProviderSubscription node should contain "
- + "one instance node");
- }
-
- if (!TextUtils.equals(TAG_PER_PROVIDER_SUBSCRIPTION, ppsNode.getName())) {
- throw new IOException("Unexpected name for PPS node: " + ppsNode.getName());
- }
-
- // Retrieve the PPS instance node.
- Node instanceNode = ppsNode.getChildren().get(0);
- if (instanceNode.getChildren() == null) {
- throw new IOException("PPS instance node doesn't contained any children");
- }
-
- // Process and retrieve the relevant configurations under the PPS instance node.
- LegacyPasspointConfig config = new LegacyPasspointConfig();
- for (Node node : instanceNode.getChildren()) {
- switch (node.getName()) {
- case TAG_HOMESP:
- processHomeSPNode(node, config);
- break;
- case TAG_CREDENTIAL:
- processCredentialNode(node, config);
- break;
- default:
- Log.d(TAG, "Ignore uninterested field under PPS instance: " + node.getName());
- break;
- }
- }
- if (config.mFqdn == null) {
- throw new IOException("PPS instance missing FQDN");
- }
- return config;
- }
-
- /**
- * Process a HomeSP node to retrieve configuration data into the given |config|.
- *
- * @param homeSpNode The HomeSP node to process
- * @param config The config object to fill in the data
- * @throws IOException
- */
- private static void processHomeSPNode(Node homeSpNode, LegacyPasspointConfig config)
- throws IOException {
- if (homeSpNode.getChildren() == null) {
- throw new IOException("HomeSP node should contain at least one child node");
- }
-
- for (Node node : homeSpNode.getChildren()) {
- switch (node.getName()) {
- case TAG_FQDN:
- config.mFqdn = getValue(node);
- break;
- case TAG_FRIENDLY_NAME:
- config.mFriendlyName = getValue(node);
- break;
- case TAG_ROAMING_CONSORTIUM_OI:
- config.mRoamingConsortiumOis = parseLongArray(getValue(node));
- break;
- default:
- Log.d(TAG, "Ignore uninterested field under HomeSP: " + node.getName());
- break;
- }
- }
- }
-
- /**
- * Process a Credential node to retrieve configuration data into the given |config|.
- *
- * @param credentialNode The Credential node to process
- * @param config The config object to fill in the data
- * @throws IOException
- */
- private static void processCredentialNode(Node credentialNode,
- LegacyPasspointConfig config)
- throws IOException {
- if (credentialNode.getChildren() == null) {
- throw new IOException("Credential node should contain at least one child node");
- }
-
- for (Node node : credentialNode.getChildren()) {
- switch (node.getName()) {
- case TAG_REALM:
- config.mRealm = getValue(node);
- break;
- case TAG_SIM:
- processSimNode(node, config);
- break;
- default:
- Log.d(TAG, "Ignore uninterested field under Credential: " + node.getName());
- break;
- }
- }
- }
-
- /**
- * Process a SIM node to retrieve configuration data into the given |config|.
- *
- * @param simNode The SIM node to process
- * @param config The config object to fill in the data
- * @throws IOException
- */
- private static void processSimNode(Node simNode, LegacyPasspointConfig config)
- throws IOException {
- if (simNode.getChildren() == null) {
- throw new IOException("SIM node should contain at least one child node");
- }
-
- for (Node node : simNode.getChildren()) {
- switch (node.getName()) {
- case TAG_IMSI:
- config.mImsi = getValue(node);
- break;
- default:
- Log.d(TAG, "Ignore uninterested field under SIM: " + node.getName());
- break;
- }
- }
- }
-
- /**
- * Parse the given line in the legacy Passpoint configuration file.
- * A line can be in the following formats:
- * 2:ab+ // internal node
- * 2:ab=2:bc // leaf node
- * . // end of internal node
- *
- * @param line The line to parse
- * @return name-value pair, a value of null indicates internal node
- * @throws IOException
- */
- private static Pair<String, String> parseLine(byte[] lineBytes) throws IOException {
- Pair<String, Integer> nameIndexPair = parseString(lineBytes, 0);
- int currentIndex = nameIndexPair.second;
- try {
- if (lineBytes[currentIndex] == START_OF_INTERNAL_NODE_INDICATOR) {
- return Pair.create(nameIndexPair.first, null);
- }
-
- if (lineBytes[currentIndex] != STRING_VALUE_INDICATOR) {
- throw new IOException("Invalid line - missing both node and value indicator: "
- + new String(lineBytes, StandardCharsets.UTF_8));
- }
- } catch (IndexOutOfBoundsException e) {
- throw new IOException("Invalid line - " + e.getMessage() + ": "
- + new String(lineBytes, StandardCharsets.UTF_8));
- }
- Pair<String, Integer> valueIndexPair = parseString(lineBytes, currentIndex + 1);
- return Pair.create(nameIndexPair.first, valueIndexPair.first);
- }
-
- /**
- * Parse a string value in the given line from the given start index.
- * A string value is in the following format:
- * |HexByteLength|:|String|
- *
- * The length value indicates the number of UTF-8 bytes in hex for the given string.
- *
- * For example: 3:abc
- *
- * @param lineBytes The UTF-8 bytes of the line to parse
- * @param startIndex The start index from the given line to parse from
- * @return Pair of a string value and an index pointed to character after the string value
- * @throws IOException
- */
- private static Pair<String, Integer> parseString(byte[] lineBytes, int startIndex)
- throws IOException {
- // Locate the index that separate length and the string value.
- int prefixIndex = -1;
- for (int i = startIndex; i < lineBytes.length; i++) {
- if (lineBytes[i] == STRING_PREFIX_INDICATOR) {
- prefixIndex = i;
- break;
- }
- }
- if (prefixIndex == -1) {
- throw new IOException("Invalid line - missing string prefix: "
- + new String(lineBytes, StandardCharsets.UTF_8));
- }
-
- try {
- String lengthStr = new String(lineBytes, startIndex, prefixIndex - startIndex,
- StandardCharsets.UTF_8);
- int length = Integer.parseInt(lengthStr, 16);
- int strStartIndex = prefixIndex + 1;
- // The length might account for bytes for the whitespaces, since the whitespaces are
- // already trimmed, ignore them.
- if ((strStartIndex + length) > lineBytes.length) {
- length = lineBytes.length - strStartIndex;
- }
- return Pair.create(
- new String(lineBytes, strStartIndex, length, StandardCharsets.UTF_8),
- strStartIndex + length);
- } catch (NumberFormatException | IndexOutOfBoundsException e) {
- throw new IOException("Invalid line - " + e.getMessage() + ": "
- + new String(lineBytes, StandardCharsets.UTF_8));
- }
- }
-
- /**
- * Parse a long array from the given string.
- *
- * @param str The string to parse
- * @return long[]
- * @throws IOException
- */
- private static long[] parseLongArray(String str)
- throws IOException {
- String[] strArray = str.split(LONG_ARRAY_SEPARATOR);
- long[] longArray = new long[strArray.length];
- for (int i = 0; i < longArray.length; i++) {
- try {
- longArray[i] = Long.parseLong(strArray[i], 16);
- } catch (NumberFormatException e) {
- throw new IOException("Invalid long integer value: " + strArray[i]);
- }
- }
- return longArray;
- }
-
- /**
- * Get the String value of the given node. An IOException will be thrown if the given
- * node doesn't contain a String value (internal node).
- *
- * @param node The node to get the value from
- * @return String
- * @throws IOException
- */
- private static String getValue(Node node) throws IOException {
- if (node.getValue() == null) {
- throw new IOException("Attempt to retreive value from non-leaf node: "
- + node.getName());
- }
- return node.getValue();
- }
-}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
index 6ff5ee945..fb8131695 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkEvaluator.java
@@ -115,6 +115,13 @@ public class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEva
if (currentNetwork != null && TextUtils.equals(currentNetwork.SSID,
ScanResultUtil.createQuotedSSID(bestNetwork.mScanDetail.getSSID()))) {
localLog("Staying with current Passpoint network " + currentNetwork.SSID);
+
+ // Update current network with the latest scan info.
+ mWifiConfigManager.setNetworkCandidateScanResult(currentNetwork.networkId,
+ bestNetwork.mScanDetail.getScanResult(), 0);
+ mWifiConfigManager.updateScanDetailForNetwork(currentNetwork.networkId,
+ bestNetwork.mScanDetail);
+
connectableNetworks.add(Pair.create(bestNetwork.mScanDetail, currentNetwork));
return currentNetwork;
}
diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallback.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallback.java
index 802f6435c..b7a4b3bc8 100644
--- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallback.java
+++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallback.java
@@ -30,8 +30,6 @@ import android.util.Log;
import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus;
import com.android.server.wifi.util.NativeUtil;
-import libcore.util.HexEncoding;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -97,7 +95,6 @@ public class SupplicantP2pIfaceCallback extends ISupplicantP2pIfaceCallback.Stub
byte[] wfdDeviceInfo) {
WifiP2pDevice device = new WifiP2pDevice();
device.deviceName = deviceName;
-
if (deviceName == null) {
Log.e(TAG, "Missing device name.");
return;
@@ -111,8 +108,7 @@ public class SupplicantP2pIfaceCallback extends ISupplicantP2pIfaceCallback.Stub
}
try {
- device.primaryDeviceType = new String(HexEncoding.encode(
- primaryDeviceType, 0, primaryDeviceType.length));
+ device.primaryDeviceType = NativeUtil.wpsDevTypeStringFromByteArray(primaryDeviceType);
} catch (Exception e) {
Log.e(TAG, "Could not encode device primary type.", e);
return;
@@ -134,7 +130,6 @@ public class SupplicantP2pIfaceCallback extends ISupplicantP2pIfaceCallback.Stub
mMonitor.broadcastP2pDeviceFound(mInterface, device);
}
-
/**
* Used to indicate that a P2P device has been lost.
*
diff --git a/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java b/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
index 0fadd804b..7d0ccbaf6 100644
--- a/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
@@ -42,7 +42,6 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
private final WifiNative mWifiNative;
private final ChannelHelper mChannelHelper;
private final WificondScannerImpl mWificondScannerDelegate;
- private final boolean mHalBasedPnoSupported;
public HalWifiScannerImpl(Context context, WifiNative wifiNative, WifiMonitor wifiMonitor,
Looper looper, Clock clock) {
@@ -51,9 +50,6 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
mWificondScannerDelegate =
new WificondScannerImpl(context, wifiNative, wifiMonitor, mChannelHelper,
looper, clock);
-
- // We are not going to support HAL ePNO currently.
- mHalBasedPnoSupported = false;
}
@Override
@@ -121,38 +117,22 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
@Override
public boolean setHwPnoList(WifiNative.PnoSettings settings,
WifiNative.PnoEventHandler eventHandler) {
- if (mHalBasedPnoSupported) {
- return mWifiNative.setPnoList(settings, eventHandler);
- } else {
- return mWificondScannerDelegate.setHwPnoList(settings, eventHandler);
- }
+ return mWificondScannerDelegate.setHwPnoList(settings, eventHandler);
}
@Override
public boolean resetHwPnoList() {
- if (mHalBasedPnoSupported) {
- return mWifiNative.resetPnoList();
- } else {
- return mWificondScannerDelegate.resetHwPnoList();
- }
+ return mWificondScannerDelegate.resetHwPnoList();
}
@Override
public boolean isHwPnoSupported(boolean isConnectedPno) {
- if (mHalBasedPnoSupported) {
- return true;
- } else {
- return mWificondScannerDelegate.isHwPnoSupported(isConnectedPno);
- }
+ return mWificondScannerDelegate.isHwPnoSupported(isConnectedPno);
}
@Override
public boolean shouldScheduleBackgroundScanForHwPno() {
- if (mHalBasedPnoSupported) {
- return true;
- } else {
- return mWificondScannerDelegate.shouldScheduleBackgroundScanForHwPno();
- }
+ return mWificondScannerDelegate.shouldScheduleBackgroundScanForHwPno();
}
@Override
diff --git a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
index ab2a5dca3..4b8e284cc 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
@@ -2129,20 +2129,21 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
pw.println();
pw.println("Latest scan results:");
List<ScanResult> scanResults = mSingleScanStateMachine.getCachedScanResultsAsList();
- long nowMs = System.currentTimeMillis();
+ long nowMs = mClock.getElapsedSinceBootMillis();
if (scanResults != null && scanResults.size() != 0) {
pw.println(" BSSID Frequency RSSI Age(sec) SSID "
+ " Flags");
for (ScanResult r : scanResults) {
+ long timeStampMs = r.timestamp / 1000;
String age;
- if (r.seen <= 0) {
+ if (timeStampMs <= 0) {
age = "___?___";
- } else if (nowMs < r.seen) {
+ } else if (nowMs < timeStampMs) {
age = " 0.000";
- } else if (r.seen < nowMs - 1000000) {
+ } else if (timeStampMs < nowMs - 1000000) {
age = ">1000.0";
} else {
- age = String.format("%3.3f", (nowMs - r.seen) / 1000.0);
+ age = String.format("%3.3f", (nowMs - timeStampMs) / 1000.0);
}
String ssid = r.SSID == null ? "" : r.SSID;
pw.printf(" %17s %9d %5d %7s %-32s %s\n",
diff --git a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
index 84105ee61..ed25e0f67 100644
--- a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
@@ -422,11 +422,22 @@ public class WificondScannerImpl extends WifiScannerImpl implements Handler.Call
mPendingSingleScanEventHandler = null;
}
- if ((newScanSettings.backgroundScanActive || newScanSettings.singleScanActive)
- && !allFreqs.isEmpty()) {
- pauseHwPnoScan();
- Set<Integer> freqs = allFreqs.getScanFreqs();
- boolean success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
+ if (newScanSettings.backgroundScanActive || newScanSettings.singleScanActive) {
+ boolean success = false;
+ Set<Integer> freqs;
+ if (!allFreqs.isEmpty()) {
+ pauseHwPnoScan();
+ freqs = allFreqs.getScanFreqs();
+ success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
+ if (!success) {
+ Log.e(TAG, "Failed to start scan, freqs=" + freqs);
+ }
+ } else {
+ // There is a scan request but no available channels could be scanned for.
+ // We regard it as a scan failure in this case.
+ Log.e(TAG, "Failed to start scan because there is "
+ + "no available channel to scan for");
+ }
if (success) {
// TODO handle scan timeout
if (DBG) {
@@ -439,7 +450,6 @@ public class WificondScannerImpl extends WifiScannerImpl implements Handler.Call
mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
} else {
- Log.e(TAG, "Failed to start scan, freqs=" + freqs);
// indicate scan failure async
mEventHandler.post(new Runnable() {
public void run() {
@@ -538,7 +548,7 @@ public class WificondScannerImpl extends WifiScannerImpl implements Handler.Call
// got a scan before we started scanning or after scan was canceled
return;
}
- mNativeScanResults = mWifiNative.getScanResults();
+ mNativeScanResults = mWifiNative.getPnoScanResults();
List<ScanResult> hwPnoScanResults = new ArrayList<>();
int numFilteredScanResults = 0;
for (int i = 0; i < mNativeScanResults.size(); ++i) {
diff --git a/service/java/com/android/server/wifi/util/Matrix.java b/service/java/com/android/server/wifi/util/Matrix.java
new file mode 100644
index 000000000..bdf147ede
--- /dev/null
+++ b/service/java/com/android/server/wifi/util/Matrix.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+/**
+ * Utility for doing basic matix calculations
+ */
+public class Matrix {
+ public final int n;
+ public final int m;
+ public final double[] mem;
+
+ /**
+ * Creates a new matrix, initialized to zeros
+ *
+ * @param rows - number of rows (n)
+ * @param cols - number of columns (m)
+ */
+ public Matrix(int rows, int cols) {
+ n = rows;
+ m = cols;
+ mem = new double[rows * cols];
+ }
+
+ /**
+ * Creates a new matrix using the provided array of values
+ * <p>
+ * Values are in row-major order.
+ *
+ * @param stride is the number of columns.
+ * @param values is the array of values.
+ * @throws IllegalArgumentException if length of values array not a multiple of stride
+ */
+ public Matrix(int stride, double[] values) {
+ n = (values.length + stride - 1) / stride;
+ m = stride;
+ mem = values;
+ if (mem.length != n * m) throw new IllegalArgumentException();
+ }
+
+ /**
+ * Creates a new matrix duplicating the given one
+ *
+ * @param that is the source Matrix.
+ */
+ public Matrix(Matrix that) {
+ n = that.n;
+ m = that.m;
+ mem = new double[that.mem.length];
+ for (int i = 0; i < mem.length; i++) {
+ mem[i] = that.mem[i];
+ }
+ }
+
+ /**
+ * Gets the matrix coefficient from row i, column j
+ *
+ * @param i row number
+ * @param j column number
+ * @return Coefficient at i,j
+ * @throws IndexOutOfBoundsException if an index is out of bounds
+ */
+ public double get(int i, int j) {
+ if (!(0 <= i && i < n && 0 <= j && j < m)) throw new IndexOutOfBoundsException();
+ return mem[i * m + j];
+ }
+
+ /**
+ * Store a matrix coefficient in row i, column j
+ *
+ * @param i row number
+ * @param j column number
+ * @param v Coefficient to store at i,j
+ * @throws IndexOutOfBoundsException if an index is out of bounds
+ */
+ public void put(int i, int j, double v) {
+ if (!(0 <= i && i < n && 0 <= j && j < m)) throw new IndexOutOfBoundsException();
+ mem[i * m + j] = v;
+ }
+
+ /**
+ * Forms the sum of two matrices, this and that
+ *
+ * @param that is the other matrix
+ * @return newly allocated matrix representing the sum of this and that
+ * @throws IllegalArgumentException if shapes differ
+ */
+ public Matrix plus(Matrix that) {
+ return plus(that, new Matrix(n, m));
+
+ }
+
+ /**
+ * Forms the sum of two matrices, this and that
+ *
+ * @param that is the other matrix
+ * @param result is space to hold the result
+ * @return result, filled with the matrix sum
+ * @throws IllegalArgumentException if shapes differ
+ */
+ public Matrix plus(Matrix that, Matrix result) {
+ if (!(this.n == that.n && this.m == that.m && this.n == result.n && this.m == result.m)) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < mem.length; i++) {
+ result.mem[i] = this.mem[i] + that.mem[i];
+ }
+ return result;
+ }
+
+ /**
+ * Forms the difference of two matrices, this and that
+ *
+ * @param that is the other matrix
+ * @return newly allocated matrix representing the difference of this and that
+ * @throws IllegalArgumentException if shapes differ
+ */
+ public Matrix minus(Matrix that) {
+ return minus(that, new Matrix(n, m));
+ }
+
+ /**
+ * Forms the difference of two matrices, this and that
+ *
+ * @param that is the other matrix
+ * @param result is space to hold the result
+ * @return result, filled with the matrix difference
+ * @throws IllegalArgumentException if shapes differ
+ */
+ public Matrix minus(Matrix that, Matrix result) {
+ if (!(this.n == that.n && this.m == that.m && this.n == result.n && this.m == result.m)) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < mem.length; i++) {
+ result.mem[i] = this.mem[i] - that.mem[i];
+ }
+ return result;
+ }
+
+ /**
+ * Forms the matrix product of two matrices, this and that
+ *
+ * @param that is the other matrix
+ * @return newly allocated matrix representing the matrix product of this and that
+ * @throws IllegalArgumentException if shapes are not conformant
+ */
+ public Matrix dot(Matrix that) {
+ return dot(that, new Matrix(this.n, that.m));
+ }
+
+ /**
+ * Forms the matrix product of two matrices, this and that
+ * <p>
+ * Caller supplies an object to contain the result, as well as scratch space
+ *
+ * @param that is the other matrix
+ * @param result is space to hold the result
+ * @return result, filled with the matrix product
+ * @throws IllegalArgumentException if shapes are not conformant
+ */
+ public Matrix dot(Matrix that, Matrix result) {
+ if (!(this.n == result.n && this.m == that.n && that.m == result.m)) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < that.m; j++) {
+ double s = 0.0;
+ for (int k = 0; k < m; k++) {
+ s += this.get(i, k) * that.get(k, j);
+ }
+ result.put(i, j, s);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Forms the matrix transpose
+ *
+ * @return newly allocated transpose matrix
+ */
+ public Matrix transpose() {
+ return transpose(new Matrix(m, n));
+ }
+
+ /**
+ * Forms the matrix transpose
+ * <p>
+ * Caller supplies an object to contain the result
+ *
+ * @param result is space to hold the result
+ * @return result, filled with the matrix transpose
+ * @throws IllegalArgumentException if result shape is wrong
+ */
+ public Matrix transpose(Matrix result) {
+ if (!(this.n == result.m && this.m == result.n)) throw new IllegalArgumentException();
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < m; j++) {
+ result.put(j, i, get(i, j));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Forms the inverse of a square matrix
+ *
+ * @return newly allocated matrix representing the matrix inverse
+ * @throws ArithmeticException if the matrix is not invertible
+ */
+ public Matrix inverse() {
+ return inverse(new Matrix(n, m), new Matrix(n, 2 * m));
+ }
+
+ /**
+ * Forms the inverse of a square matrix
+ *
+ * @param result is space to hold the result
+ * @param scratch is workspace of dimension n by 2*n
+ * @return result, filled with the matrix inverse
+ * @throws ArithmeticException if the matrix is not invertible
+ * @throws IllegalArgumentException if shape of scratch or result is wrong
+ */
+ public Matrix inverse(Matrix result, Matrix scratch) {
+ if (!(n == m && n == result.n && m == result.m && n == scratch.n && 2 * m == scratch.m)) {
+ throw new IllegalArgumentException();
+ }
+
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < m; j++) {
+ scratch.put(i, j, get(i, j));
+ scratch.put(i, m + j, i == j ? 1.0 : 0.0);
+ }
+ }
+
+ for (int i = 0; i < n; i++) {
+ int ibest = i;
+ double vbest = Math.abs(scratch.get(ibest, ibest));
+ for (int ii = i + 1; ii < n; ii++) {
+ double v = Math.abs(scratch.get(ii, i));
+ if (v > vbest) {
+ ibest = ii;
+ vbest = v;
+ }
+ }
+ if (ibest != i) {
+ for (int j = 0; j < scratch.m; j++) {
+ double t = scratch.get(i, j);
+ scratch.put(i, j, scratch.get(ibest, j));
+ scratch.put(ibest, j, t);
+ }
+ }
+ double d = scratch.get(i, i);
+ if (d == 0.0) throw new ArithmeticException("Singular matrix");
+ for (int j = 0; j < scratch.m; j++) {
+ scratch.put(i, j, scratch.get(i, j) / d);
+ }
+ for (int ii = i + 1; ii < n; ii++) {
+ d = scratch.get(ii, i);
+ for (int j = 0; j < scratch.m; j++) {
+ scratch.put(ii, j, scratch.get(ii, j) - d * scratch.get(i, j));
+ }
+ }
+ }
+ for (int i = n - 1; i >= 0; i--) {
+ for (int ii = 0; ii < i; ii++) {
+ double d = scratch.get(ii, i);
+ for (int j = 0; j < scratch.m; j++) {
+ scratch.put(ii, j, scratch.get(ii, j) - d * scratch.get(i, j));
+ }
+ }
+ }
+ for (int i = 0; i < result.n; i++) {
+ for (int j = 0; j < result.m; j++) {
+ result.put(i, j, scratch.get(i, m + j));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Tests for equality
+ */
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) return true;
+ if (!(that instanceof Matrix)) return false;
+ Matrix other = (Matrix) that;
+ if (n != other.n) return false;
+ if (m != other.m) return false;
+ for (int i = 0; i < mem.length; i++) {
+ if (mem[i] != other.mem[i]) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Calculates a hash code
+ */
+ @Override
+ public int hashCode() {
+ int h = n * 101 + m;
+ for (int i = 0; i < mem.length; i++) {
+ h = h * 37 + Double.hashCode(mem[i]);
+ }
+ return h;
+ }
+
+ /**
+ * Makes a string representation
+ *
+ * @return string like "[a, b; c, d]"
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(n * m * 8);
+ sb.append("[");
+ for (int i = 0; i < mem.length; i++) {
+ if (i > 0) sb.append(i % m == 0 ? "; " : ", ");
+ sb.append(mem[i]);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
diff --git a/service/java/com/android/server/wifi/util/NativeUtil.java b/service/java/com/android/server/wifi/util/NativeUtil.java
index 07c3f9b38..84f93514c 100644
--- a/service/java/com/android/server/wifi/util/NativeUtil.java
+++ b/service/java/com/android/server/wifi/util/NativeUtil.java
@@ -30,6 +30,7 @@ import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* Provide utility functions for native interfacing modules.
@@ -209,13 +210,13 @@ public class NativeUtil {
/**
* Converts an string to an arraylist of UTF_8 byte values.
* These forms are acceptable:
- * a) ASCII String encapsulated in quotes, or
+ * a) UTF-8 String encapsulated in quotes, or
* b) Hex string with no delimiters.
*
* @param str String to be converted.
* @throws IllegalArgumentException for null string.
*/
- public static ArrayList<Byte> hexOrQuotedAsciiStringToBytes(String str) {
+ public static ArrayList<Byte> hexOrQuotedStringToBytes(String str) {
if (str == null) {
throw new IllegalArgumentException("null string");
}
@@ -231,21 +232,21 @@ public class NativeUtil {
/**
* Converts an ArrayList<Byte> of UTF_8 byte values to string.
* The string will either be:
- * a) ASCII String encapsulated in quotes (if all the bytes are ASCII encodeable and non null),
+ * a) UTF-8 String encapsulated in quotes (if all the bytes are UTF-8 encodeable and non null),
* or
* b) Hex string with no delimiters.
*
* @param bytes List of bytes for ssid.
* @throws IllegalArgumentException for null bytes.
*/
- public static String bytesToHexOrQuotedAsciiString(ArrayList<Byte> bytes) {
+ public static String bytesToHexOrQuotedString(ArrayList<Byte> bytes) {
if (bytes == null) {
throw new IllegalArgumentException("null ssid bytes");
}
byte[] byteArray = byteArrayFromArrayList(bytes);
// Check for 0's in the byte stream in which case we cannot convert this into a string.
if (!bytes.contains(Byte.valueOf((byte) 0))) {
- CharsetDecoder decoder = StandardCharsets.US_ASCII.newDecoder();
+ CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
try {
CharBuffer decoded = decoder.decode(ByteBuffer.wrap(byteArray));
return "\"" + decoded.toString() + "\"";
@@ -258,20 +259,20 @@ public class NativeUtil {
/**
* Converts an ssid string to an arraylist of UTF_8 byte values.
* These forms are acceptable:
- * a) ASCII String encapsulated in quotes, or
+ * a) UTF-8 String encapsulated in quotes, or
* b) Hex string with no delimiters.
*
* @param ssidStr String to be converted.
* @throws IllegalArgumentException for null string.
*/
public static ArrayList<Byte> decodeSsid(String ssidStr) {
- return hexOrQuotedAsciiStringToBytes(ssidStr);
+ return hexOrQuotedStringToBytes(ssidStr);
}
/**
* Converts an ArrayList<Byte> of UTF_8 byte values to ssid string.
* The string will either be:
- * a) ASCII String encapsulated in quotes (if all the bytes are ASCII encodeable and non null),
+ * a) UTF-8 String encapsulated in quotes (if all the bytes are UTF-8 encodeable and non null),
* or
* b) Hex string with no delimiters.
*
@@ -279,7 +280,7 @@ public class NativeUtil {
* @throws IllegalArgumentException for null bytes.
*/
public static String encodeSsid(ArrayList<Byte> ssidBytes) {
- return bytesToHexOrQuotedAsciiString(ssidBytes);
+ return bytesToHexOrQuotedString(ssidBytes);
}
/**
@@ -330,4 +331,16 @@ public class NativeUtil {
}
return new String(HexEncoding.encode(bytes)).toLowerCase();
}
+
+ /**
+ * Converts an 8 byte array to a WPS device type string
+ * { 0, 1, 2, -1, 4, 5, 6, 7 } --> "1-02FF0405-1543";
+ */
+ public static String wpsDevTypeStringFromByteArray(byte[] devType) {
+ byte[] a = devType;
+ int x = ((a[0] & 0xFF) << 8) | (a[1] & 0xFF);
+ String y = new String(HexEncoding.encode(Arrays.copyOfRange(devType, 2, 6)));
+ int z = ((a[6] & 0xFF) << 8) | (a[7] & 0xFF);
+ return String.format("%d-%s-%d", x, y, z);
+ }
}
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
index c5eea7d70..52c96183e 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -17,16 +17,23 @@
package com.android.server.wifi.util;
import android.Manifest;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.net.wifi.WifiConfiguration;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.UserManager;
import android.provider.Settings;
+import android.text.TextUtils;
+import com.android.server.wifi.FrameworkFacade;
import com.android.server.wifi.WifiInjector;
import com.android.server.wifi.WifiLog;
import com.android.server.wifi.WifiSettingsStore;
@@ -45,6 +52,7 @@ public class WifiPermissionsUtil {
private final UserManager mUserManager;
private final WifiSettingsStore mSettingsStore;
private final NetworkScoreManager mNetworkScoreManager;
+ private final FrameworkFacade mFrameworkFacade;
private WifiLog mLog;
public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper,
@@ -57,6 +65,7 @@ public class WifiPermissionsUtil {
mSettingsStore = settingsStore;
mLog = wifiInjector.makeLog(TAG);
mNetworkScoreManager = networkScoreManager;
+ mFrameworkFacade = wifiInjector.getFrameworkFacade();
}
/**
@@ -113,10 +122,29 @@ public class WifiPermissionsUtil {
}
}
+
+ /**
+ * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION
+ * and a corresponding app op is allowed for this package and uid.
+ *
+ * @param pkgName PackageName of the application requesting access
+ * @param uid The uid of the package
+ */
+ public boolean checkCallersLocationPermission(String pkgName, int uid) {
+ // Coarse Permission implies Fine permission
+ if ((mWifiPermissionsWrapper.getUidPermission(
+ Manifest.permission.ACCESS_COARSE_LOCATION, uid)
+ == PackageManager.PERMISSION_GRANTED)
+ && checkAppOpAllowed(AppOpsManager.OP_COARSE_LOCATION, pkgName, uid)) {
+ return true;
+ }
+ return false;
+ }
+
/**
* API to determine if the caller has permissions to get
* scan results.
- * @param pkgName Packagename of the application requesting access
+ * @param pkgName package name of the application requesting access
* @param uid The uid of the package
* @param minVersion Minimum app API Version number to enforce location permission
* @return boolean true or false if permissions is granted
@@ -148,7 +176,7 @@ public class WifiPermissionsUtil {
}
// If the User or profile is current, permission is granted
// Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
- if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
+ if (!canAccessUserProfile(uid)) {
mLog.tC("Denied: Profile not permitted");
return false;
}
@@ -156,6 +184,77 @@ public class WifiPermissionsUtil {
}
/**
+ * API to determine if the caller has permissions to get a {@link android.net.wifi.WifiInfo}
+ * instance containing the SSID and BSSID.
+ *
+ *
+ * @param currentConfig the currently connected WiFi config
+ * @param pkgName package name of the application requesting access
+ * @param uid The uid of the package
+ * @param minVersion Minimum app API Version number to enforce location permission
+ * @return boolean true if the SSID/BSSID can be sent to the user, false if they
+ * should be hidden/removed.
+ */
+ public boolean canAccessFullConnectionInfo(@Nullable WifiConfiguration currentConfig,
+ String pkgName, int uid, int minVersion) throws SecurityException {
+ mAppOps.checkPackage(uid, pkgName);
+
+ // The User or profile must be current or the uid must
+ // have INTERACT_ACROSS_USERS_FULL permission.
+ if (!canAccessUserProfile(uid)) {
+ mLog.tC("Denied: Profile not permitted");
+ return false;
+ }
+
+ // If the caller has scan result access then they can also see the full connection info.
+ // Otherwise the caller must be the active use open wifi package and the current config
+ // must be for an open network.
+ return canAccessScanResults(pkgName, uid, minVersion)
+ || isUseOpenWifiPackageWithConnectionInfoAccess(currentConfig, pkgName);
+
+ }
+
+ /**
+ * Returns true if the given WiFi config is for an open network and the package is the active
+ * use open wifi app.
+ */
+ private boolean isUseOpenWifiPackageWithConnectionInfoAccess(
+ @Nullable WifiConfiguration currentConfig, String pkgName) {
+
+ // Access is only granted for open networks.
+ if (currentConfig == null) {
+ mLog.tC("Denied: WifiConfiguration is NULL.");
+ return false;
+ }
+
+ // Access is only granted for open networks.
+ if (!currentConfig.isOpenNetwork()) {
+ mLog.tC("Denied: The current config is not for an open network.");
+ return false;
+ }
+
+ // The USE_OPEN_WIFI_PACKAGE can access the full connection info details without
+ // scan result access.
+ if (!isUseOpenWifiPackage(pkgName)) {
+ mLog.tC("Denied: caller is not the current USE_OPEN_WIFI_PACKAGE");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the User or profile is current or the
+ * uid has the INTERACT_ACROSS_USERS_FULL permission.
+ */
+ private boolean canAccessUserProfile(int uid) {
+ if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Returns true if the caller holds PEERS_MAC_ADDRESS permission.
*/
private boolean checkCallerHasPeersMacAddressPermission(int uid) {
@@ -172,6 +271,43 @@ public class WifiPermissionsUtil {
}
/**
+ * Returns true if the given package is equal to the setting keyed by
+ * {@link Settings.Global#USE_OPEN_WIFI_PACKAGE} and the NetworkScoreManager
+ * has the package name set as the use open wifi package.
+ */
+ private boolean isUseOpenWifiPackage(String packageName) {
+ if (TextUtils.isEmpty(packageName)) {
+ return false;
+ }
+
+ // When the setting is enabled it's set to the package name of the use open wifi app.
+ final String useOpenWifiPkg =
+ mFrameworkFacade.getStringSetting(mContext, Settings.Global.USE_OPEN_WIFI_PACKAGE);
+ if (packageName.equals(useOpenWifiPkg)) {
+ // If the package name matches the setting then also confirm that the scorer is
+ // active and the package matches the expected use open wifi package from the scorer's
+ // perspective. The scorer can be active when the use open wifi feature is off so we
+ // can't rely on this check alone.
+ // TODO(b/67278755): Refactor this into an API similar to isCallerActiveScorer()
+ final NetworkScorerAppData appData;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ appData = mNetworkScoreManager.getActiveScorer();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ if (appData != null) {
+ final ComponentName enableUseOpenWifiActivity =
+ appData.getEnableUseOpenWifiActivity();
+ return enableUseOpenWifiActivity != null
+ && packageName.equals(enableUseOpenWifiActivity.getPackageName());
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Returns true if Wifi scan operation is allowed for this caller
* and package.
*/
@@ -193,19 +329,24 @@ public class WifiPermissionsUtil {
* current user.
*/
private boolean isCurrentProfile(int uid) {
- int currentUser = mWifiPermissionsWrapper.getCurrentUser();
- int callingUserId = mWifiPermissionsWrapper.getCallingUserId(uid);
- if (callingUserId == currentUser) {
- return true;
- } else {
- List<UserInfo> userProfiles = mUserManager.getProfiles(currentUser);
- for (UserInfo user: userProfiles) {
- if (user.id == callingUserId) {
- return true;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ int currentUser = mWifiPermissionsWrapper.getCurrentUser();
+ int callingUserId = mWifiPermissionsWrapper.getCallingUserId(uid);
+ if (callingUserId == currentUser) {
+ return true;
+ } else {
+ List<UserInfo> userProfiles = mUserManager.getProfiles(currentUser);
+ for (UserInfo user : userProfiles) {
+ if (user.id == callingUserId) {
+ return true;
+ }
}
}
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- return false;
}
/**
@@ -237,20 +378,6 @@ public class WifiPermissionsUtil {
return pkgName.equals(mWifiPermissionsWrapper.getTopPkgName());
}
- /**
- * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION
- * and a corresponding app op is allowed for this package and uid.
- */
- private boolean checkCallersLocationPermission(String pkgName, int uid) {
- // Coarse Permission implies Fine permission
- if ((mWifiPermissionsWrapper.getUidPermission(
- Manifest.permission.ACCESS_COARSE_LOCATION, uid)
- == PackageManager.PERMISSION_GRANTED)
- && checkAppOpAllowed(AppOpsManager.OP_COARSE_LOCATION, pkgName, uid)) {
- return true;
- }
- return false;
- }
private boolean isLocationModeEnabled(String pkgName) {
// Location mode check on applications that are later than version.
return (mSettingsStore.getLocationModeSetting(mContext)
diff --git a/service/java/com/android/server/wifi/util/XmlUtil.java b/service/java/com/android/server/wifi/util/XmlUtil.java
index 853136b90..f4c3ab1af 100644
--- a/service/java/com/android/server/wifi/util/XmlUtil.java
+++ b/service/java/com/android/server/wifi/util/XmlUtil.java
@@ -332,6 +332,7 @@ public class XmlUtil {
public static final String XML_TAG_NO_INTERNET_ACCESS_EXPECTED = "NoInternetAccessExpected";
public static final String XML_TAG_USER_APPROVED = "UserApproved";
public static final String XML_TAG_METERED_HINT = "MeteredHint";
+ public static final String XML_TAG_METERED_OVERRIDE = "MeteredOverride";
public static final String XML_TAG_USE_EXTERNAL_SCORES = "UseExternalScores";
public static final String XML_TAG_NUM_ASSOCIATION = "NumAssociation";
public static final String XML_TAG_CREATOR_UID = "CreatorUid";
@@ -445,6 +446,7 @@ public class XmlUtil {
configuration.noInternetAccessExpected);
XmlUtil.writeNextValue(out, XML_TAG_USER_APPROVED, configuration.userApproved);
XmlUtil.writeNextValue(out, XML_TAG_METERED_HINT, configuration.meteredHint);
+ XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
XmlUtil.writeNextValue(
out, XML_TAG_USE_EXTERNAL_SCORES, configuration.useExternalScores);
XmlUtil.writeNextValue(out, XML_TAG_NUM_ASSOCIATION, configuration.numAssociation);
@@ -591,6 +593,9 @@ public class XmlUtil {
case XML_TAG_METERED_HINT:
configuration.meteredHint = (boolean) value;
break;
+ case XML_TAG_METERED_OVERRIDE:
+ configuration.meteredOverride = (int) value;
+ break;
case XML_TAG_USE_EXTERNAL_SCORES:
configuration.useExternalScores = (boolean) value;
break;
diff --git a/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java b/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java
new file mode 100644
index 000000000..f8d2e5202
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 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.*;
+import static org.mockito.Mockito.*;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.EAPConstants;
+import android.net.wifi.WifiEnterpriseConfig;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.CarrierNetworkConfig}.
+ */
+@SmallTest
+public class CarrierNetworkConfigTest {
+ private static final String TEST_SSID = "Test SSID";
+ private static final int TEST_STANDARD_EAP_TYPE = EAPConstants.EAP_SIM;
+ private static final int TEST_INTERNAL_EAP_TYPE = WifiEnterpriseConfig.Eap.SIM;
+ private static final int TEST_SUBSCRIPTION_ID = 1;
+ private static final String TEST_CARRIER_NAME = "Test Carrier";
+ private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
+ new SubscriptionInfo(TEST_SUBSCRIPTION_ID, null, 0, TEST_CARRIER_NAME, null, 0, 0,
+ null, 0, null, 0, 0, null);
+
+ @Mock Context mContext;
+ @Mock CarrierConfigManager mCarrierConfigManager;
+ @Mock SubscriptionManager mSubscriptionManager;
+ BroadcastReceiver mBroadcastReceiver;
+ CarrierNetworkConfig mCarrierNetworkConfig;
+
+ /**
+ * Generate and return a carrier config for testing
+ *
+ * @param ssid The SSID of the carrier network
+ * @param eapType The EAP type of the carrier network
+ * @return {@link PersistableBundle} containing carrier config
+ */
+ private PersistableBundle generateTestConfig(String ssid, int eapType) {
+ PersistableBundle bundle = new PersistableBundle();
+ String networkConfig =
+ new String(Base64.encode(ssid.getBytes(), Base64.DEFAULT)) + "," + eapType;
+ bundle.putStringArray(CarrierConfigManager.KEY_CARRIER_WIFI_STRING_ARRAY,
+ new String[] {networkConfig});
+ return bundle;
+ }
+
+ /**
+ * Method to initialize mocks for tests.
+ */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
+ .thenReturn(mCarrierConfigManager);
+ when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE))
+ .thenReturn(mSubscriptionManager);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUBSCRIPTION_ID))
+ .thenReturn(generateTestConfig(TEST_SSID, TEST_STANDARD_EAP_TYPE));
+ when(mSubscriptionManager.getActiveSubscriptionInfoList())
+ .thenReturn(Arrays.asList(new SubscriptionInfo[] {TEST_SUBSCRIPTION_INFO}));
+ mCarrierNetworkConfig = new CarrierNetworkConfig(mContext);
+ ArgumentCaptor<BroadcastReceiver> receiver =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class));
+ mBroadcastReceiver = receiver.getValue();
+ reset(mCarrierConfigManager);
+ }
+
+ /**
+ * Verify that {@link CarrierNetworkConfig#isCarrierNetwork} will return true and
+ * {@link CarrierNetworkConfig#getNetworkEapType} will return the corresponding EAP type
+ * when the given SSID is associated with a carrier network.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getExistingCarrierNetworkInfo() throws Exception {
+ assertTrue(mCarrierNetworkConfig.isCarrierNetwork(TEST_SSID));
+ assertEquals(TEST_INTERNAL_EAP_TYPE, mCarrierNetworkConfig.getNetworkEapType(TEST_SSID));
+ assertEquals(TEST_CARRIER_NAME, mCarrierNetworkConfig.getCarrierName(TEST_SSID));
+ }
+
+ /**
+ * Verify that {@link CarrierNetworkConfig#isCarrierNetwork} will return false and
+ * {@link CarrierNetworkConfig#getNetworkEapType} will return -1 when the given SSID is not
+ * associated with any carrier network.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getNonCarrierNetworkInfo() throws Exception {
+ String dummySsid = "Dummy SSID";
+ assertFalse(mCarrierNetworkConfig.isCarrierNetwork(dummySsid));
+ assertEquals(-1, mCarrierNetworkConfig.getNetworkEapType(dummySsid));
+ }
+
+ /**
+ * Verify that the carrier network config is updated when
+ * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} intent is received.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void receivedCarrierConfigChangedIntent() throws Exception {
+ String updatedSsid = "Updated SSID";
+ int updatedStandardEapType = EAPConstants.EAP_AKA;
+ int updatedInternalEapType = WifiEnterpriseConfig.Eap.AKA;
+ String updatedCarrierName = "Updated Carrier";
+ SubscriptionInfo updatedSubscriptionInfo = new SubscriptionInfo(TEST_SUBSCRIPTION_ID,
+ null, 0, updatedCarrierName, null, 0, 0, null, 0, null, 0, 0, null);
+ when(mSubscriptionManager.getActiveSubscriptionInfoList())
+ .thenReturn(Arrays.asList(new SubscriptionInfo[] {updatedSubscriptionInfo}));
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUBSCRIPTION_ID))
+ .thenReturn(generateTestConfig(updatedSsid, updatedStandardEapType));
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+
+ // Verify that original SSID no longer associated with a carrier network.
+ assertFalse(mCarrierNetworkConfig.isCarrierNetwork(TEST_SSID));
+ assertEquals(-1, mCarrierNetworkConfig.getNetworkEapType(TEST_SSID));
+ assertEquals(null, mCarrierNetworkConfig.getCarrierName(TEST_SSID));
+
+ // Verify that updated SSID is associated with a carrier network.
+ assertTrue(mCarrierNetworkConfig.isCarrierNetwork(updatedSsid));
+ assertEquals(updatedInternalEapType, mCarrierNetworkConfig.getNetworkEapType(updatedSsid));
+ assertEquals(updatedCarrierName, mCarrierNetworkConfig.getCarrierName(updatedSsid));
+ }
+
+ /**
+ * Verify that the carrier network config is not updated when non
+ * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} intent is received.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void receivedNonCarrierConfigChangedIntent() throws Exception {
+ mBroadcastReceiver.onReceive(mContext, new Intent("dummyIntent"));
+ verify(mCarrierConfigManager, never()).getConfig();
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
index 01257c16e..19a92b8e4 100644
--- a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
@@ -16,9 +16,13 @@
package com.android.server.wifi;
+import static android.os.Process.SYSTEM_UID;
+
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
import android.test.suitebuilder.annotation.SmallTest;
@@ -29,6 +33,8 @@ import com.android.server.wifi.util.XmlUtilTest;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -49,6 +55,7 @@ public class NetworkListStoreDataTest {
private static final String TEST_SSID = "WifiConfigStoreDataSSID_";
private static final String TEST_CONNECT_CHOICE = "XmlUtilConnectChoice";
private static final long TEST_CONNECT_CHOICE_TIMESTAMP = 0x4566;
+ private static final String TEST_CREATOR_NAME = "CreatorName";
private static final String SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT =
"<Network>\n"
+ "<WifiConfiguration>\n"
@@ -75,10 +82,11 @@ public class NetworkListStoreDataTest {
+ "<boolean name=\"NoInternetAccessExpected\" value=\"false\" />\n"
+ "<int name=\"UserApproved\" value=\"0\" />\n"
+ "<boolean name=\"MeteredHint\" value=\"false\" />\n"
+ + "<int name=\"MeteredOverride\" value=\"0\" />\n"
+ "<boolean name=\"UseExternalScores\" value=\"false\" />\n"
+ "<int name=\"NumAssociation\" value=\"0\" />\n"
+ "<int name=\"CreatorUid\" value=\"%d\" />\n"
- + "<null name=\"CreatorName\" />\n"
+ + "<string name=\"CreatorName\">%s</string>\n"
+ "<null name=\"CreationTime\" />\n"
+ "<int name=\"LastUpdateUid\" value=\"-1\" />\n"
+ "<null name=\"LastUpdateName\" />\n"
@@ -125,10 +133,11 @@ public class NetworkListStoreDataTest {
+ "<boolean name=\"NoInternetAccessExpected\" value=\"false\" />\n"
+ "<int name=\"UserApproved\" value=\"0\" />\n"
+ "<boolean name=\"MeteredHint\" value=\"false\" />\n"
+ + "<int name=\"MeteredOverride\" value=\"0\" />\n"
+ "<boolean name=\"UseExternalScores\" value=\"false\" />\n"
+ "<int name=\"NumAssociation\" value=\"0\" />\n"
+ "<int name=\"CreatorUid\" value=\"%d\" />\n"
- + "<null name=\"CreatorName\" />\n"
+ + "<string name=\"CreatorName\">%s</string>\n"
+ "<null name=\"CreationTime\" />\n"
+ "<int name=\"LastUpdateUid\" value=\"-1\" />\n"
+ "<null name=\"LastUpdateName\" />\n"
@@ -168,10 +177,15 @@ public class NetworkListStoreDataTest {
+ "</Network>\n";
private NetworkListStoreData mNetworkListStoreData;
+ @Mock private Context mContext;
+ @Mock private PackageManager mPackageManager;
@Before
public void setUp() throws Exception {
- mNetworkListStoreData = new NetworkListStoreData();
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME);
+ mNetworkListStoreData = new NetworkListStoreData(mContext);
}
/**
@@ -219,11 +233,13 @@ public class NetworkListStoreDataTest {
*/
private List<WifiConfiguration> getTestNetworksConfig(boolean shared) {
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
+ openNetwork.creatorName = TEST_CREATOR_NAME;
openNetwork.shared = shared;
openNetwork.setIpConfiguration(
WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
WifiConfiguration eapNetwork = WifiConfigurationTestUtil.createEapNetwork();
eapNetwork.shared = shared;
+ eapNetwork.creatorName = TEST_CREATOR_NAME;
eapNetwork.setIpConfiguration(
WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
List<WifiConfiguration> networkList = new ArrayList<>();
@@ -245,11 +261,11 @@ public class NetworkListStoreDataTest {
String openNetworkXml = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT,
openNetwork.configKey().replaceAll("\"", "&quot;"),
openNetwork.SSID.replaceAll("\"", "&quot;"),
- openNetwork.shared, openNetwork.creatorUid);
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName);
String eapNetworkXml = String.format(SINGLE_EAP_NETWORK_DATA_XML_STRING_FORMAT,
eapNetwork.configKey().replaceAll("\"", "&quot;"),
eapNetwork.SSID.replaceAll("\"", "&quot;"),
- eapNetwork.shared, eapNetwork.creatorUid);
+ eapNetwork.shared, eapNetwork.creatorUid, openNetwork.creatorName);
return (openNetworkXml + eapNetworkXml).getBytes(StandardCharsets.UTF_8);
}
@@ -418,7 +434,8 @@ public class NetworkListStoreDataTest {
byte[] xmlData = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT,
"InvalidConfigKey",
openNetwork.SSID.replaceAll("\"", "&quot;"),
- openNetwork.shared, openNetwork.creatorUid).getBytes(StandardCharsets.UTF_8);
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName)
+ .getBytes(StandardCharsets.UTF_8);
deserializeData(xmlData, true);
}
@@ -446,4 +463,96 @@ public class NetworkListStoreDataTest {
assertNotEquals(eapNetwork.SSID, network.SSID);
}
}
+
+ /**
+ * Verify that a saved network config with invalid creatorUid resets it to
+ * {@link android.os.Process#SYSTEM_UID}.
+ */
+ public void parseNetworkWithInvalidCreatorUidResetsToSystem() throws Exception {
+ WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
+ openNetwork.creatorUid = -1;
+ // Return null for invalid uid.
+ when(mPackageManager.getNameForUid(eq(openNetwork.creatorUid))).thenReturn(null);
+
+ byte[] xmlData = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT,
+ openNetwork.configKey().replaceAll("\"", "&quot;"),
+ openNetwork.SSID.replaceAll("\"", "&quot;"),
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName)
+ .getBytes(StandardCharsets.UTF_8);
+ List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true);
+ assertEquals(1, deserializedNetworks.size());
+ assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey());
+ assertEquals(SYSTEM_UID, deserializedNetworks.get(0).creatorUid);
+ assertEquals(TEST_CREATOR_NAME, deserializedNetworks.get(0).creatorName);
+ }
+
+ /**
+ * Verify that a saved network config with invalid creatorName resets it to the package name
+ * provided {@link PackageManager} for the creatorUid.
+ */
+ public void parseNetworkWithInvalidCreatorNameResetsToPackageNameForCreatorUid()
+ throws Exception {
+ String badCreatorName = "bad";
+ String correctCreatorName = "correct";
+ WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
+ openNetwork.creatorUid = 1324422;
+ openNetwork.creatorName = badCreatorName;
+ when(mPackageManager.getNameForUid(eq(openNetwork.creatorUid)))
+ .thenReturn(correctCreatorName);
+
+ byte[] xmlData = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT,
+ openNetwork.configKey().replaceAll("\"", "&quot;"),
+ openNetwork.SSID.replaceAll("\"", "&quot;"),
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName)
+ .getBytes(StandardCharsets.UTF_8);
+ List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true);
+ assertEquals(1, deserializedNetworks.size());
+ assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey());
+ assertEquals(openNetwork.creatorUid, deserializedNetworks.get(0).creatorUid);
+ assertEquals(correctCreatorName, deserializedNetworks.get(0).creatorName);
+ }
+
+ /**
+ * Verify that a saved network config with invalid creatorName resets it to the package name
+ * provided {@link PackageManager} for the creatorUid.
+ */
+ public void parseNetworkWithNullCreatorNameResetsToPackageNameForCreatorUid()
+ throws Exception {
+ String correctCreatorName = "correct";
+ WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
+ openNetwork.creatorUid = 1324422;
+ openNetwork.creatorName = null;
+ when(mPackageManager.getNameForUid(eq(openNetwork.creatorUid)))
+ .thenReturn(correctCreatorName);
+
+ byte[] xmlData = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT,
+ openNetwork.configKey().replaceAll("\"", "&quot;"),
+ openNetwork.SSID.replaceAll("\"", "&quot;"),
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName)
+ .getBytes(StandardCharsets.UTF_8);
+ List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true);
+ assertEquals(1, deserializedNetworks.size());
+ assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey());
+ assertEquals(openNetwork.creatorUid, deserializedNetworks.get(0).creatorUid);
+ assertEquals(correctCreatorName, deserializedNetworks.get(0).creatorName);
+ }
+
+ /**
+ * Verify that a saved network config with valid creatorUid is preserved.
+ */
+ public void parseNetworkWithValidCreatorUid() throws Exception {
+ WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
+ openNetwork.creatorUid = 1324422;
+
+ byte[] xmlData = String.format(SINGLE_OPEN_NETWORK_DATA_XML_STRING_FORMAT,
+ openNetwork.configKey().replaceAll("\"", "&quot;"),
+ openNetwork.SSID.replaceAll("\"", "&quot;"),
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName)
+ .getBytes(StandardCharsets.UTF_8);
+ List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true);
+ assertEquals(1, deserializedNetworks.size());
+ assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey());
+ assertEquals(openNetwork.creatorUid, deserializedNetworks.get(0).creatorUid);
+ assertEquals(TEST_CREATOR_NAME, deserializedNetworks.get(0).creatorName);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java
new file mode 100644
index 000000000..5a0b011f2
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2016 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 com.android.server.wifi.OpenNetworkNotifier.DEFAULT_REPEAT_DELAY_SEC;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.util.ArraySet;
+
+import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link OpenNetworkNotifier}.
+ */
+public class OpenNetworkNotifierTest {
+
+ private static final String TEST_SSID_1 = "Test SSID 1";
+ private static final String TEST_SSID_2 = "Test SSID 2";
+ private static final int MIN_RSSI_LEVEL = -127;
+
+ @Mock private Context mContext;
+ @Mock private Resources mResources;
+ @Mock private FrameworkFacade mFrameworkFacade;
+ @Mock private WifiMetrics mWifiMetrics;
+ @Mock private Clock mClock;
+ @Mock private WifiConfigStore mWifiConfigStore;
+ @Mock private WifiConfigManager mWifiConfigManager;
+ @Mock private NotificationManager mNotificationManager;
+ @Mock private WifiStateMachine mWifiStateMachine;
+ @Mock private OpenNetworkRecommender mOpenNetworkRecommender;
+ @Mock private ConnectToNetworkNotificationBuilder mNotificationBuilder;
+ @Mock private UserManager mUserManager;
+ private OpenNetworkNotifier mNotificationController;
+ private TestLooper mLooper;
+ private BroadcastReceiver mBroadcastReceiver;
+ private ContentObserver mContentObserver;
+ private ScanResult mDummyNetwork;
+ private List<ScanDetail> mOpenNetworks;
+ private Set<String> mBlacklistedSsids;
+
+
+ /** Initialize objects before each test run. */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .thenReturn(mNotificationManager);
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1)).thenReturn(1);
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, DEFAULT_REPEAT_DELAY_SEC))
+ .thenReturn(DEFAULT_REPEAT_DELAY_SEC);
+ when(mContext.getSystemService(Context.USER_SERVICE))
+ .thenReturn(mUserManager);
+ when(mContext.getResources()).thenReturn(mResources);
+ mDummyNetwork = new ScanResult();
+ mDummyNetwork.SSID = TEST_SSID_1;
+ mDummyNetwork.capabilities = "[ESS]";
+ mDummyNetwork.level = MIN_RSSI_LEVEL;
+ when(mOpenNetworkRecommender.recommendNetwork(any(), any())).thenReturn(mDummyNetwork);
+ mOpenNetworks = new ArrayList<>();
+ mOpenNetworks.add(new ScanDetail(mDummyNetwork, null /* networkDetail */));
+ mBlacklistedSsids = new ArraySet<>();
+
+ mLooper = new TestLooper();
+ mNotificationController = new OpenNetworkNotifier(
+ mContext, mLooper.getLooper(), mFrameworkFacade, mClock, mWifiMetrics,
+ mWifiConfigManager, mWifiConfigStore, mWifiStateMachine, mOpenNetworkRecommender,
+ mNotificationBuilder);
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
+ mBroadcastReceiver = broadcastReceiverCaptor.getValue();
+ ArgumentCaptor<ContentObserver> observerCaptor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mFrameworkFacade).registerContentObserver(eq(mContext), any(Uri.class), eq(true),
+ observerCaptor.capture());
+ mContentObserver = observerCaptor.getValue();
+ mNotificationController.handleScreenStateChanged(true);
+ }
+
+ /**
+ * On {@link OpenNetworkNotifier} construction, WifiMetrics should track setting state.
+ */
+ @Test
+ public void onCreate_setWifiNetworksAvailableNotificationSettingState() {
+ verify(mWifiMetrics).setIsWifiNetworksAvailableNotificationEnabled(true);
+ }
+
+ /**
+ * When feature setting is toggled, WifiMetrics should track the disabled setting state.
+ */
+ @Test
+ public void onFeatureDisable_setWifiNetworksAvailableNotificationSettingDisabled() {
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1)).thenReturn(0);
+ mContentObserver.onChange(false);
+
+ verify(mWifiMetrics).setIsWifiNetworksAvailableNotificationEnabled(false);
+ }
+
+ /**
+ * When scan results with open networks are handled, a notification is posted.
+ */
+ @Test
+ public void handleScanResults_hasOpenNetworks_notificationDisplayed() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+ }
+
+ /**
+ * When scan results with no open networks are handled, a notification is not posted.
+ */
+ @Test
+ public void handleScanResults_emptyList_notificationNotDisplayed() {
+ mNotificationController.handleScanResults(new ArrayList<>());
+
+ verify(mOpenNetworkRecommender, never()).recommendNetwork(any(), any());
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ }
+
+ /**
+ * When the feature is disabled, no notifications are posted.
+ */
+ @Test
+ public void handleScanResults_featureDisabled_notificationNotDisplayed() {
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1)).thenReturn(0);
+ mContentObserver.onChange(false);
+ mNotificationController.handleScanResults(new ArrayList<>());
+
+ verify(mOpenNetworkRecommender, never()).recommendNetwork(any(), any());
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ }
+
+ /**
+ * When a notification is showing and scan results with no open networks are handled, the
+ * notification is cleared.
+ */
+ @Test
+ public void handleScanResults_notificationShown_emptyList_notificationCleared() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.handleScanResults(new ArrayList<>());
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * When a notification is showing and no recommendation is made for the new scan results, the
+ * notification is cleared.
+ */
+ @Test
+ public void handleScanResults_notificationShown_noRecommendation_notificationCleared() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ when(mOpenNetworkRecommender.recommendNetwork(any(), any())).thenReturn(null);
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * When a notification is showing, screen is off, and scan results with no open networks are
+ * handled, the notification is cleared.
+ */
+ @Test
+ public void handleScanResults_notificationShown_screenOff_emptyList_notificationCleared() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.handleScreenStateChanged(false);
+ mNotificationController.handleScanResults(new ArrayList<>());
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * When {@link OpenNetworkNotifier#clearPendingNotification(boolean)} is called and a
+ * notification is shown, clear the notification.
+ */
+ @Test
+ public void clearPendingNotification_clearsNotificationIfOneIsShowing() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(true);
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * When {@link OpenNetworkNotifier#clearPendingNotification(boolean)} is called and a
+ * notification was not previously shown, do not clear the notification.
+ */
+ @Test
+ public void clearPendingNotification_doesNotClearNotificationIfNoneShowing() {
+ mNotificationController.clearPendingNotification(true);
+
+ verify(mNotificationManager, never()).cancel(anyInt());
+ }
+
+ /**
+ * When screen is off and notification is not displayed, notification is not posted on handling
+ * new scan results with open networks.
+ */
+ @Test
+ public void screenOff_notificationNotShowing_handleScanResults_notificationNotDisplayed() {
+ mNotificationController.handleScreenStateChanged(false);
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender, never()).recommendNetwork(any(), any());
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ }
+
+ /**
+ * When screen is off and notification is displayed, the notification can be updated with a new
+ * recommendation.
+ */
+ @Test
+ public void screenOff_notificationShowing_handleScanResults_recommendationCanBeUpdated() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ ScanResult newNetwork = new ScanResult();
+ newNetwork.SSID = TEST_SSID_2;
+ mDummyNetwork.capabilities = "[ESS]";
+ mDummyNetwork.level = MIN_RSSI_LEVEL;
+ mOpenNetworks.add(new ScanDetail(newNetwork, null /* networkDetail */));
+ when(mOpenNetworkRecommender.recommendNetwork(any(), any())).thenReturn(newNetwork);
+
+ mNotificationController.handleScreenStateChanged(false);
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ // Recommendation changed
+ verify(mOpenNetworkRecommender, times(2)).recommendNetwork(
+ mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(newNetwork);
+ verify(mWifiMetrics).incrementNumOpenNetworkRecommendationUpdates();
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+ }
+
+ /**
+ * When a notification is posted and cleared without resetting delay, the next scan with open
+ * networks should not post another notification.
+ */
+ @Test
+ public void postNotification_clearNotificationWithoutDelayReset_shouldNotPostNotification() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(false);
+
+ verify(mNotificationManager).cancel(anyInt());
+
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ // no new notification posted
+ verify(mNotificationManager).notify(anyInt(), any());
+ }
+
+ /**
+ * When a notification is posted and cleared without resetting delay, the next scan with open
+ * networks should post a notification.
+ */
+ @Test
+ public void postNotification_clearNotificationWithDelayReset_shouldPostNotification() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(true);
+
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender, times(2)).recommendNetwork(
+ mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder, times(2)).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics, times(2)).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+ }
+
+ /**
+ * When user dismissed notification and there is a recommended network, network ssid should be
+ * blacklisted.
+ */
+ @Test
+ public void userDismissedNotification_shouldBlacklistNetwork() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(
+ mContext,
+ new Intent(ConnectToNetworkNotificationBuilder.ACTION_USER_DISMISSED_NOTIFICATION));
+
+ verify(mWifiConfigManager).saveToStore(false /* forceWrite */);
+
+ mNotificationController.clearPendingNotification(true);
+ List<ScanDetail> scanResults = mOpenNetworks;
+ mNotificationController.handleScanResults(scanResults);
+
+ Set<String> expectedBlacklist = new ArraySet<>();
+ expectedBlacklist.add(mDummyNetwork.SSID);
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, expectedBlacklist);
+ verify(mWifiMetrics).setOpenNetworkRecommenderBlacklistSize(expectedBlacklist.size());
+ }
+
+ /**
+ * When a notification is posted and cleared without resetting delay, after the delay has passed
+ * the next scan with open networks should post a notification.
+ */
+ @Test
+ public void delaySet_delayPassed_shouldPostNotification() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(false);
+
+ // twice the delay time passed
+ when(mClock.getWallClockMillis()).thenReturn(DEFAULT_REPEAT_DELAY_SEC * 1000L * 2);
+
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender, times(2)).recommendNetwork(
+ mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder, times(2)).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics, times(2)).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+ }
+
+ /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} disables the feature. */
+ @Test
+ public void userHasDisallowConfigWifiRestriction_notificationNotDisplayed() {
+ when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
+ .thenReturn(true);
+
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender, never()).recommendNetwork(any(), any());
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ }
+
+ /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} clears the showing notification. */
+ @Test
+ public void userHasDisallowConfigWifiRestriction_showingNotificationIsCleared() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
+ .thenReturn(true);
+
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * {@link ConnectToNetworkNotificationBuilder#ACTION_CONNECT_TO_NETWORK} does not connect to
+ * any network if the initial notification is not showing.
+ */
+ @Test
+ public void actionConnectToNetwork_notificationNotShowing_doesNothing() {
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK));
+
+ verify(mWifiStateMachine, never()).sendMessage(any(Message.class));
+ }
+
+ /**
+ * {@link ConnectToNetworkNotificationBuilder#ACTION_CONNECT_TO_NETWORK} connects to the
+ * currently recommended network if it exists.
+ */
+ @Test
+ public void actionConnectToNetwork_currentRecommendationExists_connectsAndPostsNotification() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ // Initial Notification
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK));
+
+ verify(mWifiStateMachine).sendMessage(any(Message.class));
+ // Connecting Notification
+ verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTING_TO_NETWORK);
+ verify(mWifiMetrics).incrementConnectToNetworkNotificationAction(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK,
+ ConnectToNetworkNotificationAndActionCount.ACTION_CONNECT_TO_NETWORK);
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+ }
+
+ /**
+ * {@link ConnectToNetworkNotificationBuilder#ACTION_PICK_WIFI_NETWORK} opens Wi-Fi settings
+ * if the recommendation notification is showing.
+ */
+ @Test
+ public void actionPickWifiNetwork_currentRecommendationExists_opensWifiSettings() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ // Initial Notification
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK));
+
+ ArgumentCaptor<Intent> pickerIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).startActivity(pickerIntentCaptor.capture());
+ assertEquals(pickerIntentCaptor.getValue().getAction(), Settings.ACTION_WIFI_SETTINGS);
+ verify(mWifiMetrics).incrementConnectToNetworkNotificationAction(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK,
+ ConnectToNetworkNotificationAndActionCount.ACTION_PICK_WIFI_NETWORK);
+ }
+
+ /**
+ * {@link OpenNetworkNotifier#handleWifiConnected()} does not post connected notification if
+ * the connecting notification is not showing
+ */
+ @Test
+ public void networkConnectionSuccess_wasNotInConnectingFlow_doesNothing() {
+ mNotificationController.handleWifiConnected();
+
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ verify(mWifiMetrics, never()).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTED_TO_NETWORK);
+ }
+
+ /**
+ * {@link OpenNetworkNotifier#handleWifiConnected()} clears notification that is not connecting.
+ */
+ @Test
+ public void networkConnectionSuccess_wasShowingNotification_clearsNotification() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ // Initial Notification
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.handleWifiConnected();
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * {@link OpenNetworkNotifier#handleWifiConnected()} posts the connected notification if
+ * the connecting notification is showing.
+ */
+ @Test
+ public void networkConnectionSuccess_wasInConnectingFlow_postsConnectedNotification() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ // Initial Notification
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK));
+
+ // Connecting Notification
+ verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTING_TO_NETWORK);
+ verify(mWifiMetrics).incrementConnectToNetworkNotificationAction(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK,
+ ConnectToNetworkNotificationAndActionCount.ACTION_CONNECT_TO_NETWORK);
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+
+ mNotificationController.handleWifiConnected();
+
+ // Connected Notification
+ verify(mNotificationBuilder).createNetworkConnectedNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTED_TO_NETWORK);
+ verify(mNotificationManager, times(3)).notify(anyInt(), any());
+ }
+
+ /**
+ * {@link OpenNetworkNotifier#handleConnectionFailure()} posts the Failed to Connect
+ * notification if the connecting notification is showing.
+ */
+ @Test
+ public void networkConnectionFailure_wasNotInConnectingFlow_doesNothing() {
+ mNotificationController.handleConnectionFailure();
+
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ verify(mWifiMetrics, never()).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_FAILED_TO_CONNECT);
+ }
+
+ /**
+ * {@link OpenNetworkNotifier#handleConnectionFailure()} posts the Failed to Connect
+ * notification if the connecting notification is showing.
+ */
+ @Test
+ public void networkConnectionFailure_wasInConnectingFlow_postsFailedToConnectNotification() {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ // Initial Notification
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK));
+
+ // Connecting Notification
+ verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTING_TO_NETWORK);
+ verify(mWifiMetrics).incrementConnectToNetworkNotificationAction(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK,
+ ConnectToNetworkNotificationAndActionCount.ACTION_CONNECT_TO_NETWORK);
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+
+ mNotificationController.handleConnectionFailure();
+
+ // Failed to Connect Notification
+ verify(mNotificationBuilder).createNetworkFailedNotification();
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_FAILED_TO_CONNECT);
+ verify(mNotificationManager, times(3)).notify(anyInt(), any());
+ }
+
+ /**
+ * When a {@link WifiManager#CONNECT_NETWORK_FAILED} is received from the connection callback
+ * of {@link WifiStateMachine#sendMessage(Message)}, a Failed to Connect notification should
+ * be posted. On tapping this notification, Wi-Fi Settings should be launched.
+ */
+ @Test
+ public void connectionFailedCallback_postsFailedToConnectNotification() throws RemoteException {
+ mNotificationController.handleScanResults(mOpenNetworks);
+
+ verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+ // Initial Notification
+ verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK);
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK));
+
+ ArgumentCaptor<Message> connectMessageCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mWifiStateMachine).sendMessage(connectMessageCaptor.capture());
+ Message connectMessage = connectMessageCaptor.getValue();
+
+ // Connecting Notification
+ verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork);
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTING_TO_NETWORK);
+ verify(mWifiMetrics).incrementConnectToNetworkNotificationAction(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK,
+ ConnectToNetworkNotificationAndActionCount.ACTION_CONNECT_TO_NETWORK);
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+
+ Message connectFailedMsg = Message.obtain();
+ connectFailedMsg.what = WifiManager.CONNECT_NETWORK_FAILED;
+ connectMessage.replyTo.send(connectFailedMsg);
+ mLooper.dispatchAll();
+
+ // Failed to Connect Notification
+ verify(mNotificationBuilder).createNetworkFailedNotification();
+ verify(mWifiMetrics).incrementConnectToNetworkNotification(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_FAILED_TO_CONNECT);
+ verify(mWifiMetrics).incrementNumOpenNetworkConnectMessageFailedToSend();
+ verify(mNotificationManager, times(3)).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(mContext,
+ new Intent(ConnectToNetworkNotificationBuilder
+ .ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE));
+
+ ArgumentCaptor<Intent> pickerIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).startActivity(pickerIntentCaptor.capture());
+ assertEquals(pickerIntentCaptor.getValue().getAction(), Settings.ACTION_WIFI_SETTINGS);
+ verify(mWifiMetrics).incrementConnectToNetworkNotificationAction(
+ ConnectToNetworkNotificationAndActionCount.NOTIFICATION_FAILED_TO_CONNECT,
+ ConnectToNetworkNotificationAndActionCount
+ .ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java b/tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java
new file mode 100644
index 000000000..720ec3797
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 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.junit.Assert.assertNull;
+
+import android.net.wifi.ScanResult;
+import android.util.ArraySet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for {@link OpenNetworkRecommender}.
+ */
+public class OpenNetworkRecommenderTest {
+
+ private static final String TEST_SSID_1 = "Test SSID 1";
+ private static final String TEST_SSID_2 = "Test SSID 2";
+ private static final int MIN_RSSI_LEVEL = -127;
+
+ private OpenNetworkRecommender mOpenNetworkRecommender;
+ private Set<String> mBlacklistedSsids;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mOpenNetworkRecommender = new OpenNetworkRecommender();
+ mBlacklistedSsids = new ArraySet<>();
+ }
+
+ private List<ScanDetail> createOpenScanResults(String... ssids) {
+ List<ScanDetail> scanResults = new ArrayList<>();
+ for (String ssid : ssids) {
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = ssid;
+ scanResult.capabilities = "[ESS]";
+ scanResults.add(new ScanDetail(scanResult, null /* networkDetail */));
+ }
+ return scanResults;
+ }
+
+ /** If list of open networks contain only one network, that network should be returned. */
+ @Test
+ public void onlyNetworkIsRecommended() {
+ List<ScanDetail> scanResults = createOpenScanResults(TEST_SSID_1);
+ scanResults.get(0).getScanResult().level = MIN_RSSI_LEVEL;
+
+ ScanResult actual = mOpenNetworkRecommender.recommendNetwork(
+ scanResults, mBlacklistedSsids);
+ ScanResult expected = scanResults.get(0).getScanResult();
+ assertEquals(expected, actual);
+ }
+
+ /** Verifies that the network with the highest rssi is recommended. */
+ @Test
+ public void networkWithHighestRssiIsRecommended() {
+ List<ScanDetail> scanResults = createOpenScanResults(TEST_SSID_1, TEST_SSID_2);
+ scanResults.get(0).getScanResult().level = MIN_RSSI_LEVEL;
+ scanResults.get(1).getScanResult().level = MIN_RSSI_LEVEL + 1;
+
+ ScanResult actual = mOpenNetworkRecommender.recommendNetwork(
+ scanResults, mBlacklistedSsids);
+ ScanResult expected = scanResults.get(1).getScanResult();
+ assertEquals(expected, actual);
+ }
+
+ /**
+ * If the best available open network is blacklisted, no networks should be recommended.
+ */
+ @Test
+ public void blacklistBestNetworkSsid_shouldNeverRecommendNetwork() {
+ List<ScanDetail> scanResults = createOpenScanResults(TEST_SSID_1, TEST_SSID_2);
+ scanResults.get(0).getScanResult().level = MIN_RSSI_LEVEL + 1;
+ scanResults.get(1).getScanResult().level = MIN_RSSI_LEVEL;
+ mBlacklistedSsids.add(TEST_SSID_1);
+
+ ScanResult actual = mOpenNetworkRecommender.recommendNetwork(
+ scanResults, mBlacklistedSsids);
+ assertNull(actual);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/RttServiceTest.java b/tests/wifitests/src/com/android/server/wifi/RttServiceTest.java
index 689ade80a..7300cb256 100644
--- a/tests/wifitests/src/com/android/server/wifi/RttServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/RttServiceTest.java
@@ -41,6 +41,7 @@ import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.util.test.BidirectionalAsyncChannel;
+import com.android.server.wifi.util.WifiPermissionsUtil;
import org.junit.After;
import org.junit.Before;
@@ -69,6 +70,8 @@ public class RttServiceTest {
WifiInjector mWifiInjector;
@Mock
IWificond mWificond;
+ @Mock
+ WifiPermissionsUtil mWifiPermissionsUtil;
RttService.RttServiceImpl mRttServiceImpl;
ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor = ArgumentCaptor
@@ -80,6 +83,9 @@ public class RttServiceTest {
mLooper = new TestLooper();
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
+ when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil);
+ when(mWifiPermissionsUtil.checkCallersLocationPermission(any(), anyInt()))
+ .thenReturn(true);
mRttServiceImpl = new RttService.RttServiceImpl(mContext, mLooper.getLooper(),
mWifiInjector);
mRttServiceImpl.startService();
@@ -100,7 +106,7 @@ public class RttServiceTest {
// Create and connect a bi-directional async channel.
private BidirectionalAsyncChannel connectChannel(Handler handler) {
BidirectionalAsyncChannel channel = new BidirectionalAsyncChannel();
- channel.connect(mLooper.getLooper(), mRttServiceImpl.getMessenger(),
+ channel.connect(mLooper.getLooper(), mRttServiceImpl.getMessenger(null, new int[1]),
handler);
mLooper.dispatchAll();
channel.assertConnected();
@@ -271,6 +277,22 @@ public class RttServiceTest {
}
/**
+ * Test RTT fails without proper location permission
+ */
+ @Test
+ public void testEnableResponderFailureNoPermission() throws Exception {
+ when(mWifiPermissionsUtil.checkCallersLocationPermission(any(), anyInt()))
+ .thenReturn(false);
+ startWifi();
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel channel = connectChannel(handler);
+ Message message = sendEnableResponder(channel, handler, CLIENT_KEY1, null);
+ // RTT operations failed without proper permission.
+ assertEquals("expected permission denied, but got " + message.what,
+ RttManager.REASON_PERMISSION_DENIED, message.arg1);
+ }
+
+ /**
* Test RTT ranging with empty RttParams.
*/
@Test
diff --git a/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java
new file mode 100644
index 000000000..606b825ee
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 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.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+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.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.SsidSetStoreData}.
+ */
+public class SsidSetStoreDataTest {
+ private static final String TEST_NOTIFIER_NAME = "TestNetwork";
+ private static final String TEST_SSID1 = "SSID 1";
+ private static final String TEST_SSID2 = "SSID 2";
+ private static final String TEST_SSID_SET_XML_STRING =
+ "<set name=\"SSIDSet\">\n"
+ + "<string>" + TEST_SSID1 + "</string>\n"
+ + "<string>" + TEST_SSID2 + "</string>\n"
+ + "</set>\n";
+ private static final byte[] TEST_SSID_SET_XML_BYTES =
+ TEST_SSID_SET_XML_STRING.getBytes(StandardCharsets.UTF_8);
+
+ @Mock SsidSetStoreData.DataSource mDataSource;
+ SsidSetStoreData mSsidSetStoreData;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mSsidSetStoreData = new SsidSetStoreData(TEST_NOTIFIER_NAME, mDataSource);
+ }
+
+ /**
+ * Helper function for serializing configuration data to a XML block.
+ *
+ * @param shared Flag indicating serializing shared or user configurations
+ * @return byte[] of the XML data
+ * @throws Exception
+ */
+ private byte[] serializeData(boolean shared) throws Exception {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ mSsidSetStoreData.serializeData(out, shared);
+ out.flush();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Helper function for parsing configuration data from a XML block.
+ *
+ * @param data XML data to parse from
+ * @param shared Flag indicating parsing of shared or user configurations
+ * @throws Exception
+ */
+ private void deserializeData(byte[] data, boolean shared) throws Exception {
+ final XmlPullParser in = Xml.newPullParser();
+ final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ in.setInput(inputStream, StandardCharsets.UTF_8.name());
+ mSsidSetStoreData.deserializeData(in, in.getDepth(), shared);
+ }
+
+ /**
+ * Verify that a XmlPullParserException will be thrown when attempting to serialize data
+ * to the share store.
+ *
+ * @throws Exception
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void serializeShareData() throws Exception {
+ serializeData(true /* shared */);
+ }
+
+ /**
+ * Verify that a XmlPullParserException will be thrown when attempting to deserialize
+ * data from the share store.
+ *
+ * @throws Exception
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void deserializeShareData() throws Exception {
+ deserializeData(new byte[0], true /* shared */);
+ }
+
+ /**
+ * Verify that serializing the user store data without any configuration doesn't cause any
+ * crash and no data should be serialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void serializeEmptyConfigs() throws Exception {
+ when(mDataSource.getSsids()).thenReturn(new HashSet<String>());
+ assertEquals(0, serializeData(false /* shared */).length);
+ }
+
+ /**
+ * Verify that parsing an empty data doesn't cause any crash and no configuration should
+ * be deserialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void deserializeEmptyStoreData() throws Exception {
+ deserializeData(new byte[0], false /* shared */);
+ verify(mDataSource, never()).setSsids(any(Set.class));
+ }
+
+ /**
+ * Verify that {@link SsidSetStoreData} does not support share data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void supportShareData() throws Exception {
+ assertFalse(mSsidSetStoreData.supportShareData());
+ }
+
+ /**
+ * Verify that the store data is serialized correctly, matches the predefined test XML data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void serializeSsidSet() throws Exception {
+ Set<String> ssidSet = new HashSet<>();
+ ssidSet.add(TEST_SSID1);
+ ssidSet.add(TEST_SSID2);
+ when(mDataSource.getSsids()).thenReturn(ssidSet);
+ byte[] actualData = serializeData(false /* shared */);
+ assertTrue(Arrays.equals(TEST_SSID_SET_XML_BYTES, actualData));
+ }
+
+ /**
+ * Verify that the store data is deserialized correctly using the predefined test XML data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void deserializeSsidSet() throws Exception {
+ Set<String> ssidSet = new HashSet<>();
+ ssidSet.add(TEST_SSID1);
+ ssidSet.add(TEST_SSID2);
+ deserializeData(TEST_SSID_SET_XML_BYTES, false /* shared */);
+ verify(mDataSource).setSsids(eq(ssidSet));
+ }
+
+ /**
+ * Verify that a XmlPullParserException will be thrown when parsing a SSIDSet set with an
+ * unknown tag.
+ *
+ * @throws Exception
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void parseSetWithUnknownTag() throws Exception {
+ String ssidSet =
+ "<set name=\"SSIDSet\">\n"
+ + "<string>" + TEST_SSID1 + "</string>\n"
+ + "<string>" + TEST_SSID2 + "</string>\n"
+ + "<Unknown>" + "badInput" + "</Unknown>" // Unknown tag.
+ + "</set>\n";
+ deserializeData(ssidSet.getBytes(StandardCharsets.UTF_8), false /* shared */);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
index 02064d87e..a923475f1 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
@@ -268,7 +268,9 @@ public class WifiApConfigStoreTest {
assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
// now check a valid SSID with a random length
- config.SSID = generateRandomString(mRandom.nextInt(WifiApConfigStore.SSID_MAX_LEN + 1));
+ int validLength = WifiApConfigStore.SSID_MAX_LEN - WifiApConfigStore.SSID_MIN_LEN;
+ config.SSID = generateRandomString(
+ mRandom.nextInt(validLength) + WifiApConfigStore.SSID_MIN_LEN);
assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index 7509c18b3..0fa660081 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -43,7 +43,6 @@ import android.text.TextUtils;
import android.util.Pair;
import com.android.internal.R;
-import com.android.server.wifi.WifiConfigStoreLegacy.WifiConfigStoreDataLegacy;
import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.server.wifi.util.WifiPermissionsWrapper;
@@ -101,7 +100,6 @@ public class WifiConfigManagerTest {
@Mock private TelephonyManager mTelephonyManager;
@Mock private WifiKeyStore mWifiKeyStore;
@Mock private WifiConfigStore mWifiConfigStore;
- @Mock private WifiConfigStoreLegacy mWifiConfigStoreLegacy;
@Mock private PackageManager mPackageManager;
@Mock private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
@Mock private WifiPermissionsUtil mWifiPermissionsUtil;
@@ -1144,7 +1142,7 @@ public class WifiConfigManagerTest {
ScanDetailCache retrievedScanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(result.getNetworkId());
assertEquals(1, retrievedScanDetailCache.size());
- ScanResult retrievedScanResult = retrievedScanDetailCache.get(scanResult.BSSID);
+ ScanResult retrievedScanResult = retrievedScanDetailCache.getScanResult(scanResult.BSSID);
ScanTestUtil.assertScanResultEquals(scanResult, retrievedScanResult);
}
@@ -1521,6 +1519,45 @@ public class WifiConfigManagerTest {
}
/**
+ * Verifies that the list of PNO networks does not contain any permanently or temporarily
+ * disabled networks.
+ * {@link WifiConfigManager#retrievePnoNetworkList()}.
+ */
+ @Test
+ public void testRetrievePnoListDoesNotContainDisabledNetworks() throws Exception {
+ // Create and add 2 networks.
+ WifiConfiguration network1 = WifiConfigurationTestUtil.createEapNetwork();
+ WifiConfiguration network2 = WifiConfigurationTestUtil.createPskNetwork();
+
+ NetworkUpdateResult result1 = verifyAddNetworkToWifiConfigManager(network1);
+ NetworkUpdateResult result2 = verifyAddNetworkToWifiConfigManager(network2);
+
+ // Enable all of them.
+ verifyUpdateNetworkSelectionStatus(
+ result1.getNetworkId(), NetworkSelectionStatus.NETWORK_SELECTION_ENABLE, 0);
+ verifyUpdateNetworkSelectionStatus(
+ result2.getNetworkId(), NetworkSelectionStatus.NETWORK_SELECTION_ENABLE, 0);
+
+ // Set network1 to temporarily disabled. The threshold for association rejection is 5, so
+ // disable it 5 times to actually mark it temporarily disabled.
+ int assocRejectReason = NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION;
+ int assocRejectThreshold =
+ WifiConfigManager.NETWORK_SELECTION_DISABLE_THRESHOLD[assocRejectReason];
+ for (int i = 1; i <= assocRejectThreshold; i++) {
+ verifyUpdateNetworkSelectionStatus(result1.getNetworkId(), assocRejectReason, i);
+ }
+
+ // Set network 2 to permanently disabled.
+ verifyUpdateNetworkSelectionStatus(
+ result2.getNetworkId(), NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER, 0);
+
+ // Retrieve the Pno network list & verify both networks are not included.
+ List<WifiScanner.PnoSettings.PnoNetwork> pnoNetworks =
+ mWifiConfigManager.retrievePnoNetworkList();
+ assertEquals(0, pnoNetworks.size());
+ }
+
+ /**
* Verifies the linking of networks when they have the same default GW Mac address in
* {@link WifiConfigManager#getOrCreateScanDetailCacheForNetwork(WifiConfiguration)}.
*/
@@ -2369,7 +2406,7 @@ public class WifiConfigManagerTest {
}
/**
- * Verifies that the foreground user stop using {@link WifiConfigManager#handleUserStop(int)}
+ * Verifies that the user stop handling using {@link WifiConfigManager#handleUserStop(int)}
* and ensures that the store is written only when the foreground user is stopped.
*/
@Test
@@ -2392,6 +2429,49 @@ public class WifiConfigManagerTest {
}
/**
+ * Verifies that the user stop handling using {@link WifiConfigManager#handleUserStop(int)}
+ * and ensures that the shared data is not lost when the foreground user is stopped.
+ */
+ @Test
+ public void testHandleUserStopDoesNotClearSharedData() throws Exception {
+ int user1 = TEST_DEFAULT_USER;
+
+ //
+ // Setup the database for the user before initiating stop.
+ //
+ int appId = 674;
+ // Create 2 networks. 1 for user1, and 1 shared.
+ final WifiConfiguration user1Network = WifiConfigurationTestUtil.createPskNetwork();
+ user1Network.shared = false;
+ user1Network.creatorUid = UserHandle.getUid(user1, appId);
+ final WifiConfiguration sharedNetwork = WifiConfigurationTestUtil.createPskNetwork();
+
+ // Set up the store data that is loaded initially.
+ List<WifiConfiguration> sharedNetworks = new ArrayList<WifiConfiguration>() {
+ {
+ add(sharedNetwork);
+ }
+ };
+ List<WifiConfiguration> user1Networks = new ArrayList<WifiConfiguration>() {
+ {
+ add(user1Network);
+ }
+ };
+ setupStoreDataForRead(sharedNetworks, user1Networks, new HashSet<String>());
+ assertTrue(mWifiConfigManager.loadFromStore());
+ verify(mWifiConfigStore).read();
+
+ // Ensure that we have 2 networks in the database before the stop.
+ assertEquals(2, mWifiConfigManager.getConfiguredNetworks().size());
+
+ mWifiConfigManager.handleUserStop(user1);
+
+ // Ensure that we only have 1 shared network in the database after the stop.
+ assertEquals(1, mWifiConfigManager.getConfiguredNetworks().size());
+ assertEquals(sharedNetwork.SSID, mWifiConfigManager.getConfiguredNetworks().get(0).SSID);
+ }
+
+ /**
* Verifies the foreground user unlock via {@link WifiConfigManager#handleUserUnlock(int)}
* results in a store read after bootup.
*/
@@ -2539,55 +2619,6 @@ public class WifiConfigManagerTest {
}
/**
- * Verifies the loading of networks using {@link WifiConfigManager#migrateFromLegacyStore()} ()}
- * attempts to migrate data from legacy stores when the legacy store files are present.
- */
- @Test
- public void testMigrationFromLegacyStore() throws Exception {
- // Create the store data to be returned from legacy stores.
- List<WifiConfiguration> networks = new ArrayList<>();
- networks.add(WifiConfigurationTestUtil.createPskNetwork());
- networks.add(WifiConfigurationTestUtil.createEapNetwork());
- networks.add(WifiConfigurationTestUtil.createWepNetwork());
- String deletedEphemeralSSID = "EphemeralSSID";
- Set<String> deletedEphermalSSIDs = new HashSet<>(Arrays.asList(deletedEphemeralSSID));
- WifiConfigStoreDataLegacy storeData =
- new WifiConfigStoreDataLegacy(networks, deletedEphermalSSIDs);
-
- when(mWifiConfigStoreLegacy.areStoresPresent()).thenReturn(true);
- when(mWifiConfigStoreLegacy.read()).thenReturn(storeData);
-
- // Now trigger the migration from legacy store. This should populate the in memory list with
- // all the networks above from the legacy store.
- assertTrue(mWifiConfigManager.migrateFromLegacyStore());
-
- verify(mWifiConfigStoreLegacy).read();
- verify(mWifiConfigStoreLegacy).removeStores();
-
- List<WifiConfiguration> retrievedNetworks =
- mWifiConfigManager.getConfiguredNetworksWithPasswords();
- WifiConfigurationTestUtil.assertConfigurationsEqualForConfigManagerAddOrUpdate(
- networks, retrievedNetworks);
- assertTrue(mWifiConfigManager.wasEphemeralNetworkDeleted(deletedEphemeralSSID));
- }
-
- /**
- * Verifies the loading of networks using {@link WifiConfigManager#migrateFromLegacyStore()} ()}
- * does not attempt to migrate data from legacy stores when the legacy store files are absent
- * (i.e migration was already done once).
- */
- @Test
- public void testNoDuplicateMigrationFromLegacyStore() throws Exception {
- when(mWifiConfigStoreLegacy.areStoresPresent()).thenReturn(false);
-
- // Now trigger a migration from legacy store.
- assertTrue(mWifiConfigManager.migrateFromLegacyStore());
-
- verify(mWifiConfigStoreLegacy, never()).read();
- verify(mWifiConfigStoreLegacy, never()).removeStores();
- }
-
- /**
* Verifies the loading of networks using {@link WifiConfigManager#loadFromStore()} does
* not attempt to read from any of the stores (new or legacy) when the store files are
* not present.
@@ -2595,12 +2626,10 @@ public class WifiConfigManagerTest {
@Test
public void testFreshInstallDoesNotLoadFromStore() throws Exception {
when(mWifiConfigStore.areStoresPresent()).thenReturn(false);
- when(mWifiConfigStoreLegacy.areStoresPresent()).thenReturn(false);
assertTrue(mWifiConfigManager.loadFromStore());
verify(mWifiConfigStore, never()).read();
- verify(mWifiConfigStoreLegacy, never()).read();
assertTrue(mWifiConfigManager.getConfiguredNetworksWithPasswords().isEmpty());
}
@@ -2613,11 +2642,9 @@ public class WifiConfigManagerTest {
public void testHandleUserSwitchAfterFreshInstall() throws Exception {
int user2 = TEST_DEFAULT_USER + 1;
when(mWifiConfigStore.areStoresPresent()).thenReturn(false);
- when(mWifiConfigStoreLegacy.areStoresPresent()).thenReturn(false);
assertTrue(mWifiConfigManager.loadFromStore());
verify(mWifiConfigStore, never()).read();
- verify(mWifiConfigStoreLegacy, never()).read();
setupStoreDataForUserRead(new ArrayList<WifiConfiguration>(), new HashSet<String>());
// Now switch the user to user 2.
@@ -3376,7 +3403,7 @@ public class WifiConfigManagerTest {
mWifiConfigManager =
new WifiConfigManager(
mContext, mClock, mUserManager, mTelephonyManager,
- mWifiKeyStore, mWifiConfigStore, mWifiConfigStoreLegacy,
+ mWifiKeyStore, mWifiConfigStore,
mWifiPermissionsUtil, mWifiPermissionsWrapper, mNetworkListStoreData,
mDeletedEphemeralSsidsStoreData);
mWifiConfigManager.enableVerboseLogging(1);
@@ -3971,7 +3998,7 @@ public class WifiConfigManagerTest {
ScanDetailCache retrievedScanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(network.networkId);
assertEquals(1, retrievedScanDetailCache.size());
- ScanResult retrievedScanResult = retrievedScanDetailCache.get(scanResult.BSSID);
+ ScanResult retrievedScanResult = retrievedScanDetailCache.getScanResult(scanResult.BSSID);
ScanTestUtil.assertScanResultEquals(scanResult, retrievedScanResult);
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreLegacyTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreLegacyTest.java
deleted file mode 100644
index 4b4e875a1..000000000
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreLegacyTest.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2016 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.*;
-import static org.mockito.Mockito.*;
-
-import android.app.test.MockAnswerUtil.AnswerWithArguments;
-import android.net.IpConfiguration;
-import android.net.wifi.WifiConfiguration;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.TextUtils;
-import android.util.SparseArray;
-
-import com.android.server.net.IpConfigStore;
-import com.android.server.wifi.hotspot2.LegacyPasspointConfig;
-import com.android.server.wifi.hotspot2.LegacyPasspointConfigParser;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Unit tests for {@link com.android.server.wifi.WifiConfigStoreLegacy}.
- */
-@SmallTest
-public class WifiConfigStoreLegacyTest {
- private static final String MASKED_FIELD_VALUE = "*";
-
- // Test mocks
- @Mock private WifiNative mWifiNative;
- @Mock private WifiNetworkHistory mWifiNetworkHistory;
- @Mock private IpConfigStore mIpconfigStore;
- @Mock private LegacyPasspointConfigParser mPasspointConfigParser;
-
- /**
- * Test instance of WifiConfigStore.
- */
- private WifiConfigStoreLegacy mWifiConfigStore;
-
-
- /**
- * Setup the test environment.
- */
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mWifiConfigStore = new WifiConfigStoreLegacy(mWifiNetworkHistory, mWifiNative,
- mIpconfigStore, mPasspointConfigParser);
- }
-
- /**
- * Called after each test
- */
- @After
- public void cleanup() {
- validateMockitoUsage();
- }
-
- /**
- * Verify loading of network configurations from legacy stores. This is verifying the population
- * of the masked wpa_supplicant fields using wpa_supplicant.conf file.
- */
- @Test
- public void testLoadFromStores() throws Exception {
- WifiConfiguration pskNetwork = WifiConfigurationTestUtil.createPskNetwork();
- WifiConfiguration wepNetwork = WifiConfigurationTestUtil.createWepNetwork();
- WifiConfiguration eapNetwork = WifiConfigurationTestUtil.createEapNetwork();
- WifiConfiguration passpointNetwork = WifiConfigurationTestUtil.createPasspointNetwork();
- eapNetwork.enterpriseConfig.setPassword("EapPassword");
-
- // Initialize Passpoint configuration data.
- int passpointNetworkId = 1234;
- String fqdn = passpointNetwork.FQDN;
- String providerFriendlyName = passpointNetwork.providerFriendlyName;
- long[] roamingConsortiumIds = new long[] {0x1234, 0x5678};
- String realm = "test.com";
- String imsi = "214321";
-
- // Update Passpoint network.
- // Network ID is used for lookup network extras, so use an unique ID for passpoint network.
- passpointNetwork.networkId = passpointNetworkId;
- passpointNetwork.enterpriseConfig.setPassword("PaspointPassword");
- // Reset FQDN and provider friendly name so that the derived network from #read will
- // obtained these information from networkExtras and {@link LegacyPasspointConfigParser}.
- passpointNetwork.FQDN = null;
- passpointNetwork.providerFriendlyName = null;
-
- final List<WifiConfiguration> networks = new ArrayList<>();
- networks.add(pskNetwork);
- networks.add(wepNetwork);
- networks.add(eapNetwork);
- networks.add(passpointNetwork);
-
- // Setup legacy Passpoint configuration data.
- Map<String, LegacyPasspointConfig> passpointConfigs = new HashMap<>();
- LegacyPasspointConfig passpointConfig = new LegacyPasspointConfig();
- passpointConfig.mFqdn = fqdn;
- passpointConfig.mFriendlyName = providerFriendlyName;
- passpointConfig.mRoamingConsortiumOis = roamingConsortiumIds;
- passpointConfig.mRealm = realm;
- passpointConfig.mImsi = imsi;
- passpointConfigs.put(fqdn, passpointConfig);
-
- // Return the config data with passwords masked from wpa_supplicant control interface.
- doAnswer(new AnswerWithArguments() {
- public boolean answer(Map<String, WifiConfiguration> configs,
- SparseArray<Map<String, String>> networkExtras) {
- for (Map.Entry<String, WifiConfiguration> entry:
- createWpaSupplicantLoadData(networks).entrySet()) {
- configs.put(entry.getKey(), entry.getValue());
- }
- // Setup networkExtras for Passpoint configuration.
- networkExtras.put(passpointNetworkId, createNetworkExtrasForPasspointConfig(fqdn));
- return true;
- }
- }).when(mWifiNative).migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class));
-
- when(mPasspointConfigParser.parseConfig(anyString())).thenReturn(passpointConfigs);
- WifiConfigStoreLegacy.WifiConfigStoreDataLegacy storeData = mWifiConfigStore.read();
-
- // Update the expected configuration for Passpoint network.
- passpointNetwork.isLegacyPasspointConfig = true;
- passpointNetwork.FQDN = fqdn;
- passpointNetwork.providerFriendlyName = providerFriendlyName;
- passpointNetwork.roamingConsortiumIds = roamingConsortiumIds;
- passpointNetwork.enterpriseConfig.setRealm(realm);
- passpointNetwork.enterpriseConfig.setPlmn(imsi);
-
- WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore(
- networks, storeData.getConfigurations());
- }
-
- private SparseArray<IpConfiguration> createIpConfigStoreLoadData(
- List<WifiConfiguration> configurations) {
- SparseArray<IpConfiguration> newIpConfigurations = new SparseArray<>();
- for (WifiConfiguration config : configurations) {
- newIpConfigurations.put(
- config.configKey().hashCode(),
- new IpConfiguration(config.getIpConfiguration()));
- }
- return newIpConfigurations;
- }
-
- private Map<String, String> createPskMap(List<WifiConfiguration> configurations) {
- Map<String, String> pskMap = new HashMap<>();
- for (WifiConfiguration config : configurations) {
- if (!TextUtils.isEmpty(config.preSharedKey)) {
- pskMap.put(config.configKey(), config.preSharedKey);
- }
- }
- return pskMap;
- }
-
- private Map<String, String> createWepKey0Map(List<WifiConfiguration> configurations) {
- Map<String, String> wepKeyMap = new HashMap<>();
- for (WifiConfiguration config : configurations) {
- if (!TextUtils.isEmpty(config.wepKeys[0])) {
- wepKeyMap.put(config.configKey(), config.wepKeys[0]);
- }
- }
- return wepKeyMap;
- }
-
- private Map<String, String> createWepKey1Map(List<WifiConfiguration> configurations) {
- Map<String, String> wepKeyMap = new HashMap<>();
- for (WifiConfiguration config : configurations) {
- if (!TextUtils.isEmpty(config.wepKeys[1])) {
- wepKeyMap.put(config.configKey(), config.wepKeys[1]);
- }
- }
- return wepKeyMap;
- }
-
- private Map<String, String> createWepKey2Map(List<WifiConfiguration> configurations) {
- Map<String, String> wepKeyMap = new HashMap<>();
- for (WifiConfiguration config : configurations) {
- if (!TextUtils.isEmpty(config.wepKeys[2])) {
- wepKeyMap.put(config.configKey(), config.wepKeys[2]);
- }
- }
- return wepKeyMap;
- }
-
- private Map<String, String> createWepKey3Map(List<WifiConfiguration> configurations) {
- Map<String, String> wepKeyMap = new HashMap<>();
- for (WifiConfiguration config : configurations) {
- if (!TextUtils.isEmpty(config.wepKeys[3])) {
- wepKeyMap.put(config.configKey(), config.wepKeys[3]);
- }
- }
- return wepKeyMap;
- }
-
- private Map<String, String> createEapPasswordMap(List<WifiConfiguration> configurations) {
- Map<String, String> eapPasswordMap = new HashMap<>();
- for (WifiConfiguration config : configurations) {
- if (!TextUtils.isEmpty(config.enterpriseConfig.getPassword())) {
- eapPasswordMap.put(config.configKey(), config.enterpriseConfig.getPassword());
- }
- }
- return eapPasswordMap;
- }
-
- private Map<String, WifiConfiguration> createWpaSupplicantLoadData(
- List<WifiConfiguration> configurations) {
- Map<String, WifiConfiguration> configurationMap = new HashMap<>();
- for (WifiConfiguration config : configurations) {
- configurationMap.put(config.configKey(true), config);
- }
- return configurationMap;
- }
-
- private List<WifiConfiguration> createMaskedWifiConfigurations(
- List<WifiConfiguration> configurations) {
- List<WifiConfiguration> newConfigurations = new ArrayList<>();
- for (WifiConfiguration config : configurations) {
- newConfigurations.add(createMaskedWifiConfiguration(config));
- }
- return newConfigurations;
- }
-
- private WifiConfiguration createMaskedWifiConfiguration(WifiConfiguration configuration) {
- WifiConfiguration newConfig = new WifiConfiguration(configuration);
- if (!TextUtils.isEmpty(configuration.preSharedKey)) {
- newConfig.preSharedKey = MASKED_FIELD_VALUE;
- }
- if (!TextUtils.isEmpty(configuration.wepKeys[0])) {
- newConfig.wepKeys[0] = MASKED_FIELD_VALUE;
- }
- if (!TextUtils.isEmpty(configuration.wepKeys[1])) {
- newConfig.wepKeys[1] = MASKED_FIELD_VALUE;
- }
- if (!TextUtils.isEmpty(configuration.wepKeys[2])) {
- newConfig.wepKeys[2] = MASKED_FIELD_VALUE;
- }
- if (!TextUtils.isEmpty(configuration.wepKeys[3])) {
- newConfig.wepKeys[3] = MASKED_FIELD_VALUE;
- }
- if (!TextUtils.isEmpty(configuration.enterpriseConfig.getPassword())) {
- newConfig.enterpriseConfig.setPassword(MASKED_FIELD_VALUE);
- }
- return newConfig;
- }
-
- private Map<String, String> createNetworkExtrasForPasspointConfig(String fqdn) {
- Map<String, String> extras = new HashMap<>();
- extras.put(SupplicantStaNetworkHal.ID_STRING_KEY_FQDN, fqdn);
- return extras;
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
index 47efed3c4..0958fea61 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
import android.app.test.TestAlarmManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.wifi.WifiConfiguration;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
@@ -60,6 +61,7 @@ public class WifiConfigStoreTest {
private static final String TEST_USER_DATA = "UserData";
private static final String TEST_SHARE_DATA = "ShareData";
+ private static final String TEST_CREATOR_NAME = "CreatorName";
private static final String TEST_DATA_XML_STRING_FORMAT =
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
@@ -91,10 +93,11 @@ public class WifiConfigStoreTest {
+ "<boolean name=\"NoInternetAccessExpected\" value=\"false\" />\n"
+ "<int name=\"UserApproved\" value=\"0\" />\n"
+ "<boolean name=\"MeteredHint\" value=\"false\" />\n"
+ + "<int name=\"MeteredOverride\" value=\"0\" />\n"
+ "<boolean name=\"UseExternalScores\" value=\"false\" />\n"
+ "<int name=\"NumAssociation\" value=\"0\" />\n"
+ "<int name=\"CreatorUid\" value=\"%d\" />\n"
- + "<null name=\"CreatorName\" />\n"
+ + "<string name=\"CreatorName\">%s</string>\n"
+ "<null name=\"CreationTime\" />\n"
+ "<int name=\"LastUpdateUid\" value=\"-1\" />\n"
+ "<null name=\"LastUpdateName\" />\n"
@@ -124,6 +127,7 @@ public class WifiConfigStoreTest {
// Test mocks
@Mock private Context mContext;
+ @Mock private PackageManager mPackageManager;
private TestAlarmManager mAlarmManager;
private TestLooper mLooper;
@Mock private Clock mClock;
@@ -145,6 +149,8 @@ public class WifiConfigStoreTest {
mLooper = new TestLooper();
when(mContext.getSystemService(Context.ALARM_SERVICE))
.thenReturn(mAlarmManager.getAlarmManager());
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME);
mUserStore = new MockStoreFile();
mSharedStore = new MockStoreFile();
mStoreData = new MockStoreData();
@@ -363,9 +369,10 @@ public class WifiConfigStoreTest {
@Test
public void testReadWifiConfigStoreData() throws Exception {
// Setup network list.
- NetworkListStoreData networkList = new NetworkListStoreData();
+ NetworkListStoreData networkList = new NetworkListStoreData(mContext);
mWifiConfigStore.registerStoreData(networkList);
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
+ openNetwork.creatorName = TEST_CREATOR_NAME;
openNetwork.setIpConfiguration(
WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
List<WifiConfiguration> userConfigs = new ArrayList<>();
@@ -383,7 +390,7 @@ public class WifiConfigStoreTest {
String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT,
openNetwork.configKey().replaceAll("\"", "&quot;"),
openNetwork.SSID.replaceAll("\"", "&quot;"),
- openNetwork.shared, openNetwork.creatorUid, testSsid);
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, testSsid);
byte[] xmlBytes = xmlString.getBytes(StandardCharsets.UTF_8);
mUserStore.storeRawDataToWrite(xmlBytes);
@@ -405,9 +412,10 @@ public class WifiConfigStoreTest {
mWifiConfigStore.switchUserStoreAndRead(mUserStore);
// Setup network list store data.
- NetworkListStoreData networkList = new NetworkListStoreData();
+ NetworkListStoreData networkList = new NetworkListStoreData(mContext);
mWifiConfigStore.registerStoreData(networkList);
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
+ openNetwork.creatorName = TEST_CREATOR_NAME;
openNetwork.setIpConfiguration(
WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy());
List<WifiConfiguration> userConfigs = new ArrayList<>();
@@ -427,7 +435,7 @@ public class WifiConfigStoreTest {
String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT,
openNetwork.configKey().replaceAll("\"", "&quot;"),
openNetwork.SSID.replaceAll("\"", "&quot;"),
- openNetwork.shared, openNetwork.creatorUid, testSsid);
+ openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, testSsid);
byte[] xmlBytes = xmlString.getBytes(StandardCharsets.UTF_8);
mWifiConfigStore.write(true);
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index bdb6b14ed..4fabd9d1e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -41,6 +41,7 @@ import android.net.wifi.WifiScanner.ScanData;
import android.net.wifi.WifiScanner.ScanListener;
import android.net.wifi.WifiScanner.ScanSettings;
import android.net.wifi.WifiSsid;
+import android.os.Process;
import android.os.SystemClock;
import android.os.WorkSource;
import android.os.test.TestLooper;
@@ -123,7 +124,7 @@ public class WifiConnectivityManagerTest {
@Mock private NetworkScoreManager mNetworkScoreManager;
@Mock private Clock mClock;
@Mock private WifiLastResortWatchdog mWifiLastResortWatchdog;
- @Mock private WifiNotificationController mWifiNotificationController;
+ @Mock private OpenNetworkNotifier mOpenNetworkNotifier;
@Mock private WifiMetrics mWifiMetrics;
@Mock private WifiNetworkScoreCache mScoreCache;
@Captor ArgumentCaptor<ScanResult> mCandidateScanResultCaptor;
@@ -294,7 +295,7 @@ public class WifiConnectivityManagerTest {
WifiConnectivityManager createConnectivityManager() {
return new WifiConnectivityManager(mContext, mWifiStateMachine, mWifiScanner,
mWifiConfigManager, mWifiInfo, mWifiNS, mWifiConnectivityHelper,
- mWifiLastResortWatchdog, mWifiNotificationController, mWifiMetrics,
+ mWifiLastResortWatchdog, mOpenNetworkNotifier, mWifiMetrics,
mLooper.getLooper(), mClock, mLocalLog, true, mFrameworkFacade, null, null, null);
}
@@ -314,7 +315,8 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ verify(mWifiStateMachine).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -333,7 +335,8 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
- verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ verify(mWifiStateMachine).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -353,7 +356,7 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mWifiStateMachine, atLeastOnce()).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -373,7 +376,7 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mWifiStateMachine, atLeastOnce()).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -400,7 +403,7 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mWifiStateMachine, times(0)).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -438,7 +441,7 @@ public class WifiConnectivityManagerTest {
// Verify that we attempt to connect upto the rate.
verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -479,7 +482,7 @@ public class WifiConnectivityManagerTest {
// Verify that all the connection attempts went through
verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -523,7 +526,7 @@ public class WifiConnectivityManagerTest {
// Verify that all the connection attempts went through
verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -609,12 +612,12 @@ public class WifiConnectivityManagerTest {
}
/**
- * {@link WifiNotificationController} handles scan results on network selection.
+ * {@link OpenNetworkNotifier} handles scan results on network selection.
*
* Expected behavior: ONA handles scan results
*/
@Test
- public void wifiDisconnected_noConnectionCandidate_openNetworkNotificationScanResultsHandled() {
+ public void wifiDisconnected_noConnectionCandidate_openNetworkNotifierScanResultsHandled() {
// no connection candidate selected
when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(),
anyBoolean(), anyBoolean())).thenReturn(null);
@@ -633,37 +636,66 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiNotificationController).handleScanResults(expectedOpenNetworks);
+ verify(mOpenNetworkNotifier).handleScanResults(expectedOpenNetworks);
}
/**
- * When wifi is connected, {@link WifiNotificationController} tries to clear the pending
- * notification and does not reset notification repeat delay.
+ * When wifi is connected, {@link OpenNetworkNotifier} handles the Wi-Fi connected behavior.
*
- * Expected behavior: ONA clears pending notification and does not reset repeat delay.
+ * Expected behavior: ONA handles connected behavior
*/
@Test
- public void wifiConnected_openNetworkNotificationClearsPendingNotification() {
+ public void wifiConnected_openNetworkNotifierHandlesConnection() {
// Set WiFi to connected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
- verify(mWifiNotificationController).clearPendingNotification(false /* isRepeatDelayReset*/);
+ verify(mOpenNetworkNotifier).handleWifiConnected();
}
/**
- * When wifi is connected, {@link WifiNotificationController} handles connection state
+ * When wifi is connected, {@link OpenNetworkNotifier} handles connection state
* change.
*
* Expected behavior: ONA does not clear pending notification.
*/
@Test
- public void wifiDisconnected_openNetworkNotificationDoesNotClearPendingNotification() {
+ public void wifiDisconnected_openNetworkNotifierDoesNotClearPendingNotification() {
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiNotificationController, never()).clearPendingNotification(anyBoolean());
+ verify(mOpenNetworkNotifier, never()).clearPendingNotification(anyBoolean());
+ }
+
+ /**
+ * When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} handles the connection
+ * failure. A failure code that is not {@link WifiMetrics.ConnectionEvent#FAILURE_NONE}
+ * represents a connection failure.
+ *
+ * Expected behavior: ONA handles connection failure.
+ */
+ @Test
+ public void wifiConnectionEndsWithFailure_openNetworkNotifierHandlesConnectionFailure() {
+ mWifiConnectivityManager.handleConnectionAttemptEnded(
+ WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED);
+
+ verify(mOpenNetworkNotifier).handleConnectionFailure();
+ }
+
+ /**
+ * When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} does not handle connection
+ * failure after a successful connection. {@link WifiMetrics.ConnectionEvent#FAILURE_NONE}
+ * represents a successful connection.
+ *
+ * Expected behavior: ONA does nothing.
+ */
+ @Test
+ public void wifiConnectionEndsWithSuccess_openNetworkNotifierDoesNotHandleConnectionFailure() {
+ mWifiConnectivityManager.handleConnectionAttemptEnded(
+ WifiMetrics.ConnectionEvent.FAILURE_NONE);
+
+ verify(mOpenNetworkNotifier, never()).handleConnectionFailure();
}
/**
@@ -672,24 +704,24 @@ public class WifiConnectivityManagerTest {
* Expected behavior: clear pending notification and reset notification repeat delay
* */
@Test
- public void openNetworkNotificationControllerToggledOnWifiStateChanges() {
+ public void openNetworkNotifierClearsPendingNotificationOnWifiDisabled() {
mWifiConnectivityManager.setWifiEnabled(false);
- verify(mWifiNotificationController).clearPendingNotification(true /* isRepeatDelayReset */);
+ verify(mOpenNetworkNotifier).clearPendingNotification(true /* resetRepeatDelay */);
}
/**
* Verify that the ONA controller tracks screen state changes.
*/
@Test
- public void openNetworkNotificationControllerTracksScreenStateChanges() {
+ public void openNetworkNotifierTracksScreenStateChanges() {
mWifiConnectivityManager.handleScreenStateChanged(false);
- verify(mWifiNotificationController).handleScreenStateChanged(false);
+ verify(mOpenNetworkNotifier).handleScreenStateChanged(false);
mWifiConnectivityManager.handleScreenStateChanged(true);
- verify(mWifiNotificationController).handleScreenStateChanged(true);
+ verify(mOpenNetworkNotifier).handleScreenStateChanged(true);
}
/**
@@ -1123,7 +1155,8 @@ public class WifiConnectivityManagerTest {
// Verify that WCM receives the scan results and initiates a connection
// to the network.
- verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ verify(mWifiStateMachine).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -1145,21 +1178,22 @@ public class WifiConnectivityManagerTest {
// Force a connectivity scan which enables WifiConnectivityManager
// to wait for full band scan results.
- mWifiConnectivityManager.forceConnectivityScan();
+ mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
// No roaming because no full band scan results.
verify(mWifiStateMachine, times(0)).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
// Set up as full band scan results.
when(mScanData.isAllChannelsScanned()).thenReturn(true);
// Force a connectivity scan which enables WifiConnectivityManager
// to wait for full band scan results.
- mWifiConnectivityManager.forceConnectivityScan();
+ mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
// Roaming attempt because full band scan results are available.
- verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ verify(mWifiStateMachine).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -1252,14 +1286,14 @@ public class WifiConnectivityManagerTest {
// its blacklist expiration time hasn't reached yet.
when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ WifiConnectivityManager.BSSID_BLACKLIST_EXPIRE_TIME_MS / 2);
- mWifiConnectivityManager.forceConnectivityScan();
+ mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid));
// Force another connectivity scan at BSSID_BLACKLIST_EXPIRE_TIME_MS from when the
// BSSID was blacklisted. Verify that the blacklisted BSSId is freed.
when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ WifiConnectivityManager.BSSID_BLACKLIST_EXPIRE_TIME_MS);
- mWifiConnectivityManager.forceConnectivityScan();
+ mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
// Verify the BSSID is no longer blacklisted.
assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid));
@@ -1412,7 +1446,7 @@ public class WifiConnectivityManagerTest {
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mWifiStateMachine).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, WifiStateMachine.SUPPLICANT_BSSID_ANY);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, WifiStateMachine.SUPPLICANT_BSSID_ANY);
}
/*
@@ -1448,7 +1482,8 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ verify(mWifiStateMachine).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/*
@@ -1468,7 +1503,8 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ verify(mWifiStateMachine).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/*
@@ -1500,7 +1536,8 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ verify(mWifiStateMachine).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
@@ -1590,7 +1627,7 @@ public class WifiConnectivityManagerTest {
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mWifiStateMachine, times(0)).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/*
@@ -1652,7 +1689,7 @@ public class WifiConnectivityManagerTest {
/**
* Dump ONA controller.
*
- * Expected behavior: {@link WifiNotificationController#dump(FileDescriptor, PrintWriter,
+ * Expected behavior: {@link OpenNetworkNotifier#dump(FileDescriptor, PrintWriter,
* String[])} is invoked.
*/
@Test
@@ -1661,6 +1698,6 @@ public class WifiConnectivityManagerTest {
PrintWriter pw = new PrintWriter(sw);
mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{});
- verify(mWifiNotificationController).dump(any(), any(), any());
+ verify(mOpenNetworkNotifier).dump(any(), any(), any());
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
index 33aab60e1..fb4e71ef5 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
@@ -169,7 +169,8 @@ public class WifiCountryCodeTest {
}
/**
- * Test if we can reset to the default country code when phone is out of service.
+ * Test if we can reset to the default country code when phone is out of service, when
+ * |config_wifi_revert_country_code_on_cellular_loss| is set to true;
* Telephony service calls |setCountryCode| with an empty string when phone is out of service.
* In this case we should fall back to the default country code.
* @throws Exception
@@ -184,4 +185,28 @@ public class WifiCountryCodeTest {
assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCode());
}
+ /**
+ * Test if we can keep using the last known country code when phone is out of service, when
+ * |config_wifi_revert_country_code_on_cellular_loss| is set to false;
+ * Telephony service calls |setCountryCode| with an empty string when phone is out of service.
+ * In this case we should keep using the last known country code.
+ * @throws Exception
+ */
+ @Test
+ public void doNotResetCountryCodeWhenOutOfService() throws Exception {
+ // Refresh mWifiCountryCode with |config_wifi_revert_country_code_on_cellular_loss|
+ // setting to false.
+ mWifiCountryCode = new WifiCountryCode(
+ mWifiNative,
+ mDefaultCountryCode,
+ false /* config_wifi_revert_country_code_on_cellular_loss */);
+
+ assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCode());
+ mWifiCountryCode.setCountryCode(mTelephonyCountryCode);
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCode());
+ // Out of service.
+ mWifiCountryCode.setCountryCode("");
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCode());
+ }
+
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index 5a139282b..65427beb2 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
@@ -37,6 +38,8 @@ import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.hotspot2.PasspointMatch;
import com.android.server.wifi.hotspot2.PasspointProvider;
import com.android.server.wifi.nano.WifiMetricsProto;
+import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
+import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
import org.junit.Before;
@@ -252,6 +255,24 @@ public class WifiMetricsTest {
private static final int NUM_PASSPOINT_PROVIDER_UNINSTALL_SUCCESS = 2;
private static final int NUM_PASSPOINT_PROVIDERS_SUCCESSFULLY_CONNECTED = 1;
private static final int NUM_PARTIAL_SCAN_RESULTS = 73;
+ private static final int NUM_PNO_SCAN_ATTEMPTS = 20;
+ private static final int NUM_PNO_SCAN_FAILED = 5;
+ private static final int NUM_PNO_SCAN_STARTED_OVER_OFFLOAD = 17;
+ private static final int NUM_PNO_SCAN_FAILED_OVER_OFFLOAD = 8;
+ private static final int NUM_PNO_FOUND_NETWORK_EVENTS = 10;
+ /** Number of notifications per "Connect to Network" notification type. */
+ private static final int[] NUM_CONNECT_TO_NETWORK_NOTIFICATIONS = {0, 10, 20, 30, 40};
+ /** Number of notifications per "Connect to Network notification type and action type. */
+ private static final int[][] NUM_CONNECT_TO_NETWORK_NOTIFICATION_ACTIONS = {
+ {0, 1, 2, 3, 4},
+ {10, 11, 12, 13, 14},
+ {20, 21, 22, 23, 24},
+ {30, 31, 32, 33, 34},
+ {40, 41, 42, 43, 44}};
+ private static final int SIZE_OPEN_NETWORK_RECOMMENDER_BLACKLIST = 10;
+ private static final boolean IS_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = true;
+ private static final int NUM_OPEN_NETWORK_CONNECT_MESSAGE_FAILED_TO_SEND = 5;
+ private static final int NUM_OPEN_NETWORK_RECOMMENDATION_UPDATES = 8;
private ScanDetail buildMockScanDetail(boolean hidden, NetworkDetail.HSRelease hSRelease,
String capabilities) {
@@ -474,6 +495,50 @@ public class WifiMetricsTest {
for (int i = 0; i < NUM_PASSPOINT_PROVIDER_UNINSTALL_SUCCESS; i++) {
mWifiMetrics.incrementNumPasspointProviderUninstallSuccess();
}
+
+ // increment pno scan metrics
+ for (int i = 0; i < NUM_PNO_SCAN_ATTEMPTS; i++) {
+ mWifiMetrics.incrementPnoScanStartAttempCount();
+ }
+ for (int i = 0; i < NUM_PNO_SCAN_FAILED; i++) {
+ mWifiMetrics.incrementPnoScanFailedCount();
+ }
+ for (int i = 0; i < NUM_PNO_SCAN_STARTED_OVER_OFFLOAD; i++) {
+ mWifiMetrics.incrementPnoScanStartedOverOffloadCount();
+ }
+ for (int i = 0; i < NUM_PNO_SCAN_FAILED_OVER_OFFLOAD; i++) {
+ mWifiMetrics.incrementPnoScanFailedOverOffloadCount();
+ }
+ for (int i = 0; i < NUM_PNO_FOUND_NETWORK_EVENTS; i++) {
+ mWifiMetrics.incrementPnoFoundNetworkEventCount();
+ }
+
+ // set and increment "connect to network" notification metrics
+ for (int i = 0; i < NUM_CONNECT_TO_NETWORK_NOTIFICATIONS.length; i++) {
+ int count = NUM_CONNECT_TO_NETWORK_NOTIFICATIONS[i];
+ for (int j = 0; j < count; j++) {
+ mWifiMetrics.incrementConnectToNetworkNotification(i);
+ }
+ }
+ for (int i = 0; i < NUM_CONNECT_TO_NETWORK_NOTIFICATION_ACTIONS.length; i++) {
+ int[] actions = NUM_CONNECT_TO_NETWORK_NOTIFICATION_ACTIONS[i];
+ for (int j = 0; j < actions.length; j++) {
+ int count = actions[j];
+ for (int k = 0; k < count; k++) {
+ mWifiMetrics.incrementConnectToNetworkNotificationAction(i, j);
+ }
+ }
+ }
+ mWifiMetrics.setOpenNetworkRecommenderBlacklistSize(
+ SIZE_OPEN_NETWORK_RECOMMENDER_BLACKLIST);
+ mWifiMetrics.setIsWifiNetworksAvailableNotificationEnabled(
+ IS_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+ for (int i = 0; i < NUM_OPEN_NETWORK_RECOMMENDATION_UPDATES; i++) {
+ mWifiMetrics.incrementNumOpenNetworkRecommendationUpdates();
+ }
+ for (int i = 0; i < NUM_OPEN_NETWORK_CONNECT_MESSAGE_FAILED_TO_SEND; i++) {
+ mWifiMetrics.incrementNumOpenNetworkConnectMessageFailedToSend();
+ }
}
/**
@@ -618,6 +683,40 @@ public class WifiMetricsTest {
mDecodedProto.numPasspointProviderUninstallSuccess);
assertEquals(NUM_PASSPOINT_PROVIDERS_SUCCESSFULLY_CONNECTED,
mDecodedProto.numPasspointProvidersSuccessfullyConnected);
+
+ PnoScanMetrics pno_metrics = mDecodedProto.pnoScanMetrics;
+ assertNotNull(pno_metrics);
+ assertEquals(NUM_PNO_SCAN_ATTEMPTS, pno_metrics.numPnoScanAttempts);
+ assertEquals(NUM_PNO_SCAN_FAILED, pno_metrics.numPnoScanFailed);
+ assertEquals(NUM_PNO_SCAN_STARTED_OVER_OFFLOAD, pno_metrics.numPnoScanStartedOverOffload);
+ assertEquals(NUM_PNO_SCAN_FAILED_OVER_OFFLOAD, pno_metrics.numPnoScanFailedOverOffload);
+ assertEquals(NUM_PNO_FOUND_NETWORK_EVENTS, pno_metrics.numPnoFoundNetworkEvents);
+
+ for (ConnectToNetworkNotificationAndActionCount notificationCount
+ : mDecodedProto.connectToNetworkNotificationCount) {
+ assertEquals(NUM_CONNECT_TO_NETWORK_NOTIFICATIONS[notificationCount.notification],
+ notificationCount.count);
+ assertEquals(ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN,
+ notificationCount.recommender);
+ }
+ for (ConnectToNetworkNotificationAndActionCount notificationActionCount
+ : mDecodedProto.connectToNetworkNotificationActionCount) {
+ assertEquals(NUM_CONNECT_TO_NETWORK_NOTIFICATION_ACTIONS
+ [notificationActionCount.notification]
+ [notificationActionCount.action],
+ notificationActionCount.count);
+ assertEquals(ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN,
+ notificationActionCount.recommender);
+ }
+
+ assertEquals(SIZE_OPEN_NETWORK_RECOMMENDER_BLACKLIST,
+ mDecodedProto.openNetworkRecommenderBlacklistSize);
+ assertEquals(IS_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ mDecodedProto.isWifiNetworksAvailableNotificationOn);
+ assertEquals(NUM_OPEN_NETWORK_RECOMMENDATION_UPDATES,
+ mDecodedProto.numOpenNetworkRecommendationUpdates);
+ assertEquals(NUM_OPEN_NETWORK_CONNECT_MESSAGE_FAILED_TO_SEND,
+ mDecodedProto.numOpenNetworkConnectMessageFailedToSend);
}
/**
@@ -1171,6 +1270,39 @@ public class WifiMetricsTest {
a(WifiMetrics.MAX_CONNECTABLE_BSSID_NETWORK_BUCKET), a(1));
}
+ /**
+ * Test Open Network Notification blacklist size and feature state are not cleared when proto
+ * is dumped.
+ */
+ public void testOpenNetworkNotificationBlacklistSizeAndFeatureStateNotCleared()
+ throws Exception {
+ mWifiMetrics.setOpenNetworkRecommenderBlacklistSize(
+ SIZE_OPEN_NETWORK_RECOMMENDER_BLACKLIST);
+ mWifiMetrics.setIsWifiNetworksAvailableNotificationEnabled(
+ IS_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+ for (int i = 0; i < NUM_OPEN_NETWORK_RECOMMENDATION_UPDATES; i++) {
+ mWifiMetrics.incrementNumOpenNetworkRecommendationUpdates();
+ }
+
+ // This should clear most metrics in mWifiMetrics
+ dumpProtoAndDeserialize();
+ assertEquals(SIZE_OPEN_NETWORK_RECOMMENDER_BLACKLIST,
+ mDecodedProto.openNetworkRecommenderBlacklistSize);
+ assertEquals(IS_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ mDecodedProto.isWifiNetworksAvailableNotificationOn);
+ assertEquals(NUM_OPEN_NETWORK_RECOMMENDATION_UPDATES,
+ mDecodedProto.numOpenNetworkRecommendationUpdates);
+
+ // Check that blacklist size and feature state persist on next dump but
+ // others do not.
+ dumpProtoAndDeserialize();
+ assertEquals(SIZE_OPEN_NETWORK_RECOMMENDER_BLACKLIST,
+ mDecodedProto.openNetworkRecommenderBlacklistSize);
+ assertEquals(IS_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ mDecodedProto.isWifiNetworksAvailableNotificationOn);
+ assertEquals(0, mDecodedProto.numOpenNetworkRecommendationUpdates);
+ }
+
/** short hand for instantiating an anonymous int array, instead of 'new int[]{a1, a2, ...}' */
private int[] a(int... element) {
return element;
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
index 4965a35c2..3d3af364c 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
@@ -23,12 +23,12 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import android.content.Context;
-import android.content.res.Resources;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.net.wifi.WifiInfo;
import android.os.SystemClock;
+import android.test.mock.MockResources;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.LocalLog;
import android.util.Pair;
@@ -41,6 +41,7 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import java.util.ArrayList;
import java.util.HashSet;
@@ -52,6 +53,8 @@ import java.util.List;
@SmallTest
public class WifiNetworkSelectorTest {
+ private static final int RSSI_BUMP = 1;
+
/** Sets up test. */
@Before
public void setUp() throws Exception {
@@ -68,22 +71,6 @@ public class WifiNetworkSelectorTest {
mDummyEvaluator.setEvaluatorToSelectCandidate(true);
when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
- mThresholdMinimumRssi2G = mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
- mThresholdMinimumRssi5G = mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
- mThresholdQualifiedRssi2G = mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
- mThresholdQualifiedRssi5G = mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
- mStayOnNetworkMinimumTxRate = mResource.getInteger(
- R.integer.config_wifi_framework_min_tx_rate_for_staying_on_network);
- mStayOnNetworkMinimumRxRate = mResource.getInteger(
- R.integer.config_wifi_framework_min_rx_rate_for_staying_on_network);
- mThresholdSaturatedRssi2G = mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
- mThresholdSaturatedRssi5G = mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
}
/** Cleans up test. */
@@ -145,7 +132,11 @@ public class WifiNetworkSelectorTest {
private DummyNetworkEvaluator mDummyEvaluator = new DummyNetworkEvaluator();
@Mock private WifiConfigManager mWifiConfigManager;
@Mock private Context mContext;
- @Mock private Resources mResource;
+
+ // For simulating the resources, we use a Spy on a MockResource
+ // (which is really more of a stub than a mock, in spite if its name).
+ // This is so that we get errors on any calls that we have not explicitly set up.
+ @Spy private MockResources mResource = new MockResources();
@Mock private WifiInfo mWifiInfo;
@Mock private Clock mClock;
private LocalLog mLocalLog;
@@ -155,40 +146,32 @@ public class WifiNetworkSelectorTest {
private int mThresholdQualifiedRssi5G;
private int mStayOnNetworkMinimumTxRate;
private int mStayOnNetworkMinimumRxRate;
- private int mThresholdSaturatedRssi2G;
- private int mThresholdSaturatedRssi5G;
private void setupContext() {
when(mContext.getResources()).thenReturn(mResource);
}
+ private int setupIntegerResource(int resourceName, int value) {
+ doReturn(value).when(mResource).getInteger(resourceName);
+ return value;
+ }
+
private void setupResources() {
- when(mResource.getBoolean(
- R.bool.config_wifi_framework_enable_associated_network_selection)).thenReturn(true);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz))
- .thenReturn(-70);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz))
- .thenReturn(-73);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz))
- .thenReturn(-82);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz))
- .thenReturn(-85);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_max_tx_rate_for_full_scan))
- .thenReturn(8);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_max_rx_rate_for_full_scan))
- .thenReturn(8);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz))
- .thenReturn(-57);
- when(mResource.getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz))
- .thenReturn(-60);
+ doReturn(true).when(mResource).getBoolean(
+ R.bool.config_wifi_framework_enable_associated_network_selection);
+
+ mThresholdMinimumRssi2G = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz, -79);
+ mThresholdMinimumRssi5G = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz, -76);
+ mThresholdQualifiedRssi2G = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz, -73);
+ mThresholdQualifiedRssi5G = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz, -70);
+ mStayOnNetworkMinimumTxRate = setupIntegerResource(
+ R.integer.config_wifi_framework_min_tx_rate_for_staying_on_network, 16);
+ mStayOnNetworkMinimumRxRate = setupIntegerResource(
+ R.integer.config_wifi_framework_min_rx_rate_for_staying_on_network, 16);
}
private void setupWifiInfo() {
@@ -279,7 +262,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2437, 5180};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP, mThresholdMinimumRssi5G + RSSI_BUMP};
int[] securities = {SECURITY_PSK, SECURITY_PSK};
// Make a network selection.
@@ -318,7 +301,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2437, 5180};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP, mThresholdMinimumRssi5G + RSSI_BUMP};
int[] securities = {SECURITY_PSK, SECURITY_PSK};
// Make a network selection.
@@ -483,7 +466,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2437, 2457};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 20, mThresholdMinimumRssi2G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + 20, mThresholdMinimumRssi2G + RSSI_BUMP};
int[] securities = {SECURITY_PSK, SECURITY_PSK};
// Make a network selection to connect to test1.
@@ -534,8 +517,8 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "6c:f3:7f:ae:8c:f5"};
int[] freqs = {2437, 5180, 5181};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1,
- mThresholdMinimumRssi5G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP, mThresholdMinimumRssi5G + RSSI_BUMP,
+ mThresholdMinimumRssi5G + RSSI_BUMP};
int[] securities = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK};
ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
@@ -581,7 +564,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2437, 5180};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP, mThresholdMinimumRssi5G + RSSI_BUMP};
int[] securities = {SECURITY_PSK, SECURITY_PSK};
ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
@@ -961,7 +944,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2437, 5180};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP, mThresholdMinimumRssi5G + RSSI_BUMP};
mDummyEvaluator.setEvaluatorToSelectCandidate(false);
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(
@@ -990,7 +973,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3"};
int[] freqs = {2437, 5180};
String[] caps = {"[ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP};
int[] securities = {SECURITY_NONE};
mDummyEvaluator.setEvaluatorToSelectCandidate(false);
@@ -1027,7 +1010,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2437, 5180};
String[] caps = {"[ESS]", "[ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP, mThresholdMinimumRssi5G + RSSI_BUMP};
mDummyEvaluator.setEvaluatorToSelectCandidate(false);
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(
@@ -1055,7 +1038,7 @@ public class WifiNetworkSelectorTest {
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2437, 5180};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] levels = {mThresholdMinimumRssi2G + RSSI_BUMP, mThresholdMinimumRssi5G + RSSI_BUMP};
mDummyEvaluator.setEvaluatorToSelectCandidate(false);
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java
deleted file mode 100644
index 27055a885..000000000
--- a/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2016 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.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.wifi.ScanResult;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.test.TestLooper;
-import android.provider.Settings;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit tests for {@link WifiNotificationController}.
- */
-public class WifiNotificationControllerTest {
-
- @Mock private Context mContext;
- @Mock private Resources mResources;
- @Mock private FrameworkFacade mFrameworkFacade;
- @Mock private NotificationManager mNotificationManager;
- @Mock private UserManager mUserManager;
- private WifiNotificationController mNotificationController;
-
-
- /** Initialize objects before each test run. */
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
- .thenReturn(mNotificationManager);
- when(mFrameworkFacade.getIntegerSetting(mContext,
- Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1)).thenReturn(1);
- when(mContext.getSystemService(Context.USER_SERVICE))
- .thenReturn(mUserManager);
- when(mContext.getResources()).thenReturn(mResources);
-
- TestLooper mock_looper = new TestLooper();
- mNotificationController = new WifiNotificationController(
- mContext, mock_looper.getLooper(), mFrameworkFacade,
- mock(Notification.Builder.class));
- mNotificationController.handleScreenStateChanged(true);
- }
-
- private List<ScanDetail> createOpenScanResults() {
- List<ScanDetail> scanResults = new ArrayList<>();
- ScanResult scanResult = new ScanResult();
- scanResult.capabilities = "[ESS]";
- scanResults.add(new ScanDetail(scanResult, null /* networkDetail */));
- return scanResults;
- }
-
- /**
- * When scan results with open networks are handled, a notification is posted.
- */
- @Test
- public void handleScanResults_hasOpenNetworks_notificationDisplayed() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /**
- * When scan results with no open networks are handled, a notification is not posted.
- */
- @Test
- public void handleScanResults_emptyList_notificationNotDisplayed() {
- mNotificationController.handleScanResults(new ArrayList<>());
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /**
- * When a notification is showing and scan results with no open networks are handled, the
- * notification is cleared.
- */
- @Test
- public void handleScanResults_notificationShown_emptyList_notificationCleared() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- mNotificationController.handleScanResults(new ArrayList<>());
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
- /**
- * When a notification is showing, screen is off, and scan results with no open networks are
- * handled, the notification is cleared.
- */
- @Test
- public void handleScanResults_notificationShown_screenOff_emptyList_notificationCleared() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- mNotificationController.handleScreenStateChanged(false);
- mNotificationController.handleScanResults(new ArrayList<>());
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
-
- /**
- * If notification is showing, do not post another notification.
- */
- @Test
- public void handleScanResults_notificationShowing_doesNotRepostNotification() {
- mNotificationController.handleScanResults(createOpenScanResults());
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /**
- * When {@link WifiNotificationController#clearPendingNotification(boolean)} is called and a
- * notification is shown, clear the notification.
- */
- @Test
- public void clearPendingNotification_clearsNotificationIfOneIsShowing() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- mNotificationController.clearPendingNotification(true);
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
-
- /**
- * When {@link WifiNotificationController#clearPendingNotification(boolean)} is called and a
- * notification was not previously shown, do not clear the notification.
- */
- @Test
- public void clearPendingNotification_doesNotClearNotificationIfNoneShowing() {
- mNotificationController.clearPendingNotification(true);
-
- verify(mNotificationManager, never()).cancelAsUser(any(), anyInt(), any());
- }
-
- /**
- * When screen is off and notification is not displayed, notification is not posted on handling
- * new scan results with open networks.
- */
- @Test
- public void screenOff_handleScanResults_notificationNotDisplayed() {
- mNotificationController.handleScreenStateChanged(false);
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} disables the feature. */
- @Test
- public void userHasDisallowConfigWifiRestriction_notificationNotDisplayed() {
- when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
- .thenReturn(true);
-
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} clears the showing notification. */
- @Test
- public void userHasDisallowConfigWifiRestriction_showingNotificationIsCleared() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
- .thenReturn(true);
-
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
index 24d3afa18..6f01c8eb2 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
@@ -48,6 +48,18 @@ public class WifiScoreReportTest {
private static final int CELLULAR_THRESHOLD_SCORE = 50;
+ class FakeClock extends Clock {
+ long mWallClockMillis = 1500000000000L;
+ int mStepMillis = 1001;
+
+ @Override
+ public long getWallClockMillis() {
+ mWallClockMillis += mStepMillis;
+ return mWallClockMillis;
+ }
+ }
+
+ FakeClock mClock;
WifiConfiguration mWifiConfiguration;
WifiScoreReport mWifiScoreReport;
ScanDetailCache mScanDetailCache;
@@ -122,7 +134,8 @@ public class WifiScoreReportTest {
when(mWifiConfigManager.getScanDetailCacheForNetwork(anyInt()))
.thenReturn(mScanDetailCache);
when(mContext.getResources()).thenReturn(mResources);
- mWifiScoreReport = new WifiScoreReport(mContext, mWifiConfigManager, new Clock());
+ mClock = new FakeClock();
+ mWifiScoreReport = new WifiScoreReport(mContext, mWifiConfigManager, mClock);
}
/**
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 055050deb..e43bdc201 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -400,7 +400,9 @@ public class WifiServiceImplTest {
public void testSetWifiEnabledFromNetworkSettingsHolderWhenInAirplaneMode() throws Exception {
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
- when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
+ when(mContext.checkPermission(
+ eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
assertTrue(mWifiServiceImpl.setWifiEnabled(SYSUI_PACKAGE_NAME, true));
verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
}
@@ -413,7 +415,9 @@ public class WifiServiceImplTest {
public void testSetWifiEnabledFromAppFailsWhenInAirplaneMode() throws Exception {
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
- when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
+ when(mContext.checkPermission(
+ eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
}
@@ -426,7 +430,9 @@ public class WifiServiceImplTest {
public void testSetWifiEnabledFromNetworkSettingsHolderWhenApEnabled() throws Exception {
when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
- when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
+ when(mContext.checkPermission(
+ eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(SYSUI_PACKAGE_NAME, true));
verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
@@ -438,7 +444,9 @@ public class WifiServiceImplTest {
@Test
public void testSetWifiEnabledFromAppFailsWhenApEnabled() throws Exception {
when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
- when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
+ when(mContext.checkPermission(
+ eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
verify(mSettingsStore, never()).handleWifiToggled(anyBoolean());
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 2e96f3fca..090224e4e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -30,6 +30,7 @@ import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERR
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -42,9 +43,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
import android.net.ConnectivityManager;
import android.net.DhcpResults;
import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
+import android.net.NetworkRequest;
import android.net.dhcp.DhcpClient;
import android.net.ip.IpClient;
import android.net.wifi.IApInterface;
@@ -74,6 +79,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -97,6 +103,7 @@ import com.android.internal.util.StateMachine;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
+import com.android.server.wifi.util.WifiPermissionsUtil;
import org.junit.After;
import org.junit.Before;
@@ -119,6 +126,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
/**
* Unit tests for {@link com.android.server.wifi.WifiStateMachine}.
@@ -133,11 +141,15 @@ public class WifiStateMachineTest {
(ActivityManager.isLowRamDeviceStatic()
? WifiStateMachine.NUM_LOG_RECS_VERBOSE_LOW_MEMORY
: WifiStateMachine.NUM_LOG_RECS_VERBOSE);
- private static final int FRAMEWORK_NETWORK_ID = 7;
+ private static final int FRAMEWORK_NETWORK_ID = 0;
private static final int TEST_RSSI = -54;
+ private static final int TEST_NETWORK_ID = 54;
+ private static final int TEST_VALID_NETWORK_SCORE = 54;
+ private static final int TEST_OUTSCORED_NETWORK_SCORE = 100;
private static final int WPS_SUPPLICANT_NETWORK_ID = 5;
private static final int WPS_FRAMEWORK_NETWORK_ID = 10;
private static final String DEFAULT_TEST_SSID = "\"GoogleGuest\"";
+ private static final String OP_PACKAGE_NAME = "com.xxx";
private long mBinderToken;
@@ -224,7 +236,9 @@ public class WifiStateMachineTest {
mAlarmManager.getAlarmManager());
when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(
- mock(ConnectivityManager.class));
+ mConnectivityManager);
+
+ when(context.getOpPackageName()).thenReturn(OP_PACKAGE_NAME);
return context;
}
@@ -310,6 +324,7 @@ public class WifiStateMachineTest {
HandlerThread mP2pThread;
HandlerThread mSyncThread;
AsyncChannel mWsmAsyncChannel;
+ AsyncChannel mNetworkFactoryChannel;
TestAlarmManager mAlarmManager;
MockWifiMonitor mWifiMonitor;
TestLooper mLooper;
@@ -318,6 +333,7 @@ public class WifiStateMachineTest {
FrameworkFacade mFrameworkFacade;
IpClient.Callback mIpClientCallback;
PhoneStateListener mPhoneStateListener;
+ NetworkRequest mDefaultNetworkRequest;
final ArgumentCaptor<SoftApManager.Listener> mSoftApManagerListenerCaptor =
ArgumentCaptor.forClass(SoftApManager.Listener.class);
@@ -338,6 +354,7 @@ public class WifiStateMachineTest {
@Mock IClientInterface mClientInterface;
@Mock IBinder mApInterfaceBinder;
@Mock IBinder mClientInterfaceBinder;
+ @Mock IBinder mPackageManagerBinder;
@Mock WifiConfigManager mWifiConfigManager;
@Mock WifiNative mWifiNative;
@Mock WifiConnectivityManager mWifiConnectivityManager;
@@ -345,11 +362,14 @@ public class WifiStateMachineTest {
@Mock WifiStateTracker mWifiStateTracker;
@Mock PasspointManager mPasspointManager;
@Mock SelfRecovery mSelfRecovery;
+ @Mock WifiPermissionsUtil mWifiPermissionsUtil;
@Mock IpClient mIpClient;
@Mock TelephonyManager mTelephonyManager;
@Mock WrongPasswordNotifier mWrongPasswordNotifier;
@Mock Clock mClock;
@Mock ScanDetailCache mScanDetailCache;
+ @Mock BaseWifiDiagnostics mWifiDiagnostics;
+ @Mock ConnectivityManager mConnectivityManager;
public WifiStateMachineTest() throws Exception {
}
@@ -374,8 +394,7 @@ public class WifiStateMachineTest {
when(mWifiInjector.getBuildProperties()).thenReturn(mBuildProperties);
when(mWifiInjector.getKeyStore()).thenReturn(mock(KeyStore.class));
when(mWifiInjector.getWifiBackupRestore()).thenReturn(mock(WifiBackupRestore.class));
- when(mWifiInjector.makeWifiDiagnostics(anyObject())).thenReturn(
- mock(BaseWifiDiagnostics.class));
+ when(mWifiInjector.makeWifiDiagnostics(anyObject())).thenReturn(mWifiDiagnostics);
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWifiInjector.getWifiConfigManager()).thenReturn(mWifiConfigManager);
when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
@@ -390,6 +409,7 @@ public class WifiStateMachineTest {
when(mWifiInjector.getWifiMonitor()).thenReturn(mWifiMonitor);
when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
when(mWifiInjector.getSelfRecovery()).thenReturn(mSelfRecovery);
+ when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil);
when(mWifiInjector.makeTelephonyManager()).thenReturn(mTelephonyManager);
when(mWifiInjector.getClock()).thenReturn(mClock);
@@ -438,15 +458,11 @@ public class WifiStateMachineTest {
}
}).when(mTelephonyManager).listen(any(PhoneStateListener.class), anyInt());
+ when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
initializeWsm();
}
- private void initializeWsm() throws Exception {
- mWsm = new WifiStateMachine(mContext, mFrameworkFacade, mLooper.getLooper(),
- mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative,
- mWrongPasswordNotifier);
- mWsmThread = getWsmHandlerThread(mWsm);
-
+ private void registerAsyncChannel(Consumer<AsyncChannel> consumer, Messenger messenger) {
final AsyncChannel channel = new AsyncChannel();
Handler handler = new Handler(mLooper.getLooper()) {
@Override
@@ -454,7 +470,7 @@ public class WifiStateMachineTest {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- mWsmAsyncChannel = channel;
+ consumer.accept(channel);
} else {
Log.d(TAG, "Failed to connect Command channel " + this);
}
@@ -466,15 +482,50 @@ public class WifiStateMachineTest {
}
};
- channel.connect(mContext, handler, mWsm.getMessenger());
+ channel.connect(mContext, handler, messenger);
mLooper.dispatchAll();
- /* Now channel is supposed to be connected */
+ }
+
+ private void initializeWsm() throws Exception {
+ mWsm = new WifiStateMachine(mContext, mFrameworkFacade, mLooper.getLooper(),
+ mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative,
+ mWrongPasswordNotifier);
+ mWsmThread = getWsmHandlerThread(mWsm);
+
+ registerAsyncChannel((x) -> {
+ mWsmAsyncChannel = x;
+ }, mWsm.getMessenger());
mBinderToken = Binder.clearCallingIdentity();
/* Send the BOOT_COMPLETED message to setup some WSM state. */
mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED);
mLooper.dispatchAll();
+
+ /* Simulate the initial NetworkRequest sent in by ConnectivityService. */
+ ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
+ verify(mConnectivityManager, atLeast(2)).registerNetworkFactory(
+ captor.capture(), anyString());
+ Messenger networkFactoryMessenger = captor.getAllValues().get(0);
+ registerAsyncChannel((x) -> {
+ mNetworkFactoryChannel = x;
+ }, networkFactoryMessenger);
+
+ mDefaultNetworkRequest = new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+ sendDefaultNetworkRequest(TEST_VALID_NETWORK_SCORE);
+ }
+
+ /**
+ * Helper function to resend the cached network request (id == 0) with the specified score.
+ * Note: If you need to add a separate network request, don't use the builder to create one
+ * since the new request object will again default to id == 0.
+ */
+ private void sendDefaultNetworkRequest(int score) {
+ mNetworkFactoryChannel.sendMessage(
+ NetworkFactory.CMD_REQUEST_NETWORK, score, 0, mDefaultNetworkRequest);
+ mLooper.dispatchAll();
}
@After
@@ -490,6 +541,7 @@ public class WifiStateMachineTest {
mSyncThread = null;
mWsmAsyncChannel = null;
mWsm = null;
+ mNetworkFactoryChannel = null;
}
@Test
@@ -740,18 +792,15 @@ public class WifiStateMachineTest {
(Intent) argThat(new WifiEnablingStateIntentMatcher()), any());
}
- /**
- * Verifies that configs can be removed when in client mode.
- */
- @Test
- public void canRemoveNetworkConfigInClientMode() throws Exception {
+ private void canRemoveNetwork() {
boolean result;
when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
- initializeAndAddNetworkAndVerifySuccess();
mLooper.startAutoDispatch();
result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0);
mLooper.stopAutoDispatch();
+
assertTrue(result);
+ verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
}
/**
@@ -759,23 +808,21 @@ public class WifiStateMachineTest {
*/
@Test
public void canRemoveNetworkConfigWhenWifiDisabled() {
- boolean result;
- when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
- mLooper.startAutoDispatch();
- result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0);
- mLooper.stopAutoDispatch();
-
- assertTrue(result);
- verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
+ canRemoveNetwork();
}
+
/**
- * Verifies that configs can be forgotten when in client mode.
+ * Verifies that configs can be removed when in client mode.
*/
@Test
- public void canForgetNetworkConfigInClientMode() throws Exception {
- when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
+ public void canRemoveNetworkConfigInClientMode() throws Exception {
initializeAndAddNetworkAndVerifySuccess();
+ canRemoveNetwork();
+ }
+
+ private void canForgetNetwork() {
+ when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID);
mLooper.dispatchAll();
verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
@@ -786,10 +833,109 @@ public class WifiStateMachineTest {
*/
@Test
public void canForgetNetworkConfigWhenWifiDisabled() throws Exception {
- when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
- mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID);
- mLooper.dispatchAll();
- verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
+ canForgetNetwork();
+ }
+
+ /**
+ * Verifies that configs can be forgotten when in client mode.
+ */
+ @Test
+ public void canForgetNetworkConfigInClientMode() throws Exception {
+ initializeAndAddNetworkAndVerifySuccess();
+ canForgetNetwork();
+ }
+
+ private void canSaveNetworkConfig() {
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+
+ int networkId = TEST_NETWORK_ID;
+ when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
+ .thenReturn(new NetworkUpdateResult(networkId));
+ when(mWifiConfigManager.enableNetwork(eq(networkId), eq(false), anyInt()))
+ .thenReturn(true);
+
+ mLooper.startAutoDispatch();
+ Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.SAVE_NETWORK, config);
+ mLooper.stopAutoDispatch();
+ assertEquals(WifiManager.SAVE_NETWORK_SUCCEEDED, reply.what);
+
+ verify(mWifiConfigManager).addOrUpdateNetwork(any(WifiConfiguration.class), anyInt());
+ verify(mWifiConfigManager).enableNetwork(eq(networkId), eq(false), anyInt());
+ }
+
+ /**
+ * Verifies that configs can be saved when not in client mode.
+ */
+ @Test
+ public void canSaveNetworkConfigWhenWifiDisabled() throws Exception {
+ canSaveNetworkConfig();
+ }
+
+ /**
+ * Verifies that configs can be saved when in client mode.
+ */
+ @Test
+ public void canSaveNetworkConfigInClientMode() throws Exception {
+ loadComponentsInStaMode();
+ canSaveNetworkConfig();
+ }
+
+ /**
+ * Verifies that null configs are rejected in SAVE_NETWORK message.
+ */
+ @Test
+ public void saveNetworkConfigFailsWithNullConfig() throws Exception {
+ mLooper.startAutoDispatch();
+ Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.SAVE_NETWORK, null);
+ mLooper.stopAutoDispatch();
+ assertEquals(WifiManager.SAVE_NETWORK_FAILED, reply.what);
+
+ verify(mWifiConfigManager, never())
+ .addOrUpdateNetwork(any(WifiConfiguration.class), anyInt());
+ verify(mWifiConfigManager, never())
+ .enableNetwork(anyInt(), anyBoolean(), anyInt());
+ }
+
+ /**
+ * Verifies that configs save fails when the addition of network fails.
+ */
+ @Test
+ public void saveNetworkConfigFailsWithConfigAddFailure() throws Exception {
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+
+ when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
+ .thenReturn(new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID));
+
+ mLooper.startAutoDispatch();
+ Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.SAVE_NETWORK, config);
+ mLooper.stopAutoDispatch();
+ assertEquals(WifiManager.SAVE_NETWORK_FAILED, reply.what);
+
+ verify(mWifiConfigManager).addOrUpdateNetwork(any(WifiConfiguration.class), anyInt());
+ verify(mWifiConfigManager, never())
+ .enableNetwork(anyInt(), anyBoolean(), anyInt());
+ }
+
+ /**
+ * Verifies that configs save fails when the enable of network fails.
+ */
+ @Test
+ public void saveNetworkConfigFailsWithConfigEnableFailure() throws Exception {
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+
+ int networkId = 5;
+ when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
+ .thenReturn(new NetworkUpdateResult(networkId));
+ when(mWifiConfigManager.enableNetwork(eq(networkId), eq(false), anyInt()))
+ .thenReturn(false);
+
+ mLooper.startAutoDispatch();
+ Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.SAVE_NETWORK, config);
+ mLooper.stopAutoDispatch();
+ assertEquals(WifiManager.SAVE_NETWORK_FAILED, reply.what);
+
+ verify(mWifiConfigManager).addOrUpdateNetwork(any(WifiConfiguration.class), anyInt());
+ verify(mWifiConfigManager).enableNetwork(eq(networkId), eq(false), anyInt());
}
/**
@@ -829,6 +975,7 @@ public class WifiStateMachineTest {
.thenReturn(new NetworkUpdateResult(0));
when(mWifiConfigManager.getSavedNetworks()).thenReturn(Arrays.asList(config));
when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config);
+ when(mWifiConfigManager.getConfiguredNetworkWithPassword(0)).thenReturn(config);
mLooper.startAutoDispatch();
mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config);
@@ -937,28 +1084,87 @@ public class WifiStateMachineTest {
hiddenNetworkSet);
}
- @Test
- public void connect() throws Exception {
- initializeAndAddNetworkAndVerifySuccess();
- when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(true);
- when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(true);
+ private void setupAndStartConnectSequence(WifiConfiguration config) throws Exception {
+ when(mWifiConfigManager.enableNetwork(eq(config.networkId), eq(true), anyInt()))
+ .thenReturn(true);
+ when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(config.networkId), anyInt()))
+ .thenReturn(true);
+ when(mWifiConfigManager.getConfiguredNetwork(eq(config.networkId)))
+ .thenReturn(config);
+ when(mWifiConfigManager.getConfiguredNetworkWithPassword(eq(config.networkId)))
+ .thenReturn(config);
mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
mLooper.dispatchAll();
verify(mWifiNative).removeAllNetworks();
mLooper.startAutoDispatch();
- assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
+ assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, config.networkId, true));
mLooper.stopAutoDispatch();
+ }
- verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
- verify(mWifiConnectivityManager).setUserConnectChoice(eq(0));
+ private void validateSuccessfulConnectSequence(WifiConfiguration config) {
+ verify(mWifiConfigManager).enableNetwork(eq(config.networkId), eq(true), anyInt());
+ verify(mWifiConnectivityManager).setUserConnectChoice(eq(config.networkId));
+ verify(mWifiConnectivityManager).prepareForForcedConnection(eq(config.networkId));
+ verify(mWifiConfigManager).getConfiguredNetworkWithPassword(eq(config.networkId));
+ verify(mWifiNative).connectToNetwork(eq(config));
+ }
+
+ private void validateFailureConnectSequence(WifiConfiguration config) {
+ verify(mWifiConfigManager).enableNetwork(eq(config.networkId), eq(true), anyInt());
+ verify(mWifiConnectivityManager).setUserConnectChoice(eq(config.networkId));
+ verify(mWifiConnectivityManager).prepareForForcedConnection(eq(config.networkId));
+ verify(mWifiConfigManager, never()).getConfiguredNetworkWithPassword(eq(config.networkId));
+ verify(mWifiNative, never()).connectToNetwork(eq(config));
+ }
+
+ /**
+ * Tests the network connection initiation sequence with the default network request pending
+ * from WifiNetworkFactory.
+ * This simulates the connect sequence using the public
+ * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we invoke
+ * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
+ */
+ @Test
+ public void triggerConnect() throws Exception {
+ loadComponentsInStaMode();
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+ config.networkId = FRAMEWORK_NETWORK_ID;
+ setupAndStartConnectSequence(config);
+ validateSuccessfulConnectSequence(config);
+ }
+
+ /**
+ * Tests the network connection initiation sequence with no network request pending from
+ * from WifiNetworkFactory.
+ * This simulates the connect sequence using the public
+ * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we don't invoke
+ * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
+ */
+ @Test
+ public void triggerConnectWithNoNetworkRequest() throws Exception {
+ loadComponentsInStaMode();
+ // Change the network score to remove the network request.
+ sendDefaultNetworkRequest(TEST_OUTSCORED_NETWORK_SCORE);
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+ config.networkId = FRAMEWORK_NETWORK_ID;
+ setupAndStartConnectSequence(config);
+ validateFailureConnectSequence(config);
+ }
+
+ /**
+ * Tests the entire successful network connection flow.
+ */
+ @Test
+ public void connect() throws Exception {
+ triggerConnect();
when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
.thenReturn(mScanDetailCache);
when(mScanDetailCache.getScanDetail(sBSSID)).thenReturn(
getGoogleGuestScanDetail(TEST_RSSI, sBSSID, sFreq));
- when(mScanDetailCache.get(sBSSID)).thenReturn(
+ when(mScanDetailCache.getScanResult(sBSSID)).thenReturn(
getGoogleGuestScanDetail(TEST_RSSI, sBSSID, sFreq).getScanResult());
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
@@ -988,6 +1194,54 @@ public class WifiStateMachineTest {
assertEquals("ConnectedState", getCurrentState().getName());
}
+ /**
+ * Tests the network connection initiation sequence with no network request pending from
+ * from WifiNetworkFactory when we're already connected to a different network.
+ * This simulates the connect sequence using the public
+ * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we invoke
+ * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
+ */
+ @Test
+ public void triggerConnectWithNoNetworkRequestAndAlreadyConnected() throws Exception {
+ // Simulate the first connection.
+ connect();
+
+ // Change the network score to remove the network request.
+ sendDefaultNetworkRequest(TEST_OUTSCORED_NETWORK_SCORE);
+
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+ config.networkId = FRAMEWORK_NETWORK_ID + 1;
+ setupAndStartConnectSequence(config);
+ validateSuccessfulConnectSequence(config);
+ verify(mWifiPermissionsUtil, times(2)).checkNetworkSettingsPermission(anyInt());
+ }
+
+ /**
+ * Tests the network connection initiation sequence from a non-privileged app with no network
+ * request pending from from WifiNetworkFactory when we're already connected to a different
+ * network.
+ * This simulates the connect sequence using the public
+ * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we don't invoke
+ * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
+ */
+ @Test
+ public void triggerConnectWithNoNetworkRequestAndAlreadyConnectedButNonPrivilegedApp()
+ throws Exception {
+ // Simulate the first connection.
+ connect();
+
+ // Change the network score to remove the network request.
+ sendDefaultNetworkRequest(TEST_OUTSCORED_NETWORK_SCORE);
+
+ when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
+
+ WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
+ config.networkId = FRAMEWORK_NETWORK_ID + 1;
+ setupAndStartConnectSequence(config);
+ validateFailureConnectSequence(config);
+ verify(mWifiPermissionsUtil, times(2)).checkNetworkSettingsPermission(anyInt());
+ }
+
@Test
public void connectWithNoEnablePermission() throws Exception {
initializeAndAddNetworkAndVerifySuccess();
@@ -1560,31 +1814,90 @@ public class WifiStateMachineTest {
}
/**
- * Verify successful Wps PBC network connection.
+ * Test that we disconnect from a network if it was removed while we are in the
+ * ObtainingIpState.
+ */
+ @Test
+ public void disconnectFromNetworkWhenRemovedWhileObtainingIpAddr() throws Exception {
+ initializeAndAddNetworkAndVerifySuccess();
+
+ when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(true);
+ when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(true);
+
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+ verify(mWifiNative).removeAllNetworks();
+
+ mLooper.startAutoDispatch();
+ assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
+ mLooper.stopAutoDispatch();
+
+ verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
+ verify(mWifiConnectivityManager).setUserConnectChoice(eq(0));
+ when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
+ .thenReturn(mScanDetailCache);
+
+ when(mScanDetailCache.getScanDetail(sBSSID)).thenReturn(
+ getGoogleGuestScanDetail(TEST_RSSI, sBSSID, sFreq));
+ when(mScanDetailCache.getScanResult(sBSSID)).thenReturn(
+ getGoogleGuestScanDetail(TEST_RSSI, sBSSID, sFreq).getScanResult());
+
+ mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
+ mLooper.dispatchAll();
+
+ mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
+ mLooper.dispatchAll();
+
+ assertEquals("ObtainingIpState", getCurrentState().getName());
+
+ // now remove the config
+ when(mWifiConfigManager.removeNetwork(eq(FRAMEWORK_NETWORK_ID), anyInt()))
+ .thenReturn(true);
+ mWsm.sendMessage(WifiManager.FORGET_NETWORK, FRAMEWORK_NETWORK_ID, MANAGED_PROFILE_UID);
+ mLooper.dispatchAll();
+ verify(mWifiConfigManager).removeNetwork(eq(FRAMEWORK_NETWORK_ID), anyInt());
+
+ reset(mWifiConfigManager);
+
+ when(mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID)).thenReturn(null);
+
+ DhcpResults dhcpResults = new DhcpResults();
+ dhcpResults.setGateway("1.2.3.4");
+ dhcpResults.setIpAddress("192.168.1.100", 0);
+ dhcpResults.addDns("8.8.8.8");
+ dhcpResults.setLeaseDuration(3600);
+
+ injectDhcpSuccess(dhcpResults);
+ mLooper.dispatchAll();
+
+ assertEquals("DisconnectingState", getCurrentState().getName());
+ }
+
+ /**
+ * Sunny-day scenario for WPS connections. Verifies that after a START_WPS and
+ * NETWORK_CONNECTION_EVENT command, WifiStateMachine will have transitioned to ObtainingIpState
*/
@Test
public void wpsPbcConnectSuccess() throws Exception {
loadComponentsInStaMode();
mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
mLooper.dispatchAll();
+ assertEquals("DisconnectedState", getCurrentState().getName());
- when(mWifiNative.startWpsPbc(eq(sBSSID))).thenReturn(true);
WpsInfo wpsInfo = new WpsInfo();
wpsInfo.setup = WpsInfo.PBC;
wpsInfo.BSSID = sBSSID;
-
+ when(mWifiNative.removeAllNetworks()).thenReturn(true);
+ when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
mLooper.dispatchAll();
- verify(mWifiNative).startWpsPbc(eq(sBSSID));
-
assertEquals("WpsRunningState", getCurrentState().getName());
setupMocksForWpsNetworkMigration();
-
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
mLooper.dispatchAll();
-
- assertEquals("DisconnectedState", getCurrentState().getName());
+ assertEquals("ObtainingIpState", getCurrentState().getName());
verifyMocksForWpsNetworkMigration();
}
@@ -1610,6 +1923,68 @@ public class WifiStateMachineTest {
}
/**
+ * Verify that if Supplicant generates multiple networks for a WPS configuration,
+ * WifiStateMachine cycles into DisconnectedState
+ */
+ @Test
+ public void wpsPbcConnectFailure_tooManyConfigs() throws Exception {
+ loadComponentsInStaMode();
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+ assertEquals("DisconnectedState", getCurrentState().getName());
+
+ WpsInfo wpsInfo = new WpsInfo();
+ wpsInfo.setup = WpsInfo.PBC;
+ wpsInfo.BSSID = sBSSID;
+ when(mWifiNative.removeAllNetworks()).thenReturn(true);
+ when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
+ mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
+ mLooper.dispatchAll();
+ assertEquals("WpsRunningState", getCurrentState().getName());
+
+ setupMocksForWpsNetworkMigration();
+ doAnswer(new AnswerWithArguments() {
+ public boolean answer(Map<String, WifiConfiguration> configs,
+ SparseArray<Map<String, String>> networkExtras) throws Exception {
+ configs.put("dummy1", new WifiConfiguration());
+ configs.put("dummy2", new WifiConfiguration());
+ return true;
+ }
+ }).when(mWifiNative).migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class));
+ mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
+ mLooper.dispatchAll();
+ assertTrue("DisconnectedState".equals(getCurrentState().getName()));
+ }
+
+ /**
+ * Verify that when supplicant fails to load networks during WPS, WifiStateMachine cycles into
+ * DisconnectedState
+ */
+ @Test
+ public void wpsPbcConnectFailure_migrateNetworksFailure() throws Exception {
+ loadComponentsInStaMode();
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+ assertEquals("DisconnectedState", getCurrentState().getName());
+
+ WpsInfo wpsInfo = new WpsInfo();
+ wpsInfo.setup = WpsInfo.PBC;
+ wpsInfo.BSSID = sBSSID;
+ when(mWifiNative.removeAllNetworks()).thenReturn(true);
+ when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
+ mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
+ mLooper.dispatchAll();
+ assertEquals("WpsRunningState", getCurrentState().getName());
+
+ setupMocksForWpsNetworkMigration();
+ when(mWifiNative.migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class)))
+ .thenReturn(false);
+ mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
+ mLooper.dispatchAll();
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ }
+
+ /**
* Verify successful Wps Pin Display network connection.
*/
@Test
@@ -1634,7 +2009,7 @@ public class WifiStateMachineTest {
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
mLooper.dispatchAll();
- assertEquals("DisconnectedState", getCurrentState().getName());
+ assertEquals("ObtainingIpState", getCurrentState().getName());
verifyMocksForWpsNetworkMigration();
}
@@ -1682,6 +2057,7 @@ public class WifiStateMachineTest {
verify(mWifiMetrics).incrementNumHalCrashes();
verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_HAL_CRASH));
+ verify(mWifiDiagnostics).captureBugReportData(WifiDiagnostics.REPORT_REASON_HAL_CRASH);
}
@Test
@@ -1704,16 +2080,16 @@ public class WifiStateMachineTest {
verify(mWifiMetrics).incrementNumWificondCrashes();
verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_WIFICOND_CRASH));
+ verify(mWifiDiagnostics).captureBugReportData(WifiDiagnostics.REPORT_REASON_WIFICOND_CRASH);
}
private void setupMocksForWpsNetworkMigration() {
- // Now trigger the network connection event for adding the WPS network.
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = WPS_SUPPLICANT_NETWORK_ID;
+ config.SSID = DEFAULT_TEST_SSID;
doAnswer(new AnswerWithArguments() {
public boolean answer(Map<String, WifiConfiguration> configs,
SparseArray<Map<String, String>> networkExtras) throws Exception {
- WifiConfiguration config = new WifiConfiguration();
- config.networkId = WPS_SUPPLICANT_NETWORK_ID;
- config.SSID = DEFAULT_TEST_SSID;
configs.put("dummy", config);
return true;
}
@@ -1722,6 +2098,10 @@ public class WifiStateMachineTest {
.thenReturn(new NetworkUpdateResult(WPS_FRAMEWORK_NETWORK_ID));
when(mWifiConfigManager.enableNetwork(eq(WPS_FRAMEWORK_NETWORK_ID), anyBoolean(), anyInt()))
.thenReturn(true);
+ when(mWifiNative.getFrameworkNetworkId(eq(WPS_FRAMEWORK_NETWORK_ID))).thenReturn(
+ WPS_FRAMEWORK_NETWORK_ID);
+ when(mWifiConfigManager.getConfiguredNetwork(eq(WPS_FRAMEWORK_NETWORK_ID))).thenReturn(
+ config);
}
private void verifyMocksForWpsNetworkMigration() {
@@ -1748,7 +2128,7 @@ public class WifiStateMachineTest {
.thenReturn(mScanDetailCache);
when(mScanDetailCache.getScanDetail(sBSSID1)).thenReturn(
getGoogleGuestScanDetail(TEST_RSSI, sBSSID1, sFreq1));
- when(mScanDetailCache.get(sBSSID1)).thenReturn(
+ when(mScanDetailCache.getScanResult(sBSSID1)).thenReturn(
getGoogleGuestScanDetail(TEST_RSSI, sBSSID1, sFreq1).getScanResult());
// This simulates the behavior of roaming to network with |sBSSID1|, |sFreq1|.
@@ -1776,7 +2156,7 @@ public class WifiStateMachineTest {
.thenReturn(mScanDetailCache);
when(mScanDetailCache.getScanDetail(sBSSID1)).thenReturn(
getGoogleGuestScanDetail(TEST_RSSI, sBSSID1, sFreq1));
- when(mScanDetailCache.get(sBSSID1)).thenReturn(
+ when(mScanDetailCache.getScanResult(sBSSID1)).thenReturn(
getGoogleGuestScanDetail(TEST_RSSI, sBSSID1, sFreq1).getScanResult());
// This simulates the behavior of roaming to network with |sBSSID1|, |sFreq1|.
@@ -1856,6 +2236,153 @@ public class WifiStateMachineTest {
}
/**
+ * Test that the process uid has full wifiInfo access.
+ * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
+ * returns a copy of WifiInfo.
+ */
+ @Test
+ public void testConnectedIdsAreVisibleFromOwnUid() throws Exception {
+ assertEquals(Process.myUid(), Binder.getCallingUid());
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
+ wifiInfo.setBSSID(sBSSID);
+ wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(sSSID));
+
+ connect();
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
+ assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
+ }
+
+ /**
+ * Test that connected SSID and BSSID are not exposed to an app that does not have the
+ * appropriate permissions.
+ * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
+ * returns a copy of WifiInfo.
+ */
+ @Test
+ public void testConnectedIdsAreHiddenFromRandomApp() throws Exception {
+ int actualUid = Binder.getCallingUid();
+ int fakeUid = Process.myUid() + 100000;
+ assertNotEquals(actualUid, fakeUid);
+ BinderUtil.setUid(fakeUid);
+ try {
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
+
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+
+ when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
+ anyInt())).thenReturn(false);
+
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
+ } finally {
+ BinderUtil.setUid(actualUid);
+ }
+ }
+
+ /**
+ * Test that connected SSID and BSSID are not exposed to an app that does not have the
+ * appropriate permissions, when canAccessScanResults raises a SecurityException.
+ * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
+ * returns a copy of WifiInfo.
+ */
+ @Test
+ public void testConnectedIdsAreHiddenOnSecurityException() throws Exception {
+ int actualUid = Binder.getCallingUid();
+ int fakeUid = Process.myUid() + 100000;
+ assertNotEquals(actualUid, fakeUid);
+ BinderUtil.setUid(fakeUid);
+ try {
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
+
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+
+ when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
+ anyInt())).thenThrow(new SecurityException());
+
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
+ } finally {
+ BinderUtil.setUid(actualUid);
+ }
+ }
+
+ /**
+ * Test that connected SSID and BSSID are exposed to an app that does have the
+ * appropriate permissions.
+ */
+ @Test
+ public void testConnectedIdsAreVisibleFromPermittedApp() throws Exception {
+ int actualUid = Binder.getCallingUid();
+ int fakeUid = Process.myUid() + 100000;
+ BinderUtil.setUid(fakeUid);
+ try {
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
+
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+
+ when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
+ anyInt())).thenReturn(true);
+
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
+ assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
+ // Access to our MAC address uses a different permission, make sure it is not granted
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getMacAddress());
+ } finally {
+ BinderUtil.setUid(actualUid);
+ }
+ }
+
+ /**
+ * Test that reconnectCommand() triggers connectivity scan when WifiStateMachine
+ * is in DisconnectedMode.
+ */
+ @Test
+ public void testReconnectCommandWhenDisconnected() throws Exception {
+ // Connect to network with |sBSSID|, |sFreq|, and then disconnect.
+ disconnect();
+
+ mWsm.reconnectCommand(WifiStateMachine.WIFI_WORK_SOURCE);
+ mLooper.dispatchAll();
+ verify(mWifiConnectivityManager).forceConnectivityScan(WifiStateMachine.WIFI_WORK_SOURCE);
+ }
+
+ /**
+ * Test that reconnectCommand() doesn't trigger connectivity scan when WifiStateMachine
+ * is in ConnectedMode.
+ */
+ @Test
+ public void testReconnectCommandWhenConnected() throws Exception {
+ // Connect to network with |sBSSID|, |sFreq|.
+ connect();
+
+ mWsm.reconnectCommand(WifiStateMachine.WIFI_WORK_SOURCE);
+ mLooper.dispatchAll();
+ verify(mWifiConnectivityManager, never())
+ .forceConnectivityScan(WifiStateMachine.WIFI_WORK_SOURCE);
+ }
+
+ /**
* Adds the network without putting WifiStateMachine into ConnectMode.
*/
@Test
@@ -1872,9 +2399,7 @@ public class WifiStateMachineTest {
@Test
public void testStartWps_nullWpsInfo() throws Exception {
loadComponentsInStaMode();
- mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
- assertEquals("DisconnectedState", getCurrentState().getName());
+
mLooper.startAutoDispatch();
Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.START_WPS, 0, 0,
null);
@@ -1889,9 +2414,6 @@ public class WifiStateMachineTest {
@Test
public void testSyncDisableNetwork_failure() throws Exception {
loadComponentsInStaMode();
- mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
- assertEquals("DisconnectedState", getCurrentState().getName());
when(mWifiConfigManager.disableNetwork(anyInt(), anyInt())).thenReturn(false);
mLooper.startAutoDispatch();
@@ -2151,6 +2673,43 @@ public class WifiStateMachineTest {
}
/**
+ * Verifies that WifiStateMachine sets and unsets appropriate 'RecentFailureReason' values
+ * on a WifiConfiguration when it fails association, authentication, or successfully connects
+ */
+ @Test
+ public void testExtraFailureReason_ApIsBusy() throws Exception {
+ // Setup CONNECT_MODE & a WifiConfiguration
+ initializeAndAddNetworkAndVerifySuccess();
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+ // Trigger a connection to this (CMD_START_CONNECT will actually fail, but it sets up
+ // targetNetworkId state)
+ mWsm.sendMessage(WifiStateMachine.CMD_START_CONNECT, 0, 0, sBSSID);
+ mLooper.dispatchAll();
+ // Simulate an ASSOCIATION_REJECTION_EVENT, due to the AP being busy
+ mWsm.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT, 0,
+ ISupplicantStaIfaceCallback.StatusCode.AP_UNABLE_TO_HANDLE_NEW_STA, sBSSID);
+ mLooper.dispatchAll();
+ verify(mWifiConfigManager).setRecentFailureAssociationStatus(eq(0),
+ eq(WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA));
+ assertEquals("DisconnectedState", getCurrentState().getName());
+
+ // Simulate an AUTHENTICATION_FAILURE_EVENT, which should clear the ExtraFailureReason
+ reset(mWifiConfigManager);
+ mWsm.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, 0, 0, null);
+ mLooper.dispatchAll();
+ verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
+ verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
+
+ // Simulate a NETWORK_CONNECTION_EVENT which should clear the ExtraFailureReason
+ reset(mWifiConfigManager);
+ mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
+ mLooper.dispatchAll();
+ verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
+ verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
+ }
+
+ /**
* Test that the helper method
* {@link WifiStateMachine#shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration)}
* returns true when we connect to the last selected network before expiration of
@@ -2214,20 +2773,4 @@ public class WifiStateMachineTest {
currentConfig.networkId = lastSelectedNetworkId - 1;
assertFalse(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
}
-
- /**
- * Test that {@link WifiStateMachine#syncRequestConnectionInfo()} always returns a copy of
- * WifiInfo.
- */
- @Test
- public void testSyncRequestConnectionInfoDoesNotReturnLocalReference() {
- WifiInfo wifiInfo = mWsm.getWifiInfo();
- wifiInfo.setBSSID(sBSSID);
- wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(sSSID));
-
- WifiInfo syncWifiInfo = mWsm.syncRequestConnectionInfo();
- assertEquals(wifiInfo.getSSID(), syncWifiInfo.getSSID());
- assertEquals(wifiInfo.getBSSID(), syncWifiInfo.getBSSID());
- assertFalse(wifiInfo == syncWifiInfo);
- }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java b/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java
index 261733144..cca204564 100644
--- a/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java
@@ -23,7 +23,10 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,6 +36,8 @@ import android.net.wifi.IPnoScanEvent;
import android.net.wifi.IScanEvent;
import android.net.wifi.IWifiScannerImpl;
import android.net.wifi.IWificond;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiScanner;
import android.test.suitebuilder.annotation.SmallTest;
@@ -48,6 +53,7 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
+import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
@@ -60,6 +66,8 @@ import java.util.Set;
public class WificondControlTest {
private WifiInjector mWifiInjector;
private WifiMonitor mWifiMonitor;
+ private WifiMetrics mWifiMetrics;
+ private CarrierNetworkConfig mCarrierNetworkConfig;
private WificondControl mWificondControl;
private static final String TEST_INTERFACE_NAME = "test_wlan_if";
private static final byte[] TEST_SSID =
@@ -68,7 +76,7 @@ public class WificondControlTest {
new byte[] {(byte) 0x12, (byte) 0xef, (byte) 0xa1,
(byte) 0x2c, (byte) 0x97, (byte) 0x8b};
// This the IE buffer which is consistent with TEST_SSID.
- private static final byte[] TEST_INFO_ELEMENT =
+ private static final byte[] TEST_INFO_ELEMENT_SSID =
new byte[] {
// Element ID for SSID.
(byte) 0x00,
@@ -76,6 +84,17 @@ public class WificondControlTest {
(byte) 0x0b,
// This is string "GoogleGuest"
'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ // RSN IE data indicating EAP key management.
+ private static final byte[] TEST_INFO_ELEMENT_RSN =
+ new byte[] {
+ // Element ID for RSN.
+ (byte) 0x30,
+ // Length of the element data.
+ (byte) 0x18,
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x02,
+ (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x04,
+ (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x02, (byte) 0x01, (byte) 0x00,
+ (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x01, (byte) 0x00, (byte) 0x00 };
private static final int TEST_FREQUENCY = 2456;
private static final int TEST_SIGNAL_MBM = -4500;
@@ -86,7 +105,7 @@ public class WificondControlTest {
new NativeScanResult() {{
ssid = TEST_SSID;
bssid = TEST_BSSID;
- infoElement = TEST_INFO_ELEMENT;
+ infoElement = TEST_INFO_ELEMENT_SSID;
frequency = TEST_FREQUENCY;
signalMbm = TEST_SIGNAL_MBM;
capability = TEST_CAPABILITY;
@@ -127,7 +146,10 @@ public class WificondControlTest {
public void setUp() throws Exception {
mWifiInjector = mock(WifiInjector.class);
mWifiMonitor = mock(WifiMonitor.class);
- mWificondControl = new WificondControl(mWifiInjector, mWifiMonitor);
+ mWifiMetrics = mock(WifiMetrics.class);
+ when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
+ mCarrierNetworkConfig = mock(CarrierNetworkConfig.class);
+ mWificondControl = new WificondControl(mWifiInjector, mWifiMonitor, mCarrierNetworkConfig);
}
/**
@@ -441,7 +463,8 @@ public class WificondControlTest {
assertTrue(mWificondControl.tearDownInterfaces());
// getScanResults should fail.
- assertEquals(0, mWificondControl.getScanResults().size());
+ assertEquals(0,
+ mWificondControl.getScanResults(WificondControl.SCAN_TYPE_SINGLE_SCAN).size());
}
/**
@@ -456,7 +479,12 @@ public class WificondControlTest {
NativeScanResult[] mockScanResults = {MOCK_NATIVE_SCAN_RESULT};
when(scanner.getScanResults()).thenReturn(mockScanResults);
- ArrayList<ScanDetail> returnedScanResults = mWificondControl.getScanResults();
+ ArrayList<ScanDetail> returnedScanResults = mWificondControl.getScanResults(
+ WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ // The test IEs {@link #TEST_INFO_ELEMENT} doesn't contained RSN IE, which means non-EAP
+ // AP. So verify carrier network is not checked, since EAP is currently required for a
+ // carrier network.
+ verify(mCarrierNetworkConfig, never()).isCarrierNetwork(anyString());
assertEquals(mockScanResults.length, returnedScanResults.size());
// Since NativeScanResult is organized differently from ScanResult, this only checks
// a few fields.
@@ -471,6 +499,60 @@ public class WificondControlTest {
}
/**
+ * Verifies that scan result's carrier network info {@link ScanResult#isCarrierAp} and
+ * {@link ScanResult#getCarrierApEapType} is set appropriated based on the carrier network
+ * config.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testGetScanResultsForCarrierAp() throws Exception {
+ IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
+ assertNotNull(scanner);
+
+ // Include RSN IE to indicate EAP key management.
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ out.write(TEST_INFO_ELEMENT_SSID);
+ out.write(TEST_INFO_ELEMENT_RSN);
+ NativeScanResult nativeScanResult = new NativeScanResult(MOCK_NATIVE_SCAN_RESULT);
+ nativeScanResult.infoElement = out.toByteArray();
+ when(scanner.getScanResults()).thenReturn(new NativeScanResult[] {nativeScanResult});
+
+ // AP associated with a carrier network.
+ int eapType = WifiEnterpriseConfig.Eap.SIM;
+ String carrierName = "Test Carrier";
+ when(mCarrierNetworkConfig.isCarrierNetwork(new String(nativeScanResult.ssid)))
+ .thenReturn(true);
+ when(mCarrierNetworkConfig.getNetworkEapType(new String(nativeScanResult.ssid)))
+ .thenReturn(eapType);
+ when(mCarrierNetworkConfig.getCarrierName(new String(nativeScanResult.ssid)))
+ .thenReturn(carrierName);
+ ArrayList<ScanDetail> returnedScanResults = mWificondControl.getScanResults(
+ WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ assertEquals(1, returnedScanResults.size());
+ // Verify returned scan result.
+ ScanResult scanResult = returnedScanResults.get(0).getScanResult();
+ assertArrayEquals(nativeScanResult.ssid, scanResult.SSID.getBytes());
+ assertTrue(scanResult.isCarrierAp);
+ assertEquals(eapType, scanResult.carrierApEapType);
+ assertEquals(carrierName, scanResult.carrierName);
+ reset(mCarrierNetworkConfig);
+
+ // AP not associated with a carrier network.
+ when(mCarrierNetworkConfig.isCarrierNetwork(new String(nativeScanResult.ssid)))
+ .thenReturn(false);
+ returnedScanResults = mWificondControl.getScanResults(
+ WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ assertEquals(1, returnedScanResults.size());
+ // Verify returned scan result.
+ scanResult = returnedScanResults.get(0).getScanResult();
+ assertArrayEquals(nativeScanResult.ssid, scanResult.SSID.getBytes());
+ assertFalse(scanResult.isCarrierAp);
+ assertEquals(ScanResult.UNSPECIFIED, scanResult.carrierApEapType);
+ assertEquals(null, scanResult.carrierName);
+ }
+
+ /**
* Verifies that Scan() can convert input parameters to SingleScanSettings correctly.
*/
@Test
@@ -581,7 +663,7 @@ public class WificondControlTest {
/**
* Verifies that WificondControl can invoke WifiMonitor broadcast methods upon pno scan
- * reuslt event.
+ * result event.
*/
@Test
public void testPnoScanResultEvent() throws Exception {
@@ -592,11 +674,48 @@ public class WificondControlTest {
IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
assertNotNull(pnoScanEvent);
pnoScanEvent.OnPnoNetworkFound();
-
verify(mWifiMonitor).broadcastPnoScanResultEvent(any(String.class));
}
/**
+ * Verifies that WificondControl can invoke WifiMetrics pno scan count methods upon pno event.
+ */
+ @Test
+ public void testPnoScanEventsForMetrics() throws Exception {
+ IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
+
+ ArgumentCaptor<IPnoScanEvent> messageCaptor = ArgumentCaptor.forClass(IPnoScanEvent.class);
+ verify(scanner).subscribePnoScanEvents(messageCaptor.capture());
+ IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
+ assertNotNull(pnoScanEvent);
+
+ pnoScanEvent.OnPnoNetworkFound();
+ verify(mWifiMetrics).incrementPnoFoundNetworkEventCount();
+
+ pnoScanEvent.OnPnoScanFailed();
+ verify(mWifiMetrics).incrementPnoScanFailedCount();
+
+ pnoScanEvent.OnPnoScanOverOffloadStarted();
+ verify(mWifiMetrics).incrementPnoScanStartedOverOffloadCount();
+
+ pnoScanEvent.OnPnoScanOverOffloadFailed(0);
+ verify(mWifiMetrics).incrementPnoScanFailedOverOffloadCount();
+ }
+
+ /**
+ * Verifies that startPnoScan() can invoke WifiMetrics pno scan count methods correctly.
+ */
+ @Test
+ public void testStartPnoScanForMetrics() throws Exception {
+ IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
+
+ when(scanner.startPnoScan(any(PnoSettings.class))).thenReturn(false);
+ assertFalse(mWificondControl.startPnoScan(TEST_PNO_SETTINGS));
+ verify(mWifiMetrics).incrementPnoScanStartAttempCount();
+ verify(mWifiMetrics).incrementPnoScanFailedCount();
+ }
+
+ /**
* Verifies that abortScan() calls underlying wificond.
*/
@Test
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
index 806300423..61143d9bb 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
@@ -19,6 +19,7 @@ package com.android.server.wifi.aware;
import static android.hardware.wifi.V1_0.NanDataPathChannelCfg.CHANNEL_NOT_REQUESTED;
import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -83,8 +84,9 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.lang.reflect.Field;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
/**
* Unit test harness for WifiAwareDataPathStateManager class.
@@ -99,7 +101,6 @@ public class WifiAwareDataPathStateManagerTest {
@Mock private WifiAwareNativeManager mMockNativeManager;
@Mock private WifiAwareNativeApi mMockNative;
@Mock private Context mMockContext;
- @Mock private IWifiAwareManager mMockAwareService;
@Mock private ConnectivityManager mMockCm;
@Mock private INetworkManagementService mMockNwMgt;
@Mock private WifiAwareDataPathStateManager.NetworkInterfaceWrapper mMockNetworkInterface;
@@ -172,7 +173,8 @@ public class WifiAwareDataPathStateManagerTest {
when(mPermissionsWrapperMock.getUidPermission(eq(Manifest.permission.CONNECTIVITY_INTERNAL),
anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
- installDataPathStateManagerMocks();
+ mDut.mDataPathMgr.mNwService = mMockNwMgt;
+ mDut.mDataPathMgr.mNiWrapper = mMockNetworkInterface;
}
/**
@@ -252,7 +254,7 @@ public class WifiAwareDataPathStateManagerTest {
mMockLooper.dispatchAll();
}
- verifyNoMoreInteractions(mMockNative);
+ verifyNoMoreInteractions(mMockNative, mMockNwMgt);
}
/**
@@ -273,12 +275,12 @@ public class WifiAwareDataPathStateManagerTest {
anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
// (0) initialize
- DataPathEndPointInfo res = initDataPathEndPoint(clientId, pubSubId, requestorId,
+ DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, false);
// (1) request network
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle, pmk,
- null, false);
+ null, false, 0);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
@@ -288,7 +290,7 @@ public class WifiAwareDataPathStateManagerTest {
mMockLooper.dispatchAll();
// failure: no interactions with connectivity manager or native manager
- verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock);
+ verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
/**
@@ -309,12 +311,12 @@ public class WifiAwareDataPathStateManagerTest {
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
// (0) initialize
- DataPathEndPointInfo res = initDataPathEndPoint(clientId, pubSubId, requestorId,
+ DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, true);
// (1) request network
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle,
- null, null, true);
+ null, null, true, 0);
Message reqNetworkMsg = Message.obtain();
reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
@@ -342,7 +344,302 @@ public class WifiAwareDataPathStateManagerTest {
mMockLooper.dispatchAll();
// failure if there's further activity
- verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock);
+ verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
+ }
+
+ /**
+ * Validate multiple NDPs created on a single NDI. Most importantly that the interface is
+ * set up on first NDP and torn down on last NDP - and not when one or the other is created or
+ * deleted.
+ *
+ * Procedure:
+ * - create NDP 1, 2, and 3 (interface up only on first)
+ * - delete NDP 2, 1, and 3 (interface down only on last)
+ */
+ @Test
+ public void testMultipleNdpsOnSingleNdi() throws Exception {
+ final int clientId = 123;
+ final byte pubSubId = 58;
+ final int requestorId = 1341234;
+ final int ndpId = 2;
+
+ final int[] startOrder = {0, 1, 2};
+ final int[] endOrder = {1, 0, 2};
+ int networkRequestId = 0;
+
+ ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
+ ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
+ InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
+ mMockNwMgt);
+ InOrder inOrderM = inOrder(mAwareMetricsMock);
+
+ NetworkRequest[] nrs = new NetworkRequest[3];
+ DataPathEndPointInfo[] ress = new DataPathEndPointInfo[3];
+ Messenger[] agentMessengers = new Messenger[3];
+ Messenger messenger = null;
+ boolean first = true;
+ for (int i : startOrder) {
+ networkRequestId += 1;
+ byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
+ byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
+ peerDiscoveryMac[5] = (byte) (peerDiscoveryMac[5] + i);
+ peerDataPathMac[5] = (byte) (peerDataPathMac[5] + i);
+
+ // (0) initialize
+ ress[i] = initDataPathEndPoint(first, clientId, (byte) (pubSubId + i),
+ requestorId + i, peerDiscoveryMac, inOrder, inOrderM, false);
+ if (first) {
+ messenger = ress[i].mMessenger;
+ }
+
+ // (1) request network
+ nrs[i] = getSessionNetworkRequest(clientId, ress[i].mSessionId, ress[i].mPeerHandle,
+ null, null, false, networkRequestId);
+
+ Message reqNetworkMsg = Message.obtain();
+ reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
+ reqNetworkMsg.obj = nrs[i];
+ reqNetworkMsg.arg1 = 0;
+ messenger.send(reqNetworkMsg);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(),
+ eq(requestorId + i),
+ eq(CHANNEL_NOT_REQUESTED), anyInt(), eq(peerDiscoveryMac),
+ eq(sAwareInterfacePrefix + "0"), eq(null),
+ eq(null), eq(false), any());
+
+ mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId + i);
+ mMockLooper.dispatchAll();
+
+ // (2) get confirmation
+ mDut.onDataPathConfirmNotification(ndpId + i, peerDataPathMac, true, 0, null);
+ mMockLooper.dispatchAll();
+ if (first) {
+ inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
+ inOrder.verify(mMockNwMgt).enableIpv6(anyString());
+
+ first = false;
+ }
+ inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
+ any(), anyInt(), any());
+ agentMessengers[i] = messengerCaptor.getValue();
+ inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
+ eq(false), anyLong());
+ inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
+ }
+
+ // (3) end data-path (unless didn't get confirmation)
+ int index = 0;
+ for (int i: endOrder) {
+ Message endNetworkReqMsg = Message.obtain();
+ endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
+ endNetworkReqMsg.obj = nrs[i];
+ messenger.send(endNetworkReqMsg);
+
+ Message endNetworkUsageMsg = Message.obtain();
+ endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
+ agentMessengers[i].send(endNetworkUsageMsg);
+ mMockLooper.dispatchAll();
+
+ inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId + i));
+
+ mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
+ mDut.onDataPathEndNotification(ndpId + i);
+ mMockLooper.dispatchAll();
+
+ if (index++ == endOrder.length - 1) {
+ inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
+ }
+ inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
+ }
+
+ verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
+ }
+
+ /**
+ * Validate that multiple NDP requests which resolve to the same canonical request are treated
+ * as one.
+ */
+ @Test
+ public void testMultipleIdenticalRequests() throws Exception {
+ final int numRequestsPre = 6;
+ final int numRequestsPost = 5;
+ final int clientId = 123;
+ final int ndpId = 5;
+ final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
+ final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
+ NetworkRequest[] nrs = new NetworkRequest[numRequestsPre + numRequestsPost];
+
+ ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
+ ArgumentCaptor<Messenger> agentMessengerCaptor = ArgumentCaptor.forClass(Messenger.class);
+
+ InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
+ mMockNwMgt);
+ InOrder inOrderM = inOrder(mAwareMetricsMock);
+
+ // (1) initialize all clients
+ Messenger messenger = initOobDataPathEndPoint(true, 1, clientId, inOrder, inOrderM);
+ for (int i = 1; i < numRequestsPre + numRequestsPost; ++i) {
+ initOobDataPathEndPoint(false, 1, clientId + i, inOrder, inOrderM);
+ }
+
+ // (2) make 3 network requests (all identical under the hood)
+ for (int i = 0; i < numRequestsPre; ++i) {
+ nrs[i] = getDirectNetworkRequest(clientId + i,
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerDiscoveryMac, null,
+ null, i);
+
+ Message reqNetworkMsg = Message.obtain();
+ reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
+ reqNetworkMsg.obj = nrs[i];
+ reqNetworkMsg.arg1 = 0;
+ messenger.send(reqNetworkMsg);
+ }
+ mMockLooper.dispatchAll();
+
+ // (3) verify the start NDP HAL request
+ inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(), eq(0),
+ eq(CHANNEL_NOT_REQUESTED), anyInt(), eq(peerDiscoveryMac),
+ eq(sAwareInterfacePrefix + "0"), eq(null), eq(null), eq(true), any());
+
+ // (4) unregister request #0 (the primary)
+ Message endNetworkReqMsg = Message.obtain();
+ endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
+ endNetworkReqMsg.obj = nrs[0];
+ messenger.send(endNetworkReqMsg);
+ mMockLooper.dispatchAll();
+
+ // (5) respond to the registration request
+ mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId);
+ mMockLooper.dispatchAll();
+
+ // (6) unregister request #1
+ endNetworkReqMsg = Message.obtain();
+ endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
+ endNetworkReqMsg.obj = nrs[1];
+ messenger.send(endNetworkReqMsg);
+ mMockLooper.dispatchAll();
+
+ // (7) confirm the NDP creation
+ mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0, null);
+ mMockLooper.dispatchAll();
+
+ inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
+ inOrder.verify(mMockNwMgt).enableIpv6(anyString());
+ inOrder.verify(mMockCm).registerNetworkAgent(agentMessengerCaptor.capture(), any(), any(),
+ any(), anyInt(), any());
+ inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
+ eq(true), anyLong());
+ inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
+
+ // (8) execute 'post' requests
+ for (int i = numRequestsPre; i < numRequestsPre + numRequestsPost; ++i) {
+ nrs[i] = getDirectNetworkRequest(clientId + i,
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerDiscoveryMac, null,
+ null, i);
+
+ Message reqNetworkMsg = Message.obtain();
+ reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
+ reqNetworkMsg.obj = nrs[i];
+ reqNetworkMsg.arg1 = 0;
+ messenger.send(reqNetworkMsg);
+ }
+ mMockLooper.dispatchAll();
+
+ // (9) unregister all requests
+ for (int i = 2; i < numRequestsPre + numRequestsPost; ++i) {
+ endNetworkReqMsg = Message.obtain();
+ endNetworkReqMsg.what = NetworkFactory.CMD_CANCEL_REQUEST;
+ endNetworkReqMsg.obj = nrs[i];
+ messenger.send(endNetworkReqMsg);
+ mMockLooper.dispatchAll();
+ }
+
+ Message endNetworkUsageMsg = Message.obtain();
+ endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
+ agentMessengerCaptor.getValue().send(endNetworkUsageMsg);
+ mMockLooper.dispatchAll();
+
+ // (10) verify that NDP torn down
+ inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
+
+ mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
+ mDut.onDataPathEndNotification(ndpId);
+ mMockLooper.dispatchAll();
+
+ inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
+ inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
+
+ verifyNoMoreInteractions(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
+ mAwareMetricsMock, mMockNwMgt);
+ }
+
+ /**
+ * Validate that multiple NDP requests to the same peer target different NDIs.
+ */
+ @Test
+ public void testMultipleNdi() throws Exception {
+ final int numNdis = 5;
+ final int clientId = 123;
+ final int ndpId = 5;
+ final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
+ final byte[] peerDataPathMac = HexEncoding.decode("0A0B0C0D0E0F".toCharArray(), false);
+
+ ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
+ ArgumentCaptor<String> ifNameCaptor = ArgumentCaptor.forClass(String.class);
+
+ InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
+ mMockNwMgt);
+ InOrder inOrderM = inOrder(mAwareMetricsMock);
+
+ // (1) initialize all clients
+ Messenger messenger = initOobDataPathEndPoint(true, numNdis, clientId, inOrder, inOrderM);
+ for (int i = 1; i < numNdis + 3; ++i) {
+ initOobDataPathEndPoint(false, numNdis, clientId + i, inOrder, inOrderM);
+ }
+
+ // (2) make N network requests: each unique
+ Set<String> interfaces = new HashSet<>();
+ for (int i = 0; i < numNdis + 1; ++i) {
+ byte[] pmk = new byte[32];
+ pmk[0] = (byte) i;
+
+ NetworkRequest nr = getDirectNetworkRequest(clientId + i,
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerDiscoveryMac, pmk,
+ null, i);
+
+ Message reqNetworkMsg = Message.obtain();
+ reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
+ reqNetworkMsg.obj = nr;
+ reqNetworkMsg.arg1 = 0;
+ messenger.send(reqNetworkMsg);
+ mMockLooper.dispatchAll();
+
+ if (i < numNdis) {
+ inOrder.verify(mMockNative).initiateDataPath(transactionId.capture(), eq(0),
+ eq(CHANNEL_NOT_REQUESTED), anyInt(), eq(peerDiscoveryMac),
+ ifNameCaptor.capture(), eq(pmk), eq(null), eq(true), any());
+ interfaces.add(ifNameCaptor.getValue());
+
+ mDut.onInitiateDataPathResponseSuccess(transactionId.getValue(), ndpId + i);
+ mDut.onDataPathConfirmNotification(ndpId + i, peerDataPathMac, true, 0, null);
+ mMockLooper.dispatchAll();
+
+ inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
+ inOrder.verify(mMockNwMgt).enableIpv6(anyString());
+ inOrder.verify(mMockCm).registerNetworkAgent(any(), any(), any(), any(), anyInt(),
+ any());
+ inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
+ eq(true), anyLong());
+ inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
+ }
+ }
+
+ // verify that each interface name is unique
+ assertEquals("Number of unique interface names", numNdis, interfaces.size());
+
+ verifyNoMoreInteractions(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
+ mAwareMetricsMock, mMockNwMgt);
}
/*
@@ -563,12 +860,12 @@ public class WifiAwareDataPathStateManagerTest {
InOrder inOrderM = inOrder(mAwareMetricsMock);
// (0) initialize
- DataPathEndPointInfo res = initDataPathEndPoint(clientId, pubSubId, requestorId,
+ DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, doPublish);
// (1) request network
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle, pmk,
- null, doPublish);
+ null, doPublish, 0);
// corrupt the network specifier: reverse the role (so it's mis-matched)
WifiAwareNetworkSpecifier ns =
@@ -603,7 +900,7 @@ public class WifiAwareDataPathStateManagerTest {
eq(ndpId), eq(""), eq(null), eq(null), anyBoolean(), any());
}
- verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock);
+ verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private void testDataPathInitiatorResponderInvalidUidUtility(boolean doPublish,
@@ -619,12 +916,12 @@ public class WifiAwareDataPathStateManagerTest {
InOrder inOrderM = inOrder(mAwareMetricsMock);
// (0) initialize
- DataPathEndPointInfo res = initDataPathEndPoint(clientId, pubSubId, requestorId,
+ DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, doPublish);
// (1) create network request
NetworkRequest nr = getSessionNetworkRequest(clientId, res.mSessionId, res.mPeerHandle, pmk,
- null, doPublish);
+ null, doPublish, 0);
// (2) corrupt request's UID
WifiAwareNetworkSpecifier ns =
@@ -660,7 +957,7 @@ public class WifiAwareDataPathStateManagerTest {
eq(ndpId), eq(""), eq(null), eq(null), anyBoolean(), any());
}
- verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock);
+ verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private void testDataPathInitiatorUtility(boolean useDirect, boolean provideMac,
@@ -678,7 +975,8 @@ public class WifiAwareDataPathStateManagerTest {
ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
- InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
+ InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
+ mMockNwMgt);
InOrder inOrderM = inOrder(mAwareMetricsMock);
if (!providePmk) {
@@ -694,7 +992,7 @@ public class WifiAwareDataPathStateManagerTest {
}
// (0) initialize
- DataPathEndPointInfo res = initDataPathEndPoint(clientId, pubSubId, requestorId,
+ DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, false);
// (1) request network
@@ -703,11 +1001,11 @@ public class WifiAwareDataPathStateManagerTest {
nr = getDirectNetworkRequest(clientId,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR,
provideMac ? peerDiscoveryMac : null, providePmk ? pmk : null,
- providePassphrase ? passphrase : null);
+ providePassphrase ? passphrase : null, 0);
} else {
nr = getSessionNetworkRequest(clientId, res.mSessionId,
provideMac ? res.mPeerHandle : null, providePmk ? pmk : null,
- providePassphrase ? passphrase : null, false);
+ providePassphrase ? passphrase : null, false, 0);
}
Message reqNetworkMsg = Message.obtain();
@@ -737,6 +1035,8 @@ public class WifiAwareDataPathStateManagerTest {
mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0,
peerToken.getBytes());
mMockLooper.dispatchAll();
+ inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
+ inOrder.verify(mMockNwMgt).enableIpv6(anyString());
inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
any(), anyInt(), any());
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
@@ -763,16 +1063,16 @@ public class WifiAwareDataPathStateManagerTest {
Message endNetworkUsageMsg = Message.obtain();
endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
messengerCaptor.getValue().send(endNetworkUsageMsg);
-
- mMockLooper.dispatchAll();
- inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mDut.onDataPathEndNotification(ndpId);
mMockLooper.dispatchAll();
+
+ inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
+ inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
}
- verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock);
+ verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private void testDataPathResponderUtility(boolean useDirect, boolean provideMac,
@@ -790,7 +1090,8 @@ public class WifiAwareDataPathStateManagerTest {
ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
- InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
+ InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback,
+ mMockNwMgt);
InOrder inOrderM = inOrder(mAwareMetricsMock);
if (providePmk) {
@@ -800,7 +1101,7 @@ public class WifiAwareDataPathStateManagerTest {
}
// (0) initialize
- DataPathEndPointInfo res = initDataPathEndPoint(clientId, pubSubId, requestorId,
+ DataPathEndPointInfo res = initDataPathEndPoint(true, clientId, pubSubId, requestorId,
peerDiscoveryMac, inOrder, inOrderM, true);
// (1) request network
@@ -809,11 +1110,11 @@ public class WifiAwareDataPathStateManagerTest {
nr = getDirectNetworkRequest(clientId,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
provideMac ? peerDiscoveryMac : null, providePmk ? pmk : null,
- providePassphrase ? passphrase : null);
+ providePassphrase ? passphrase : null, 0);
} else {
nr = getSessionNetworkRequest(clientId, res.mSessionId,
provideMac ? res.mPeerHandle : null, providePmk ? pmk : null,
- providePassphrase ? passphrase : null, true);
+ providePassphrase ? passphrase : null, true, 0);
}
Message reqNetworkMsg = Message.obtain();
@@ -837,6 +1138,8 @@ public class WifiAwareDataPathStateManagerTest {
mDut.onDataPathConfirmNotification(ndpId, peerDataPathMac, true, 0,
peerToken.getBytes());
mMockLooper.dispatchAll();
+ inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
+ inOrder.verify(mMockNwMgt).enableIpv6(anyString());
inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
any(), anyInt(), any());
inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
@@ -864,35 +1167,23 @@ public class WifiAwareDataPathStateManagerTest {
endNetworkUsageMsg.what = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
messengerCaptor.getValue().send(endNetworkUsageMsg);
- mMockLooper.dispatchAll();
- inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
mDut.onEndDataPathResponse(transactionId.getValue(), true, 0);
mDut.onDataPathEndNotification(ndpId);
mMockLooper.dispatchAll();
+
+ inOrder.verify(mMockNwMgt).setInterfaceDown(anyString());
+ inOrder.verify(mMockNative).endDataPath(transactionId.capture(), eq(ndpId));
inOrderM.verify(mAwareMetricsMock).recordNdpSessionDuration(anyLong());
}
- verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock);
- }
-
- private void installDataPathStateManagerMocks() throws Exception {
- Field field = WifiAwareStateManager.class.getDeclaredField("mDataPathMgr");
- field.setAccessible(true);
- Object mDataPathMgr = field.get(mDut);
-
- field = WifiAwareDataPathStateManager.class.getDeclaredField("mNwService");
- field.setAccessible(true);
- field.set(mDataPathMgr, mMockNwMgt);
-
- field = WifiAwareDataPathStateManager.class.getDeclaredField("mNiWrapper");
- field.setAccessible(true);
- field.set(mDataPathMgr, mMockNetworkInterface);
+ verifyNoMoreInteractions(mMockNative, mMockCm, mAwareMetricsMock, mMockNwMgt);
}
private NetworkRequest getSessionNetworkRequest(int clientId, int sessionId,
- PeerHandle peerHandle, byte[] pmk, String passphrase, boolean doPublish)
+ PeerHandle peerHandle, byte[] pmk, String passphrase, boolean doPublish, int requestId)
throws Exception {
- final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mMockAwareService);
+ final IWifiAwareManager mockAwareService = mock(IWifiAwareManager.class);
+ final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mockAwareService);
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
@@ -910,30 +1201,33 @@ public class WifiAwareDataPathStateManagerTest {
DiscoverySessionCallback mockSessionCallback = mock(
DiscoverySessionCallback.class);
+ InOrder inOrderS = inOrder(mockAwareService, mockCallback, mockSessionCallback);
+
mgr.attach(mMockLooperHandler, configRequest, mockCallback, null);
- verify(mMockAwareService).connect(any(), any(),
+ inOrderS.verify(mockAwareService).connect(any(), any(),
clientProxyCallback.capture(), eq(configRequest), eq(false));
- clientProxyCallback.getValue().onConnectSuccess(clientId);
+ IWifiAwareEventCallback iwaec = clientProxyCallback.getValue();
+ iwaec.onConnectSuccess(clientId);
mMockLooper.dispatchAll();
- verify(mockCallback).onAttached(sessionCaptor.capture());
+ inOrderS.verify(mockCallback).onAttached(sessionCaptor.capture());
if (doPublish) {
sessionCaptor.getValue().publish(publishConfig, mockSessionCallback,
mMockLooperHandler);
- verify(mMockAwareService).publish(eq(clientId), eq(publishConfig),
+ inOrderS.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
} else {
sessionCaptor.getValue().subscribe(subscribeConfig, mockSessionCallback,
mMockLooperHandler);
- verify(mMockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
+ inOrderS.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
sessionProxyCallback.capture());
}
sessionProxyCallback.getValue().onSessionStarted(sessionId);
mMockLooper.dispatchAll();
if (doPublish) {
- verify(mockSessionCallback).onPublishStarted(
+ inOrderS.verify(mockSessionCallback).onPublishStarted(
(PublishDiscoverySession) discoverySession.capture());
} else {
- verify(mockSessionCallback).onSubscribeStarted(
+ inOrderS.verify(mockSessionCallback).onSubscribeStarted(
(SubscribeDiscoverySession) discoverySession.capture());
}
@@ -957,13 +1251,14 @@ public class WifiAwareDataPathStateManagerTest {
nc.setLinkDownstreamBandwidthKbps(1);
nc.setSignalStrength(1);
- return new NetworkRequest(nc, 0, 0, NetworkRequest.Type.NONE);
+ return new NetworkRequest(nc, 0, requestId, NetworkRequest.Type.NONE);
}
private NetworkRequest getDirectNetworkRequest(int clientId, int role, byte[] peer,
- byte[] pmk, String passphrase) throws Exception {
+ byte[] pmk, String passphrase, int requestId) throws Exception {
+ final IWifiAwareManager mockAwareService = mock(IWifiAwareManager.class);
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
- final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mMockAwareService);
+ final WifiAwareManager mgr = new WifiAwareManager(mMockContext, mockAwareService);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -973,7 +1268,7 @@ public class WifiAwareDataPathStateManagerTest {
AttachCallback mockCallback = mock(AttachCallback.class);
mgr.attach(mMockLooperHandler, configRequest, mockCallback, null);
- verify(mMockAwareService).connect(any(), any(),
+ verify(mockAwareService).connect(any(), any(),
clientProxyCallback.capture(), eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -997,64 +1292,25 @@ public class WifiAwareDataPathStateManagerTest {
nc.setLinkDownstreamBandwidthKbps(1);
nc.setSignalStrength(1);
- return new NetworkRequest(nc, 0, 0, NetworkRequest.Type.REQUEST);
+ return new NetworkRequest(nc, 0, requestId, NetworkRequest.Type.REQUEST);
}
- private DataPathEndPointInfo initDataPathEndPoint(int clientId, byte pubSubId,
- int requestorId, byte[] peerDiscoveryMac, InOrder inOrder, InOrder inOrderM,
- boolean doPublish)
+ private DataPathEndPointInfo initDataPathEndPoint(boolean isFirstIteration, int clientId,
+ byte pubSubId, int requestorId, byte[] peerDiscoveryMac, InOrder inOrder,
+ InOrder inOrderM, boolean doPublish)
throws Exception {
- final int pid = 2000;
- final String callingPackage = "com.android.somePackage";
final String someMsg = "some arbitrary message from peer";
- final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
- Capabilities capabilities = new Capabilities();
- capabilities.maxNdiInterfaces = 1;
-
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
- ArgumentCaptor<String> strCaptor = ArgumentCaptor.forClass(String.class);
-
- // (0) start/registrations
- inOrder.verify(mMockCm).registerNetworkFactory(messengerCaptor.capture(),
- strCaptor.capture());
- collector.checkThat("factory name", "WIFI_AWARE_FACTORY", equalTo(strCaptor.getValue()));
- // (1) get capabilities
- mDut.queryCapabilities();
- mMockLooper.dispatchAll();
- inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
- mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
- mMockLooper.dispatchAll();
-
- // (2) enable usage
- mDut.enableUsage();
- mMockLooper.dispatchAll();
- inOrderM.verify(mAwareMetricsMock).recordEnableUsage();
-
- // (3) create client & session & rx message
- mDut.connect(clientId, Process.myUid(), pid, callingPackage, mMockCallback, configRequest,
- false);
- mMockLooper.dispatchAll();
- inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
- eq(configRequest), eq(false), eq(true), eq(true), eq(false));
- mDut.onConfigSuccessResponse(transactionId.getValue());
- mMockLooper.dispatchAll();
- inOrder.verify(mMockCallback).onConnectSuccess(clientId);
- inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(Process.myUid()), eq(false),
- any());
-
- inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
- strCaptor.capture());
- collector.checkThat("interface created -- 0", sAwareInterfacePrefix + 0,
- equalTo(strCaptor.getValue()));
- mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
- mMockLooper.dispatchAll();
+ Messenger messenger = null;
+ if (isFirstIteration) {
+ messenger = initOobDataPathEndPoint(true, 1, clientId, inOrder, inOrderM);
+ }
if (doPublish) {
mDut.publish(clientId, publishConfig, mMockSessionCallback);
@@ -1084,7 +1340,72 @@ public class WifiAwareDataPathStateManagerTest {
eq(someMsg.getBytes()));
return new DataPathEndPointInfo(sessionId.getValue(), peerIdCaptor.getValue(),
- messengerCaptor.getValue());
+ isFirstIteration ? messenger : null);
+ }
+
+ private Messenger initOobDataPathEndPoint(boolean startUpSequence, int maxNdiInterfaces,
+ int clientId, InOrder inOrder, InOrder inOrderM) throws Exception {
+ final int pid = 2000;
+ final String callingPackage = "com.android.somePackage";
+ final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+
+ ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
+ ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
+ ArgumentCaptor<String> strCaptor = ArgumentCaptor.forClass(String.class);
+
+ Capabilities capabilities = new Capabilities();
+ capabilities.maxNdiInterfaces = maxNdiInterfaces;
+
+ if (startUpSequence) {
+ // (0) start/registrations
+ inOrder.verify(mMockCm).registerNetworkFactory(messengerCaptor.capture(),
+ strCaptor.capture());
+ collector.checkThat("factory name", "WIFI_AWARE_FACTORY",
+ equalTo(strCaptor.getValue()));
+
+ // (1) get capabilities
+ mDut.queryCapabilities();
+ mMockLooper.dispatchAll();
+ inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
+ mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), capabilities);
+ mMockLooper.dispatchAll();
+
+ // (2) enable usage
+ mDut.enableUsage();
+ mMockLooper.dispatchAll();
+ inOrderM.verify(mAwareMetricsMock).recordEnableUsage();
+ }
+
+ // (3) create client
+ mDut.connect(clientId, Process.myUid(), pid, callingPackage, mMockCallback,
+ configRequest,
+ false);
+ mMockLooper.dispatchAll();
+
+ if (startUpSequence) {
+ inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
+ eq(configRequest), eq(false), eq(true), eq(true), eq(false));
+ mDut.onConfigSuccessResponse(transactionId.getValue());
+ mMockLooper.dispatchAll();
+ }
+
+ inOrder.verify(mMockCallback).onConnectSuccess(clientId);
+ inOrderM.verify(mAwareMetricsMock).recordAttachSession(eq(Process.myUid()), eq(false),
+ any());
+
+ if (startUpSequence) {
+ for (int i = 0; i < maxNdiInterfaces; ++i) {
+ inOrder.verify(mMockNative).createAwareNetworkInterface(transactionId.capture(),
+ strCaptor.capture());
+ collector.checkThat("interface created -- " + i, sAwareInterfacePrefix + i,
+ equalTo(strCaptor.getValue()));
+ mDut.onCreateDataPathInterfaceResponse(transactionId.getValue(), true, 0);
+ mMockLooper.dispatchAll();
+ }
+ return messengerCaptor.getValue();
+ }
+
+ return null;
}
private static class DataPathEndPointInfo {
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareMetricsTest.java
index 8cd1e1097..4252cfe6a 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareMetricsTest.java
@@ -655,8 +655,7 @@ public class WifiAwareMetricsTest {
WifiAwareDataPathStateManager.AwareNetworkRequestInformation anri =
new WifiAwareDataPathStateManager.AwareNetworkRequestInformation();
anri.networkSpecifier = ns;
- anri.state = WifiAwareDataPathStateManager.AwareNetworkRequestInformation
- .STATE_RESPONDER_CONFIRMED;
+ anri.state = WifiAwareDataPathStateManager.AwareNetworkRequestInformation.STATE_CONFIRMED;
anri.uid = uid;
anri.interfaceName = interfaceName;
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java
index 616e68c0c..3df62f35d 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java
@@ -74,7 +74,7 @@ public class WifiAwareRttStateManagerTest {
mTestLooper = new TestLooper();
BidirectionalAsyncChannelServer server = new BidirectionalAsyncChannelServer(
mMockContext, mTestLooper.getLooper(), mMockHandler);
- when(mMockRttService.getMessenger()).thenReturn(server.getMessenger());
+ when(mMockRttService.getMessenger(null, new int[1])).thenReturn(server.getMessenger());
mDut.startWithRttService(mMockContext, mTestLooper.getLooper(), mMockRttService);
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/LegacyPasspointConfigParserTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/LegacyPasspointConfigParserTest.java
deleted file mode 100644
index 10ebceb22..000000000
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/LegacyPasspointConfigParserTest.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2017 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.hotspot2;
-
-import static org.junit.Assert.*;
-
-import android.os.FileUtils;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Unit tests for {@link com.android.server.wifi.hotspot2.LegacyPasspointConfigParser}.
- */
-@SmallTest
-public class LegacyPasspointConfigParserTest {
- private static final String TEST_CONFIG =
- "tree 3:1.2(urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0)\n"
- + "8:MgmtTree+\n"
- + "17:PerProviderSubscription+\n"
- + "4:r1i1+\n"
- + "6:HomeSP+\n"
- + "c:FriendlyName=12:Test Provider 1™\n"
- + "4:FQDN=9:test1.net\n"
- + "13:RoamingConsortiumOI=9:1234,5678\n"
- + ".\n"
- + "a:Credential+\n"
- + "10:UsernamePassword+\n"
- + "8:Username=5:user1\n"
- + "8:Password=5:pass1\n"
- + "\n"
- + "9:EAPMethod+\n"
- + "7:EAPType=2:21\n"
- + "b:InnerMethod=3:PAP\n"
- + ".\n"
- + ".\n"
- + "5:Realm=9:test1.com\n"
- + ".\n"
- + ".\n"
- + ".\n"
- + "17:PerProviderSubscription+\n"
- + "4:r1i2+\n"
- + "6:HomeSP+\n"
- + "c:FriendlyName=f:Test Provider 2\n"
- + "4:FQDN=9:test2.net\n"
- + ".\n"
- + "a:Credential+\n"
- + "3:SIM+\n"
- + "4:IMSI=4:1234\n"
- + "7:EAPType=2:18\n"
- + ".\n"
- + "5:Realm=9:test2.com\n"
- + ".\n"
- + ".\n"
- + ".\n"
- + ".\n";
-
- /**
- * Helper function for generating {@link LegacyPasspointConfig} objects based on the predefined
- * test configuration string {@link #TEST_CONFIG}
- *
- * @return Map of FQDN to {@link LegacyPasspointConfig}
- */
- private Map<String, LegacyPasspointConfig> generateTestConfig() {
- Map<String, LegacyPasspointConfig> configs = new HashMap<>();
-
- LegacyPasspointConfig config1 = new LegacyPasspointConfig();
- config1.mFqdn = "test1.net";
- config1.mFriendlyName = "Test Provider 1™";
- config1.mRoamingConsortiumOis = new long[] {0x1234, 0x5678};
- config1.mRealm = "test1.com";
- configs.put("test1.net", config1);
-
- LegacyPasspointConfig config2 = new LegacyPasspointConfig();
- config2.mFqdn = "test2.net";
- config2.mFriendlyName = "Test Provider 2";
- config2.mRealm = "test2.com";
- config2.mImsi = "1234";
- configs.put("test2.net", config2);
-
- return configs;
- }
-
- /**
- * Helper function for parsing configuration data.
- *
- * @param data The configuration data to parse
- * @return Map of FQDN to {@link LegacyPasspointConfig}
- * @throws Exception
- */
- private Map<String, LegacyPasspointConfig> parseConfig(String data) throws Exception {
- // Write configuration data to file.
- File configFile = File.createTempFile("LegacyPasspointConfig", "");
- FileUtils.stringToFile(configFile, data);
-
- // Parse the configuration file.
- LegacyPasspointConfigParser parser = new LegacyPasspointConfigParser();
- Map<String, LegacyPasspointConfig> configMap =
- parser.parseConfig(configFile.getAbsolutePath());
-
- configFile.delete();
- return configMap;
- }
-
- /**
- * Verify that the expected {@link LegacyPasspointConfig} objects are return when parsing
- * predefined test configuration data {@link #TEST_CONFIG}.
- *
- * @throws Exception
- */
- @Test
- public void parseTestConfig() throws Exception {
- Map<String, LegacyPasspointConfig> parsedConfig = parseConfig(TEST_CONFIG);
- assertEquals(generateTestConfig(), parsedConfig);
- }
-
- /**
- * Verify that an empty map is return when parsing a configuration containing an empty
- * configuration (MgmtTree).
- *
- * @throws Exception
- */
- @Test
- public void parseEmptyConfig() throws Exception {
- String emptyConfig = "tree 3:1.2(urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0)\n"
- + "8:MgmtTree+\n"
- + ".\n";
- Map<String, LegacyPasspointConfig> parsedConfig = parseConfig(emptyConfig);
- assertTrue(parsedConfig.isEmpty());
- }
-
- /**
- * Verify that an empty map is return when parsing an empty configuration data.
- *
- * @throws Exception
- */
- @Test
- public void parseEmptyData() throws Exception {
- Map<String, LegacyPasspointConfig> parsedConfig = parseConfig("");
- assertTrue(parsedConfig.isEmpty());
- }
-
- /**
- * Verify that an IOException is thrown when parsing a configuration containing an unknown
- * root name. The expected root name is "MgmtTree".
- *
- * @throws Exception
- */
- @Test(expected = IOException.class)
- public void parseConfigWithUnknownRootName() throws Exception {
- String config = "tree 3:1.2(urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0)\n"
- + "8:TestTest+\n"
- + ".\n";
- parseConfig(config);
- }
-
- /**
- * Verify that an IOException is thrown when parsing a configuration containing a line with
- * mismatched string length for the name.
- *
- * @throws Exception
- */
- @Test(expected = IOException.class)
- public void parseConfigWithMismatchedStringLengthInName() throws Exception {
- String config = "tree 3:1.2(urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0)\n"
- + "9:MgmtTree+\n"
- + ".\n";
- parseConfig(config);
- }
-
- /**
- * Verify that an IOException is thrown when parsing a configuration containing a line with
- * mismatched string length for the value.
- *
- * @throws Exception
- */
- @Test(expected = IOException.class)
- public void parseConfigWithMismatchedStringLengthInValue() throws Exception {
- String config = "tree 3:1.2(urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0)\n"
- + "8:MgmtTree+\n"
- + "4:test=5:test\n"
- + ".\n";
- parseConfig(config);
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java
index 9f61ca09c..7ddddd250 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointNetworkEvaluatorTest.java
@@ -59,6 +59,8 @@ public class PasspointNetworkEvaluatorTest {
private static final int TEST_NETWORK_ID = 1;
private static final String TEST_SSID1 = "ssid1";
private static final String TEST_SSID2 = "ssid2";
+ private static final String TEST_BSSID1 = "01:23:45:56:78:9a";
+ private static final String TEST_BSSID2 = "23:12:34:90:81:12";
private static final String TEST_FQDN1 = "test1.com";
private static final String TEST_FQDN2 = "test2.com";
private static final WifiConfiguration TEST_CONFIG1 = generateWifiConfig(TEST_FQDN1);
@@ -107,14 +109,18 @@ public class PasspointNetworkEvaluatorTest {
* @param rssiLevel The RSSI level associated with the scan
* @return {@link ScanDetail}
*/
- private static ScanDetail generateScanDetail(String ssid) {
+ private static ScanDetail generateScanDetail(String ssid, String bssid) {
NetworkDetail networkDetail = mock(NetworkDetail.class);
when(networkDetail.isInterworking()).thenReturn(true);
when(networkDetail.getAnt()).thenReturn(NetworkDetail.Ant.FreePublic);
ScanDetail scanDetail = mock(ScanDetail.class);
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = ssid;
+ scanResult.BSSID = bssid;
when(scanDetail.getSSID()).thenReturn(ssid);
- when(scanDetail.getScanResult()).thenReturn(new ScanResult());
+ when(scanDetail.getBSSIDString()).thenReturn(bssid);
+ when(scanDetail.getScanResult()).thenReturn(scanResult);
when(scanDetail.getNetworkDetail()).thenReturn(networkDetail);
return scanDetail;
}
@@ -138,7 +144,8 @@ public class PasspointNetworkEvaluatorTest {
@Test
public void evaluateScansWithNoMatch() throws Exception {
List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
- generateScanDetail(TEST_SSID1), generateScanDetail(TEST_SSID2)});
+ generateScanDetail(TEST_SSID1, TEST_BSSID1),
+ generateScanDetail(TEST_SSID2, TEST_BSSID2)});
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
when(mPasspointManager.matchProvider(any(ScanResult.class))).thenReturn(null);
assertEquals(null, mEvaluator.evaluateNetworks(
@@ -177,7 +184,8 @@ public class PasspointNetworkEvaluatorTest {
@Test
public void evaluateScansWithNetworkMatchingHomeProvider() throws Exception {
List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
- generateScanDetail(TEST_SSID1), generateScanDetail(TEST_SSID2)});
+ generateScanDetail(TEST_SSID1, TEST_BSSID1),
+ generateScanDetail(TEST_SSID2, TEST_BSSID2)});
// Setup matching providers for ScanDetail with TEST_SSID1.
Pair<PasspointProvider, PasspointMatch> homeProvider = Pair.create(
@@ -219,7 +227,8 @@ public class PasspointNetworkEvaluatorTest {
@Test
public void evaluateScansWithNetworkMatchingRoamingProvider() throws Exception {
List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
- generateScanDetail(TEST_SSID1), generateScanDetail(TEST_SSID2)});
+ generateScanDetail(TEST_SSID1, TEST_BSSID1),
+ generateScanDetail(TEST_SSID2, TEST_BSSID2)});
// Setup matching providers for ScanDetail with TEST_SSID1.
Pair<PasspointProvider, PasspointMatch> roamingProvider = Pair.create(
@@ -261,7 +270,8 @@ public class PasspointNetworkEvaluatorTest {
@Test
public void evaluateScansWithHomeProviderNewtorkAndRoamingProviderNetwork() throws Exception {
List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
- generateScanDetail(TEST_SSID1), generateScanDetail(TEST_SSID2)});
+ generateScanDetail(TEST_SSID1, TEST_BSSID1),
+ generateScanDetail(TEST_SSID2, TEST_BSSID2)});
// Setup matching providers for ScanDetail with TEST_SSID1.
Pair<PasspointProvider, PasspointMatch> homeProvider = Pair.create(
@@ -305,7 +315,8 @@ public class PasspointNetworkEvaluatorTest {
@Test
public void evaluateScansWithActiveNetworkMatchingHomeProvider() throws Exception {
List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
- generateScanDetail(TEST_SSID1), generateScanDetail(TEST_SSID2)});
+ generateScanDetail(TEST_SSID1, TEST_BSSID1),
+ generateScanDetail(TEST_SSID2, TEST_BSSID2)});
// Setup matching providers for both ScanDetail.
Pair<PasspointProvider, PasspointMatch> homeProvider = Pair.create(
@@ -315,7 +326,7 @@ public class PasspointNetworkEvaluatorTest {
WifiConfiguration currentNetwork = new WifiConfiguration();
currentNetwork.networkId = TEST_NETWORK_ID;
currentNetwork.SSID = ScanResultUtil.createQuotedSSID(TEST_SSID2);
- String currentBssid = "12:23:34:45:12:0F";
+ String currentBssid = TEST_BSSID2;
// Returning the same matching provider for both ScanDetail.
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
@@ -344,7 +355,7 @@ public class PasspointNetworkEvaluatorTest {
public void evaluateScanMatchingSIMProviderWithoutSIMCard() throws Exception {
// Setup ScanDetail and match providers.
List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
- generateScanDetail(TEST_SSID1)});
+ generateScanDetail(TEST_SSID1, TEST_BSSID1)});
PasspointProvider testProvider = mock(PasspointProvider.class);
Pair<PasspointProvider, PasspointMatch> homeProvider = Pair.create(
testProvider, PasspointMatch.HomeProvider);
@@ -357,6 +368,45 @@ public class PasspointNetworkEvaluatorTest {
scanDetails, null, null, false, false, connectableNetworks));
assertTrue(connectableNetworks.isEmpty());
verify(testProvider, never()).getWifiConfig();
+ }
+
+ /**
+ * Verify that when the current active network is matched, the scan info associated with
+ * the network is updated.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void evaluateScansMatchingActiveNetworkWithDifferentBSS() throws Exception {
+ List<ScanDetail> scanDetails = Arrays.asList(new ScanDetail[] {
+ generateScanDetail(TEST_SSID1, TEST_BSSID2)});
+ // Setup matching provider.
+ Pair<PasspointProvider, PasspointMatch> homeProvider = Pair.create(
+ TEST_PROVIDER1, PasspointMatch.HomeProvider);
+
+ // Setup currently connected network.
+ WifiConfiguration currentNetwork = new WifiConfiguration();
+ currentNetwork.networkId = TEST_NETWORK_ID;
+ currentNetwork.SSID = ScanResultUtil.createQuotedSSID(TEST_SSID1);
+ String currentBssid = TEST_BSSID1;
+
+ // Match the current connected network to a home provider.
+ List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
+ when(mPasspointManager.matchProvider(any(ScanResult.class))).thenReturn(homeProvider);
+ WifiConfiguration config = mEvaluator.evaluateNetworks(scanDetails, currentNetwork,
+ currentBssid, true, false, connectableNetworks);
+ assertEquals(1, connectableNetworks.size());
+ // Verify network candidate information is updated.
+ ArgumentCaptor<ScanResult> updatedCandidateScanResult =
+ ArgumentCaptor.forClass(ScanResult.class);
+ verify(mWifiConfigManager).setNetworkCandidateScanResult(eq(TEST_NETWORK_ID),
+ updatedCandidateScanResult.capture(), anyInt());
+ assertEquals(TEST_BSSID2, updatedCandidateScanResult.getValue().BSSID);
+ ArgumentCaptor<ScanDetail> updatedCandidateScanDetail =
+ ArgumentCaptor.forClass(ScanDetail.class);
+ verify(mWifiConfigManager).updateScanDetailForNetwork(eq(TEST_NETWORK_ID),
+ updatedCandidateScanDetail.capture());
+ assertEquals(TEST_BSSID2, updatedCandidateScanDetail.getValue().getBSSIDString());
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackTest.java b/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackTest.java
index 4443bb1f6..8b853a470 100644
--- a/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackTest.java
@@ -83,8 +83,8 @@ public class SupplicantP2pIfaceCallbackTest {
*/
@Test
public void testOnDeviceFound_success() throws Exception {
- byte[] fakePrimaryDeviceTypeBytes = { 0x01, 0x02, 0x03 };
- String fakePrimaryDeviceTypeString = "010203";
+ byte[] fakePrimaryDeviceTypeBytes = { 0x00, 0x01, 0x02, -1, 0x04, 0x05, 0x06, 0x07 };
+ String fakePrimaryDeviceTypeString = "1-02FF0405-1543";
String fakeDeviceName = "test device name";
short fakeConfigMethods = 0x1234;
byte fakeCapabilities = 123;
@@ -131,8 +131,8 @@ public class SupplicantP2pIfaceCallbackTest {
*/
@Test
public void testOnDeviceFound_invalidArguments() throws Exception {
- byte[] fakePrimaryDeviceTypeBytes = { 0x01, 0x02, 0x03 };
- String fakePrimaryDeviceTypeString = "010203";
+ byte[] fakePrimaryDeviceTypeBytes = { 0x0, 0x01, 0x02, -1, 0x04, 0x05, 0x06, 0x07 };
+ String fakePrimaryDeviceTypeString = "1-02FF0405-1543";
String fakeDeviceName = "test device name";
short fakeConfigMethods = 0x1234;
byte fakeCapabilities = 123;
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
index c63a9a042..974cf6635 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
@@ -429,6 +429,7 @@ public class WificondPnoScannerTest {
expectHwDisconnectedPnoScanStart(order, pnoSettings);
// Setup scan results
+ when(mWifiNative.getPnoScanResults()).thenReturn(scanResults.getScanDetailArrayList());
when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
// Notify scan has finished
@@ -451,6 +452,7 @@ public class WificondPnoScannerTest {
order.verify(mWifiNative).scan(eq(expectedScanFreqs), any(Set.class));
+ when(mWifiNative.getPnoScanResults()).thenReturn(scanResults.getScanDetailArrayList());
when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
// Notify scan has finished
@@ -478,6 +480,7 @@ public class WificondPnoScannerTest {
// Setup scan results
when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
+ when(mWifiNative.getPnoScanResults()).thenReturn(scanResults.getScanDetailArrayList());
// Notify scan has finished
mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
index ed7c58298..d337cf1cf 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
@@ -32,6 +32,7 @@ import com.android.server.wifi.ScanDetail;
import com.android.server.wifi.ScanResults;
import com.android.server.wifi.WifiMonitor;
import com.android.server.wifi.WifiNative;
+import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
import org.junit.Before;
import org.junit.Test;
@@ -56,6 +57,39 @@ public class WificondScannerTest extends BaseWifiScannerImplTest {
mLooper.getLooper(), mClock);
}
+ /**
+ * Test that WificondScannerImpl will not issue a scan and report scan failure
+ * when there is no channel to scan for.
+ */
+ @Test
+ public void singleScanNotIssuedIfNoAvailableChannels() {
+ // Use mocked ChannelHelper and ChannelCollection to simulate the scenario
+ // that no channel is available for this request.
+ ChannelHelper channelHelper = mock(ChannelHelper.class);
+ ChannelCollection channelCollection = mock(ChannelCollection.class);
+ when(channelHelper.createChannelCollection()).thenReturn(channelCollection);
+ when(channelCollection.isEmpty()).thenReturn(true);
+
+ mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
+ channelHelper, mLooper.getLooper(), mClock);
+
+ WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
+ .withBasePeriod(10000) // ms
+ .withMaxApPerScan(10)
+ .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
+ WifiScanner.WIFI_BAND_5_GHZ)
+ .build();
+ WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
+ mScanner.startSingleScan(settings, eventHandler);
+
+ mLooper.dispatchAll();
+
+ // No scan is issued to WifiNative.
+ verify(mWifiNative, never()).scan(any(), any(Set.class));
+ // A scan failed event must be reported.
+ verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
+ }
+
@Test
public void backgroundScanSuccessSingleBucket() {
WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
diff --git a/tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java b/tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java
new file mode 100644
index 000000000..bfa107159
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import java.util.Random;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.util.Matrix}.
+ */
+public class MatrixTest {
+ /**
+ * Test that both forms of constructor work
+ */
+ @Test
+ public void testConstructors() throws Exception {
+ assertEquals(new Matrix(3, 2), new Matrix(2, new double[]{0, 0, 0, 0, 0, 0}));
+ }
+
+ /**
+ * Test some degenerate cases
+ */
+ @Test
+ public void testDegenerate() throws Exception {
+ Matrix m1 = new Matrix(0, 20);
+ Matrix m2 = new Matrix(20, 0);
+ assertEquals(m1, m2.transpose());
+ }
+
+ /**
+ * Test addition
+ */
+ @Test
+ public void testAddition() throws Exception {
+ Matrix m1 = new Matrix(2, new double[]{1, 2, 3, 4});
+ Matrix m2 = new Matrix(2, new double[]{10, 20, 30, 40});
+ Matrix m3 = new Matrix(2, new double[]{11, 22, 33, 44});
+ assertEquals(m3, m1.plus(m2));
+ }
+
+ /**
+ * Test subtraction.
+ */
+ @Test
+ public void testSubtraction() throws Exception {
+ Matrix m1 = new Matrix(2, new double[]{1, 2, 3, 4});
+ Matrix m2 = new Matrix(2, new double[]{10, 20, 30, 40});
+ Matrix m3 = new Matrix(2, new double[]{11, 22, 33, 44});
+ assertEquals(m1, m3.minus(m2));
+ }
+
+ /**
+ * Test multiplication.
+ */
+ @Test
+ public void testMultiplication() throws Exception {
+ Matrix m1 = new Matrix(2, new double[]{1, 2, 3, 4});
+ Matrix m2 = new Matrix(2, new double[]{-3, 3, 7, 1});
+ Matrix m3 = new Matrix(2, new double[]{11, 5, 19, 13});
+ assertEquals(m3, m1.dot(m2));
+ }
+
+ /**
+ * Test that matrix inverse works (non-singular case).
+ */
+ @Test
+ public void testInverse() throws Exception {
+ Matrix i3 = new Matrix(3, new double[]{1, 0, 0, 0, 1, 0, 0, 0, 1});
+ Matrix f = new Matrix(3, new double[]{100, 100, 100, 100, 100, 100, 100, 100, 100});
+ Matrix m1 = new Matrix(3, new double[]{10, 1, -1, 2, 14, -1, 0, 2, 20});
+ Matrix m2 = m1.inverse();
+ Matrix m12 = m1.dot(m2);
+ Matrix m21 = m2.dot(m1);
+ // Add f here to wash out the roundoff errors
+ assertEquals(i3.plus(f), m12.plus(f));
+ assertEquals(i3.plus(f), m21.plus(f));
+ }
+
+ /**
+ * Test that attempting to invert a singular matrix throws an exception.
+ * @throws Exception
+ */
+ @Test(expected = ArithmeticException.class)
+ public void testSingularity() throws Exception {
+ Matrix m1 = new Matrix(3, new double[]{10, 1, -1, 0, 0, 0, 0, 0, 0});
+ Matrix m2 = m1.inverse();
+ }
+
+ /**
+ * Test that a copy is equal to the original, and that hash codes match,
+ * and that string versions match.
+ */
+ @Test
+ public void testCopy() throws Exception {
+ Random random = new Random();
+ Matrix m1 = new Matrix(3, 4);
+ for (int i = 0; i < m1.mem.length; i++) {
+ m1.mem[i] = random.nextDouble();
+ }
+ Matrix m2 = new Matrix(m1);
+ assertEquals(m1, m2);
+ assertEquals(m1.hashCode(), m2.hashCode());
+ assertEquals(m1.toString(), m2.toString());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/NativeUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/NativeUtilTest.java
index 3f51c5a6a..367e6b34a 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/NativeUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/NativeUtilTest.java
@@ -98,10 +98,25 @@ public class NativeUtilTest {
}
/**
+ * Test that conversion of ssid bytes to quoted UTF8 string ssid works.
+ */
+ @Test
+ public void testUtf8SsidDecode() throws Exception {
+ assertEquals(
+ new ArrayList<>(
+ Arrays.asList((byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72,
+ (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x41, (byte) 0x50,
+ (byte) 0xe3, (byte) 0x81, (byte) 0x8f, (byte) 0xe3, (byte) 0x81,
+ (byte) 0xa0, (byte) 0xe3, (byte) 0x81, (byte) 0x95, (byte) 0xe3,
+ (byte) 0x81, (byte) 0x84)),
+ NativeUtil.decodeSsid("\"AndroidAPください\""));
+ }
+
+ /**
* Test that conversion of ssid bytes to hex string ssid works.
*/
@Test
- public void testNonAsciiSsidDecode() throws Exception {
+ public void testNonSsidDecode() throws Exception {
assertEquals(
new ArrayList<>(
Arrays.asList((byte) 0xf5, (byte) 0xe4, (byte) 0xab, (byte) 0x78,
@@ -110,10 +125,10 @@ public class NativeUtilTest {
}
/**
- * Test that conversion of ssid bytes to quoted ASCII string ssid works.
+ * Test that conversion of ssid bytes to quoted string ssid works.
*/
@Test
- public void testAsciiSsidEncode() throws Exception {
+ public void testSsidEncode() throws Exception {
assertEquals(
"\"ssid_test123\"",
NativeUtil.encodeSsid(new ArrayList<>(
@@ -126,7 +141,7 @@ public class NativeUtilTest {
* Test that conversion of byte array to hex string works when the byte array contains 0.
*/
@Test
- public void testNullCharInAsciiSsidEncode() throws Exception {
+ public void testNullCharInSsidEncode() throws Exception {
assertEquals(
"007369645f74657374313233",
NativeUtil.encodeSsid(new ArrayList<>(
@@ -139,7 +154,7 @@ public class NativeUtilTest {
* Test that conversion of byte array to hex string ssid works.
*/
@Test
- public void testNonAsciiSsidEncode() throws Exception {
+ public void testNonSsidEncode() throws Exception {
assertEquals(
"f5e4ab78ab3432439a",
NativeUtil.encodeSsid(new ArrayList<>(
diff --git a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
index 308e26776..7f5a66d0e 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
@@ -19,6 +19,7 @@ package com.android.server.wifi.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
@@ -27,12 +28,15 @@ import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.AppOpsManager;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.net.wifi.WifiConfiguration;
import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -41,6 +45,7 @@ import android.provider.Settings;
import com.android.server.wifi.BinderUtil;
import com.android.server.wifi.FakeWifiLog;
+import com.android.server.wifi.FrameworkFacade;
import com.android.server.wifi.WifiInjector;
import com.android.server.wifi.WifiSettingsStore;
@@ -72,8 +77,10 @@ public class WifiPermissionsUtilTest {
@Mock private UserManager mMockUserManager;
@Mock private WifiSettingsStore mMockWifiSettingsStore;
@Mock private ContentResolver mMockContentResolver;
- @Mock private NetworkScoreManager mNetworkScoreManager;
- @Mock private WifiInjector mWifiInjector;
+ @Mock private NetworkScoreManager mMockNetworkScoreManager;
+ @Mock private WifiInjector mMockWifiInjector;
+ @Mock private FrameworkFacade mMockFrameworkFacade;
+ @Mock private WifiConfiguration mMockWifiConfig;
@Spy private FakeWifiLog mWifiLog;
private static final String TEST_PACKAGE_NAME = "com.google.somePackage";
@@ -101,6 +108,10 @@ public class WifiPermissionsUtilTest {
private boolean mActiveNwScorer;
private Answer<Integer> mReturnPermission;
private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
+ private String mUseOpenWifiPackage;
+ private NetworkScorerAppData mNetworkScorerAppData;
+ private boolean mGetActiveScorerThrowsSecurityException;
+ private boolean mConfigIsOpen;
/**
* Set up Mockito tests
@@ -124,8 +135,8 @@ public class WifiPermissionsUtilTest {
mUid = MANAGED_PROFILE_UID; // do not really care about this value
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
.thenReturn(PackageManager.PERMISSION_GRANTED);
assertTrue(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -139,8 +150,8 @@ public class WifiPermissionsUtilTest {
mUid = OTHER_USER_UID; // do not really care about this value
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
.thenReturn(PackageManager.PERMISSION_DENIED);
assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -154,8 +165,8 @@ public class WifiPermissionsUtilTest {
mUid = OTHER_USER_UID; // do not really care about this value
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
doThrow(new RemoteException("Failed to check permissions for " + mUid))
.when(mMockPermissionsWrapper).getOverrideWifiConfigPermission(mUid);
assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -179,8 +190,8 @@ public class WifiPermissionsUtilTest {
mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -207,8 +218,8 @@ public class WifiPermissionsUtilTest {
mMockUserInfo.id = mCallingUser;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -230,8 +241,8 @@ public class WifiPermissionsUtilTest {
mPermissionsList.put(mMacAddressPermission, mUid);
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -259,8 +270,8 @@ public class WifiPermissionsUtilTest {
mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -286,8 +297,8 @@ public class WifiPermissionsUtilTest {
mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -312,8 +323,8 @@ public class WifiPermissionsUtilTest {
mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -323,6 +334,354 @@ public class WifiPermissionsUtilTest {
}
/**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User is current
+ * The current config is for an open network.
+ * Validate result is true
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_PackageIsUseOpenWifiPackage() throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+ mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+ null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+ useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(true, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because the caller has access to scan results.
+ * Location mode is ON
+ * User is current
+ * The current config is not for an open network.
+ * Validate result is true
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_HasAccessToScanResults() throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD;
+ mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+ mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
+ mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
+ mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mConfigIsOpen = false;
+
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(true, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User or profile is not current but the uid has
+ * permission to INTERACT_ACROSS_USERS_FULL
+ * The current config is for an open network.
+ * Validate result is true
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_UserNotCurrentButHasInteractAcrossUsers()
+ throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mUid = MANAGED_PROFILE_UID;
+ mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+ mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+ null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+ useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(true, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User or profile is NOT current
+ * INTERACT_ACROSS_USERS_FULL NOT granted
+ * The current config is for an open network.
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_UserNotCurrentNoInteractAcrossUsers()
+ throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mUid = MANAGED_PROFILE_UID;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User is current
+ * The current config is NULL.
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_WiFiConfigIsNull() throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+ mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+ null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+ useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(null /*config*/, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User is current
+ * The current config is not for an open network.
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_WiFiConfigIsNotOpen() throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+ mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+ null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+ useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+ mConfigIsOpen = false;
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User is current
+ * The current config is for an open network.
+ * There is no active scorer
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsSetButNoActiveScorer()
+ throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ mNetworkScorerAppData = null; // getActiveScorer() will return null
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User is current
+ * The current config is for an open network.
+ * The scorer is active but the useOpenWiFi component name doesn't match
+ * the provided package.
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_MismatchBetweenUseOpenWifiPackages()
+ throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ ComponentName useOpenWifiComponent =
+ new ComponentName(mUseOpenWifiPackage + ".nomatch", "TestClass");
+ mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+ null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+ useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+ * User is current
+ * The current config is for an open network.
+ * The scorer is active but the useOpenWiFi component name is null.
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_UseOpenWifiPackageFromScorerIsNull()
+ throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+ null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+ null /*useOpenWifiComponent*/, null /*networkAvailableNotificationChannelId*/);
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: Package is invalid because USE_OPEN_WIFI_PACKAGE is an empty string.
+ * Location mode is ON
+ * User is current
+ * The current config is for an open network.
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsEmpty() throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = "";
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: Package is invalid because it does not match the USE_OPEN_WIFI_PACKAGE.
+ * User is current
+ * The current config is for an open network.
+ * Validate result is false
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_DoesNotMatchUseOpenWifiPackage() throws Exception {
+ final boolean output;
+ mThrowSecurityException = false;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME + ".nomatch";
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+ mUid, mTargetVersion);
+
+ assertEquals(false, output);
+ }
+
+ /**
+ * Test case setting: The caller is invalid because its UID does not match the provided package.
+ *
+ * Validate a SecurityException is thrown.
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_UidPackageCheckFails() throws Exception {
+ mThrowSecurityException = true;
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ try {
+ codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
+ mTargetVersion);
+ fail("SecurityException not thrown.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test case setting: The getActiveScorer() call fails with a SecurityException.
+ *
+ * Validate a SecurityException is thrown.
+ */
+ @Test
+ public void testCanAccessFullConnectionInfo_GetActiveScorerFails() throws Exception {
+ mThrowSecurityException = false;
+ mGetActiveScorerThrowsSecurityException = true;
+ mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+ mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+ mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+ setupTestCase();
+ WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
+
+ try {
+ codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
+ mTargetVersion);
+ fail("SecurityException not thrown.");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
* Test case Setting: Package is valid
* Legacy App
* Foreground
@@ -341,8 +700,8 @@ public class WifiPermissionsUtilTest {
mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -373,8 +732,8 @@ public class WifiPermissionsUtilTest {
mMockUserInfo.id = mCallingUser;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -400,8 +759,8 @@ public class WifiPermissionsUtilTest {
mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -419,8 +778,8 @@ public class WifiPermissionsUtilTest {
boolean output = false;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -444,8 +803,8 @@ public class WifiPermissionsUtilTest {
mMockUserInfo.id = mCallingUser;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
}
@@ -457,8 +816,8 @@ public class WifiPermissionsUtilTest {
public void testEnforceLocationPermissionExpectSecurityException() throws Exception {
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
- mWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+ mMockWifiInjector);
codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
}
@@ -500,7 +859,15 @@ public class WifiPermissionsUtilTest {
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
when(mMockContext.getSystemService(Context.USER_SERVICE))
.thenReturn(mMockUserManager);
- when(mWifiInjector.makeLog(anyString())).thenReturn(mWifiLog);
+ when(mMockWifiInjector.makeLog(anyString())).thenReturn(mWifiLog);
+ when(mMockWifiInjector.getFrameworkFacade()).thenReturn(mMockFrameworkFacade);
+ if (mGetActiveScorerThrowsSecurityException) {
+ when(mMockNetworkScoreManager.getActiveScorer()).thenThrow(
+ new SecurityException("Caller is neither the system process nor a "
+ + "score requester."));
+ } else {
+ when(mMockNetworkScoreManager.getActiveScorer()).thenReturn(mNetworkScorerAppData);
+ }
}
private void initTestVars() {
@@ -518,6 +885,10 @@ public class WifiPermissionsUtilTest {
mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
mActiveNwScorer = false;
+ mUseOpenWifiPackage = null;
+ mNetworkScorerAppData = null;
+ mGetActiveScorerThrowsSecurityException = false;
+ mConfigIsOpen = true;
}
private void setupMockInterface() {
@@ -528,11 +899,14 @@ public class WifiPermissionsUtilTest {
anyString(), anyInt());
when(mMockPermissionsWrapper.getCallingUserId(mUid)).thenReturn(mCallingUser);
when(mMockPermissionsWrapper.getCurrentUser()).thenReturn(mCurrentUser);
- when(mNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer);
+ when(mMockNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer);
when(mMockPermissionsWrapper.getUidPermission(mManifestStringCoarse, mUid))
.thenReturn(mCoarseLocationPermission);
when(mMockWifiSettingsStore.getLocationModeSetting(mMockContext))
.thenReturn(mLocationModeSetting);
when(mMockPermissionsWrapper.getTopPkgName()).thenReturn(mPkgNameOfTopActivity);
+ when(mMockFrameworkFacade.getStringSetting(mMockContext,
+ Settings.Global.USE_OPEN_WIFI_PACKAGE)).thenReturn(mUseOpenWifiPackage);
+ when(mMockWifiConfig.isOpenNetwork()).thenReturn(mConfigIsOpen);
}
}