diff options
374 files changed, 24053 insertions, 3840 deletions
diff --git a/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java b/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java index 7bbfed3b8a..4dab628bbc 100644 --- a/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java +++ b/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java @@ -246,19 +246,17 @@ public class WifiDialogActivity extends Activity { @Override protected void onStop() { super.onStop(); - if (!isChangingConfigurations()) { - if (!BuildCompat.isAtLeastU()) { - // Before U, we don't have INTERNAL_SYSTEM_WINDOW permission to always show at the - // top, so close all dialogs when we're not visible anymore. - for (int i = 0; i < mActiveDialogsPerId.size(); i++) { - mActiveDialogsPerId.valueAt(i).cancel(); - } + if (!isChangingConfigurations() && !BuildCompat.isAtLeastU()) { + // Before U, we don't have INTERNAL_SYSTEM_WINDOW permission to always show at the + // top, so close all dialogs when we're not visible anymore (i.e. another app launches + // on top of us). + for (int i = 0; i < mActiveDialogsPerId.size(); i++) { + mActiveDialogsPerId.valueAt(i).cancel(); } return; } - // If we're stopping due to a configuration change, dismiss all the dialogs without - // removing it from mLaunchIntentsPerId to prevent window leaking. The dialogs will be - // recreated from mLaunchIntentsPerId in onStart(). + // Dismiss all the dialogs without removing it from mLaunchIntentsPerId to prevent window + // leaking. The dialogs will be recreated from mLaunchIntentsPerId in onStart(). for (int i = 0; i < mActiveDialogsPerId.size(); i++) { Dialog dialog = mActiveDialogsPerId.valueAt(i); // Set the dismiss listener to null to prevent removing the Intent from diff --git a/apex/Android.bp b/apex/Android.bp index 276d8166ff..a878695458 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -121,6 +121,7 @@ bootclasspath_fragment { "android.net.wifi.hotspot2", "android.net.wifi.p2p", "android.net.wifi.rtt", + "android.net.wifi.twt", "android.net.wifi.util", "com.android.wifi", ], diff --git a/flags/Android.bp b/flags/Android.bp index ba7141dcb6..f73608a5d8 100644 --- a/flags/Android.bp +++ b/flags/Android.bp @@ -21,6 +21,7 @@ package { aconfig_declarations { name: "wifi_aconfig_flags", package: "com.android.wifi.flags", + container: "com.android.wifi", srcs: ["wifi_flags.aconfig"], } @@ -37,4 +38,16 @@ java_aconfig_library { "//packages/modules/Wifi:__subpackages__", "//cts/tests/tests/wifi:__subpackages__", ], -}
\ No newline at end of file +} + +java_aconfig_library { + name: "wifi_framework_aconfig_flags_lib", + aconfig_declarations: "wifi_aconfig_flags", + defaults: ["wifi-framework-aconfig-java-defaults"], +} + +java_defaults { + name: "wifi-framework-aconfig-java-defaults", + sdk_version: "core_platform", + libs: ["fake_device_config"], +} diff --git a/flags/wifi_flags.aconfig b/flags/wifi_flags.aconfig index a35702ca92..1b92fff3a8 100644 --- a/flags/wifi_flags.aconfig +++ b/flags/wifi_flags.aconfig @@ -1,4 +1,5 @@ package: "com.android.wifi.flags" +container: "com.android.wifi" flag { name: "test_flag_function" @@ -8,14 +9,6 @@ flag { } flag { - name: "runtime_disable_pno_scan" - namespace: "wifi" - description: "Control the API to disable the PNO runtime" - bug: "282821585" -} - - -flag { name: "delay_save_to_store" namespace: "wifi" description: "Control the feature delay the save to store in batch to reduce the blocking time" @@ -30,49 +23,8 @@ flag { } flag { - name: "vendor_parcelable_parameters" - namespace: "wifi" - description: "Control the APIs that allow additional vendor-specific parcelables" - bug: "296069900" -} - -flag { - name: "verbose_logging_for_aware_only" - namespace: "wifi" - description: "Control the API that allow only enable verbose logging for Wifi Aware" - bug: "289273616" -} - -flag { - name: "add_channel_stats_per_link" - namespace: "wifi" - description: "Control the API that get the channel stats per link from WifiUsabilityStatsEntry" - bug: "276385220" -} - -flag { - name: "mlo_link_capabilities_info" - namespace: "wifi" - description: "Control the API that get the MLO link capabilities" - bug: "262643386" -} - -flag { - name: "disable_reason_unwanted_low_rssi" - namespace: "wifi" - description: "Control the API that as disable because of unwanted network under sufficient rssi" - bug: "262643386" -} - -flag { - name: "low_latency_lock_listener" - namespace: "wifi" - description: "Control the API that add/remove the low latency lock listener" - bug: "277556184" -} - -flag { name: "network_provider_battery_charging_status" + is_exported: true namespace: "wifi" description: "Control the API that allows setting / reading the NetworkProviderInfo's battery charging status" bug: "305067231" @@ -80,6 +32,7 @@ flag { flag { name: "shared_connectivity_broadcast_receiver_test_api" + is_exported: true namespace: "wifi" description: "Control the test API for SharedConnectivityManager's getBroadcastReceiver() method" bug: "305067231" @@ -93,22 +46,18 @@ flag { } flag { - name: "wep_usage" - namespace: "wifi" - description: "Control the API for wep usage" - bug: "275367422" -} - -flag { - name: "wpa_personal_usage" + name: "android_v_wifi_api" + is_exported: true namespace: "wifi" - description: "Control the API for wpa personal usage" - bug: "275367422" + description: "For new API added to Android V" + bug: "319927407" + is_fixed_read_only: true } flag { - name: "add_subscription_id" + name: "d2d_when_infra_sta_off" namespace: "wifi" - description: "Add new API to set the subscription id in the Wifi Info" - bug: "236669534" + description: "Add new API to configure d2d when infra sta is off" + bug: "295792510" + is_fixed_read_only: true } diff --git a/framework/Android.bp b/framework/Android.bp index 250b7535a6..4cc0613dbd 100644 --- a/framework/Android.bp +++ b/framework/Android.bp @@ -45,6 +45,7 @@ filegroup { ":framework-wifi-updatable-java-sources", ":framework-wifi-updatable-exported-aidl-sources", ":module-utils-os-aidls", + ":wifi_framework_aconfig_flags_lib{.generated_srcjars}", ], } @@ -112,6 +113,9 @@ java_defaults { "androidx.annotation_annotation", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage "app-compat-annotations", + // Add aconfig-annotations-lib as a dependency for the optimization + "aconfig-annotations-lib", + "framework-configinfrastructure", ], aidl: { generate_get_transaction_name: true, @@ -155,7 +159,6 @@ java_sdk_library { ], impl_only_libs: [ - "framework-location.stubs.module_lib", "framework-connectivity.stubs.module_lib", "framework-location.stubs.module_lib", "framework-tethering.stubs.module_lib", @@ -182,6 +185,9 @@ java_sdk_library { "framework-tethering.stubs.module_lib", ], }, + api_srcs: [ + ":wifi_javadoc_only_files", + ], jarjar_rules: ":wifi-jarjar-rules", diff --git a/framework/aidl-export/android/net/wifi/MscsParams.aidl b/framework/aidl-export/android/net/wifi/MscsParams.aidl new file mode 100644 index 0000000000..96d378bc9d --- /dev/null +++ b/framework/aidl-export/android/net/wifi/MscsParams.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2023, 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 android.net.wifi; + +parcelable MscsParams; diff --git a/framework/aidl-export/android/net/wifi/OuiKeyedData.aidl b/framework/aidl-export/android/net/wifi/OuiKeyedData.aidl new file mode 100644 index 0000000000..802c5e7b36 --- /dev/null +++ b/framework/aidl-export/android/net/wifi/OuiKeyedData.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2024, 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 android.net.wifi; + +parcelable OuiKeyedData; diff --git a/framework/aidl-export/android/net/wifi/p2p/WifiP2pGroupList.aidl b/framework/aidl-export/android/net/wifi/p2p/WifiP2pGroupList.aidl new file mode 100644 index 0000000000..eb52254a5a --- /dev/null +++ b/framework/aidl-export/android/net/wifi/p2p/WifiP2pGroupList.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2023, 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 android.net.wifi.p2p; + +parcelable WifiP2pGroupList; diff --git a/framework/aidl-export/android/net/wifi/twt/TwtRequest.aidl b/framework/aidl-export/android/net/wifi/twt/TwtRequest.aidl new file mode 100644 index 0000000000..59b415855f --- /dev/null +++ b/framework/aidl-export/android/net/wifi/twt/TwtRequest.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2024, 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 android.net.wifi.twt; + +parcelable TwtRequest; diff --git a/framework/api/current.txt b/framework/api/current.txt index 40d2765497..f48cfe84f1 100644 --- a/framework/api/current.txt +++ b/framework/api/current.txt @@ -52,8 +52,10 @@ package android.net.wifi { method @NonNull public int[] getSecurityTypes(); method @Nullable public android.net.wifi.WifiSsid getWifiSsid(); method public int getWifiStandard(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean is80211azNtbResponder(); method public boolean is80211mcResponder(); method public boolean isPasspointNetwork(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isTwtResponder(); method public void writeToParcel(android.os.Parcel, int); field public String BSSID; field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3 @@ -389,6 +391,7 @@ package android.net.wifi { method public int getNetworkId(); method @Nullable public String getPasspointFqdn(); method @Nullable public String getPasspointProviderFriendlyName(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @Nullable public String getPasspointUniqueId(); method public int getRssi(); method @IntRange(from=0xffffffff) public int getRxLinkSpeedMbps(); method public String getSSID(); @@ -427,7 +430,7 @@ package android.net.wifi { method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int); method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int); method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]); - method @FlaggedApi("com.android.wifi.flags.add_subscription_id") @NonNull public android.net.wifi.WifiInfo.Builder setSubscriptionId(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.WifiInfo.Builder setSubscriptionId(int); } public class WifiManager { @@ -463,6 +466,7 @@ package android.net.wifi { method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions(); method public void getNumberOfEnabledTdlsSessions(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @Deprecated public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void getPerSsidRoamingModes(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.lang.Integer>>); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public java.util.List<android.net.wifi.ScanResult> getScanResults(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getStaConcurrencyForMultiInternetMode(); method @NonNull @RequiresPermission(android.Manifest.permission.NEARBY_WIFI_DEVICES) public java.util.List<android.net.wifi.WifiAvailableChannel> getUsableChannels(int, int); @@ -471,9 +475,11 @@ package android.net.wifi { method public boolean is5GHzBandSupported(); method public boolean is60GHzBandSupported(); method public boolean is6GHzBandSupported(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isAggressiveRoamingModeSupported(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isAutoWakeupEnabled(); method public boolean isBridgedApConcurrencySupported(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isCarrierNetworkOffloadEnabled(int, boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isD2dSupportedWhenInfraStaDisabled(); method public boolean isDecoratedIdentitySupported(); method @Deprecated public boolean isDeviceToApRttSupported(); method public boolean isDualBandSimultaneousSupported(); @@ -499,7 +505,7 @@ package android.net.wifi { method public boolean isTlsV13Supported(); method public boolean isTrustOnFirstUseSupported(); method public boolean isWapiSupported(); - method @FlaggedApi("com.android.wifi.flags.wep_usage") public boolean isWepSupported(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isWepSupported(); method public boolean isWifiDisplayR2Supported(); method public boolean isWifiEnabled(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiPasspointEnabled(); @@ -508,9 +514,10 @@ package android.net.wifi { method public boolean isWpa3SaePublicKeySupported(); method public boolean isWpa3SaeSupported(); method public boolean isWpa3SuiteBSupported(); - method @FlaggedApi("com.android.wifi.flags.wpa_personal_usage") public boolean isWpaPersonalSupported(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isWpaPersonalSupported(); method @Deprecated public boolean pingSupplicant(); method public void queryAutojoinGlobal(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void querySendDhcpHostnameRestriction(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer); method @Deprecated public boolean reassociate(); method @Deprecated public boolean reconnect(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void registerScanResultsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.ScanResultsCallback); @@ -521,10 +528,13 @@ package android.net.wifi { method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, int); method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean removeNonCallerConfiguredNetworks(); method @Deprecated public void removePasspointConfiguration(String); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void removePerSsidRoamingMode(@NonNull android.net.wifi.WifiSsid); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeSuggestionConnectionStatusListener(@NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeSuggestionUserApprovalStatusListener(@NonNull android.net.wifi.WifiManager.SuggestionUserApprovalStatusListener); method @RequiresPermission(allOf={android.Manifest.permission.MANAGE_WIFI_INTERFACES, android.Manifest.permission.ACCESS_WIFI_STATE}) public void reportCreateInterfaceImpact(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.BiConsumer<java.lang.Boolean,java.util.Set<android.net.wifi.WifiManager.InterfaceCreationImpact>>); method @Deprecated public boolean saveConfiguration(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setPerSsidRoamingMode(@NonNull android.net.wifi.WifiSsid, int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setSendDhcpHostnameRestriction(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabled(@NonNull java.net.InetAddress, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method public void setTdlsEnabledWithMacAddress(String, boolean); @@ -558,8 +568,13 @@ package android.net.wifi { field @Deprecated public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError"; field @Deprecated public static final String EXTRA_WIFI_INFO = "wifiInfo"; field public static final String EXTRA_WIFI_STATE = "wifi_state"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN = 1; // 0x1 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE = 2; // 0x2 field public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; field public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int ROAMING_MODE_AGGRESSIVE = 2; // 0x2 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int ROAMING_MODE_NONE = 0; // 0x0 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int ROAMING_MODE_NORMAL = 1; // 0x1 field public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED"; field public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS"; field public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_ASSOCIATION = 1; // 0x1 @@ -751,6 +766,7 @@ package android.net.wifi { method public boolean isRestricted(); method public boolean isUntrusted(); method public boolean isUserInteractionRequired(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isWifi7Enabled(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR; field public static final int RANDOMIZATION_NON_PERSISTENT = 1; // 0x1 @@ -781,6 +797,7 @@ package android.net.wifi { method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean); method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig); method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiPassphrase(@NonNull String); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWifi7Enabled(boolean); method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWifiSsid(@NonNull android.net.wifi.WifiSsid); method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig); method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2Passphrase(@NonNull String); @@ -1267,6 +1284,7 @@ package android.net.wifi.p2p { ctor public WifiP2pDevice(); ctor public WifiP2pDevice(android.net.wifi.p2p.WifiP2pDevice); method public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @Nullable public java.net.InetAddress getIpAddress(); method @NonNull public java.util.List<android.net.wifi.ScanResult.InformationElement> getVendorElements(); method @Nullable public android.net.wifi.p2p.WifiP2pWfdInfo getWfdInfo(); method public boolean isGroupOwner(); @@ -1299,6 +1317,20 @@ package android.net.wifi.p2p { field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pDeviceList> CREATOR; } + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class WifiP2pDiscoveryConfig implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getFrequencyMhz(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getScanType(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pDiscoveryConfig> CREATOR; + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class WifiP2pDiscoveryConfig.Builder { + ctor @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public WifiP2pDiscoveryConfig.Builder(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.p2p.WifiP2pDiscoveryConfig build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.p2p.WifiP2pDiscoveryConfig.Builder setFrequencyMhz(@IntRange(from=0) int); + } + public class WifiP2pGroup implements android.os.Parcelable { ctor public WifiP2pGroup(); ctor public WifiP2pGroup(android.net.wifi.p2p.WifiP2pGroup); @@ -1349,6 +1381,7 @@ package android.net.wifi.p2p { method public boolean isGroupClientRemovalSupported(); method public boolean isGroupOwnerIPv6LinkLocalAddressProvided(); method public boolean isSetVendorElementsSupported(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(allOf={android.Manifest.permission.NEARBY_WIFI_DEVICES, android.Manifest.permission.ACCESS_WIFI_STATE}, conditional=true) public void registerWifiP2pListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.p2p.WifiP2pManager.WifiP2pListener); method public void removeClient(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.MacAddress, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); method @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void removeExternalApprover(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.MacAddress, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener); @@ -1369,8 +1402,10 @@ package android.net.wifi.p2p { method @RequiresPermission(allOf={android.Manifest.permission.NEARBY_WIFI_DEVICES, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setVendorElements(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull java.util.List<android.net.wifi.ScanResult.InformationElement>, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); method @RequiresPermission(allOf={android.Manifest.permission.NEARBY_WIFI_DEVICES, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(allOf={android.Manifest.permission.NEARBY_WIFI_DEVICES, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public void startPeerDiscovery(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pDiscoveryConfig, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); method public void stopListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); method public void stopPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void unregisterWifiP2pListener(@NonNull android.net.wifi.p2p.WifiP2pManager.WifiP2pListener); field public static final String ACTION_WIFI_P2P_LISTEN_STATE_CHANGED = "android.net.wifi.p2p.action.WIFI_P2P_LISTEN_STATE_CHANGED"; field public static final String ACTION_WIFI_P2P_REQUEST_RESPONSE_CHANGED = "android.net.wifi.p2p.action.WIFI_P2P_REQUEST_RESPONSE_CHANGED"; field public static final int BUSY = 2; // 0x2 @@ -1389,6 +1424,12 @@ package android.net.wifi.p2p { field public static final String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo"; field public static final String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo"; field public static final String EXTRA_WIFI_STATE = "wifi_p2p_state"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int GROUP_CREATION_FAILURE_REASON_CONNECTION_CANCELLED = 0; // 0x0 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int GROUP_CREATION_FAILURE_REASON_GROUP_REMOVED = 4; // 0x4 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int GROUP_CREATION_FAILURE_REASON_INVITATION_FAILED = 5; // 0x5 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED = 3; // 0x3 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int GROUP_CREATION_FAILURE_REASON_TIMED_OUT = 1; // 0x1 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int GROUP_CREATION_FAILURE_REASON_USER_REJECTED = 2; // 0x2 field public static final int NO_SERVICE_REQUESTS = 3; // 0x3 field public static final int P2P_UNSUPPORTED = 1; // 0x1 field public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_STATE_CHANGE"; @@ -1398,6 +1439,9 @@ package android.net.wifi.p2p { field public static final int WIFI_P2P_LISTEN_STARTED = 2; // 0x2 field public static final int WIFI_P2P_LISTEN_STOPPED = 1; // 0x1 field public static final String WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int WIFI_P2P_SCAN_FULL = 0; // 0x0 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int WIFI_P2P_SCAN_SINGLE_FREQ = 2; // 0x2 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int WIFI_P2P_SCAN_SOCIAL = 1; // 0x1 field public static final String WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED"; field public static final int WIFI_P2P_STATE_DISABLED = 1; // 0x1 field public static final int WIFI_P2P_STATE_ENABLED = 2; // 0x2 @@ -1475,6 +1519,22 @@ package android.net.wifi.p2p { method public void onUpnpServiceAvailable(java.util.List<java.lang.String>, android.net.wifi.p2p.WifiP2pDevice); } + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static interface WifiP2pManager.WifiP2pListener { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onDeviceConfigurationChanged(@Nullable android.net.wifi.p2p.WifiP2pDevice); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onDiscoveryStateChanged(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onFrequencyChanged(@NonNull android.net.wifi.p2p.WifiP2pInfo, @NonNull android.net.wifi.p2p.WifiP2pGroup); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onGroupCreated(@NonNull android.net.wifi.p2p.WifiP2pInfo, @NonNull android.net.wifi.p2p.WifiP2pGroup); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onGroupCreating(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onGroupCreationFailed(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onGroupNegotiationRejectedByUser(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onGroupRemoved(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onListenStateChanged(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onP2pStateChanged(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onPeerClientDisconnected(@NonNull android.net.wifi.p2p.WifiP2pInfo, @NonNull android.net.wifi.p2p.WifiP2pGroup); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onPeerClientJoined(@NonNull android.net.wifi.p2p.WifiP2pInfo, @NonNull android.net.wifi.p2p.WifiP2pGroup); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onPeerListChanged(@NonNull android.net.wifi.p2p.WifiP2pDeviceList); + } + public final class WifiP2pWfdInfo implements android.os.Parcelable { ctor public WifiP2pWfdInfo(); ctor public WifiP2pWfdInfo(@Nullable android.net.wifi.p2p.WifiP2pWfdInfo); @@ -1627,11 +1687,19 @@ package android.net.wifi.rtt { public final class RangingResult implements android.os.Parcelable { method public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int get80211azInitiatorTxLtfRepetitionsCount(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int get80211azNumberOfRxSpatialStreams(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int get80211azNumberOfTxSpatialStreams(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int get80211azResponderTxLtfRepetitionsCount(); method public int getDistanceMm(); method public int getDistanceStdDevMm(); + method @NonNull public byte[] getLci(); + method @NonNull public byte[] getLcr(); method @Nullable public android.net.MacAddress getMacAddress(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public long getMaxTimeBetweenNtbMeasurementsMicros(); method public int getMeasurementBandwidth(); method public int getMeasurementChannelFrequencyMHz(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public long getMinTimeBetweenNtbMeasurementsMicros(); method public int getNumAttemptedMeasurements(); method public int getNumSuccessfulMeasurements(); method @Nullable public android.net.wifi.aware.PeerHandle getPeerHandle(); @@ -1639,6 +1707,7 @@ package android.net.wifi.rtt { method public int getRssi(); method public int getStatus(); method @Nullable public android.net.wifi.rtt.ResponderLocation getUnverifiedResponderLocation(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean is80211azNtbMeasurement(); method public boolean is80211mcMeasurement(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingResult> CREATOR; @@ -1648,6 +1717,33 @@ package android.net.wifi.rtt { field public static final int UNSPECIFIED = -1; // 0xffffffff } + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class RangingResult.Builder { + ctor public RangingResult.Builder(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder set80211azInitiatorTxLtfRepetitionsCount(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder set80211azNtbMeasurement(boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder set80211azNumberOfRxSpatialStreams(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder set80211azNumberOfTxSpatialStreams(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder set80211azResponderTxLtfRepetitionsCount(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder set80211mcMeasurement(boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setDistanceMm(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setDistanceStdDevMm(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setLci(@Nullable byte[]); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setLcr(@Nullable byte[]); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setMacAddress(@Nullable android.net.MacAddress); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setMaxTimeBetweenNtbMeasurementsMicros(long); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setMeasurementBandwidth(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setMeasurementChannelFrequencyMHz(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setMinTimeBetweenNtbMeasurementsMicros(long); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setNumAttemptedMeasurements(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setNumSuccessfulMeasurements(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setPeerHandle(@Nullable android.net.wifi.aware.PeerHandle); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setRangingTimestampMillis(long); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setRssi(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setStatus(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setUnverifiedResponderLocation(@Nullable android.net.wifi.rtt.ResponderLocation); + } + public abstract class RangingResultCallback { ctor public RangingResultCallback(); method public abstract void onRangingFailure(int); @@ -1666,6 +1762,7 @@ package android.net.wifi.rtt { method @Nullable public android.net.MacAddress getMacAddress(); method public int getPreamble(); method public int getResponderType(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean is80211azNtbSupported(); method public boolean is80211mcSupported(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.ResponderConfig> CREATOR; @@ -1676,6 +1773,7 @@ package android.net.wifi.rtt { public static final class ResponderConfig.Builder { ctor public ResponderConfig.Builder(); method @NonNull public android.net.wifi.rtt.ResponderConfig build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.ResponderConfig.Builder set80211azNtbSupported(boolean); method @NonNull public android.net.wifi.rtt.ResponderConfig.Builder set80211mcSupported(boolean); method @NonNull public android.net.wifi.rtt.ResponderConfig.Builder setCenterFreq0Mhz(@IntRange(from=0) int); method @NonNull public android.net.wifi.rtt.ResponderConfig.Builder setCenterFreq1Mhz(@IntRange(from=0) int); @@ -1733,6 +1831,7 @@ package android.net.wifi.rtt { field public static final String ACTION_WIFI_RTT_STATE_CHANGED = "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED"; field public static final String CHARACTERISTICS_KEY_BOOLEAN_LCI = "key_lci"; field public static final String CHARACTERISTICS_KEY_BOOLEAN_LCR = "key_lcr"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final String CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR = "key_ntb_initiator"; field public static final String CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT = "key_one_sided_rtt"; field public static final String CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER = "key_sta_responder"; } diff --git a/framework/api/lint-baseline.txt b/framework/api/lint-baseline.txt index f44824210d..5c8c1f713b 100644 --- a/framework/api/lint-baseline.txt +++ b/framework/api/lint-baseline.txt @@ -77,6 +77,8 @@ RequiresPermission: android.net.wifi.p2p.WifiP2pManager#requestPeers(android.net Method 'requestPeers' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.p2p.WifiP2pManager#startListening(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener): Method 'startListening' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.wifi.p2p.WifiP2pManager#startPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pDiscoveryConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener): + Method 'startPeerDiscovery' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.rtt.WifiRttManager#startRanging(android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback): Method 'startRanging' documentation mentions permissions already declared by @RequiresPermission diff --git a/framework/api/module-lib-lint-baseline.txt b/framework/api/module-lib-lint-baseline.txt index 24552e0c46..1e141e3355 100644 --- a/framework/api/module-lib-lint-baseline.txt +++ b/framework/api/module-lib-lint-baseline.txt @@ -139,6 +139,8 @@ RequiresPermission: android.net.wifi.p2p.WifiP2pManager#requestPersistentGroupIn Method 'requestPersistentGroupInfo' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.p2p.WifiP2pManager#startListening(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener): Method 'startListening' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.wifi.p2p.WifiP2pManager#startPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pDiscoveryConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener): + Method 'startPeerDiscovery' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.rtt.WifiRttManager#startRanging(android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback): Method 'startRanging' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.rtt.WifiRttManager#startRanging(android.os.WorkSource, android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback): diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index d99b5b8a19..444356b641 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt @@ -29,17 +29,82 @@ package android.net.wifi { field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0 } - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") public final class OuiKeyedData implements android.os.Parcelable { - method @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") public int describeContents(); - method @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") @NonNull public android.os.PersistableBundle getData(); - method @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") public int getOui(); - method @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") public void writeToParcel(@NonNull android.os.Parcel, int); - field @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.OuiKeyedData> CREATOR; - } - - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") public static final class OuiKeyedData.Builder { - ctor @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") public OuiKeyedData.Builder(int, @NonNull android.os.PersistableBundle); - method @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") @NonNull public android.net.wifi.OuiKeyedData build(); + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class MscsParams implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getFrameClassifierFields(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=0, to=0x3938700) public int getStreamTimeoutUs(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getUserPriorityBitmap(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=0, to=7) public int getUserPriorityLimit(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.MscsParams> CREATOR; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_DSCP = 32; // 0x20 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_DST_IP_ADDR = 4; // 0x4 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_DST_PORT = 16; // 0x10 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_FLOW_LABEL = 128; // 0x80 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_IP_VERSION = 1; // 0x1 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_PROTOCOL_NEXT_HDR = 64; // 0x40 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_SRC_IP_ADDR = 2; // 0x2 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int FRAME_CLASSIFIER_SRC_PORT = 8; // 0x8 + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class MscsParams.Builder { + ctor @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public MscsParams.Builder(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.MscsParams build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.MscsParams.Builder setFrameClassifierFields(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.MscsParams.Builder setStreamTimeoutUs(@IntRange(from=0, to=0x3938700) int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.MscsParams.Builder setUserPriorityBitmap(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.MscsParams.Builder setUserPriorityLimit(@IntRange(from=0, to=7) int); + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class OuiKeyedData implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.os.PersistableBundle getData(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getOui(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.OuiKeyedData> CREATOR; + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class OuiKeyedData.Builder { + ctor @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public OuiKeyedData.Builder(int, @NonNull android.os.PersistableBundle); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.OuiKeyedData build(); + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class QosCharacteristics implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getBurstSizeOctets(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=0, to=15) public int getCountExponent(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getDelayBoundMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getDeliveryRatio(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Short.MAX_VALUE) public int getMaxMsduSizeOctets(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxServiceIntervalMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMeanDataRateKbps(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMinDataRateKbps(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMinServiceIntervalMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=1, to=java.lang.Short.MAX_VALUE) public int getMsduLifetimeMillis(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getServiceStartTimeLinkId(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=0, to=java.lang.Integer.MAX_VALUE) public int getServiceStartTimeMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.QosCharacteristics> CREATOR; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_95 = 0; // 0x0 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_96 = 1; // 0x1 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_97 = 2; // 0x2 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_98 = 3; // 0x3 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_99 = 5; // 0x5 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_99_9 = 6; // 0x6 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_99_99 = 7; // 0x7 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_99_999 = 8; // 0x8 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DELIVERY_RATIO_99_9999 = 9; // 0x9 + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class QosCharacteristics.Builder { + ctor @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public QosCharacteristics.Builder(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int, @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int, @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int, @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosCharacteristics build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosCharacteristics.Builder setBurstSizeOctets(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosCharacteristics.Builder setMaxMsduSizeOctets(@IntRange(from=1, to=java.lang.Short.MAX_VALUE) int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosCharacteristics.Builder setMeanDataRateKbps(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosCharacteristics.Builder setMsduDeliveryInfo(int, @IntRange(from=0, to=15) int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosCharacteristics.Builder setMsduLifetimeMillis(@IntRange(from=1, to=java.lang.Short.MAX_VALUE) int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosCharacteristics.Builder setServiceStartTimeInfo(@IntRange(from=0, to=java.lang.Integer.MAX_VALUE) int, int); } public final class QosPolicyParams implements android.os.Parcelable { @@ -53,6 +118,7 @@ package android.net.wifi { method public int getIpVersion(); method @IntRange(from=1, to=255) public int getPolicyId(); method public int getProtocol(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @Nullable public android.net.wifi.QosCharacteristics getQosCharacteristics(); method @Nullable public java.net.InetAddress getSourceAddress(); method @IntRange(from=android.net.DscpPolicy.SOURCE_PORT_ANY, to=65535) public int getSourcePort(); method public int getUserPriority(); @@ -90,6 +156,7 @@ package android.net.wifi { method @NonNull public android.net.wifi.QosPolicyParams.Builder setFlowLabel(@Nullable byte[]); method @NonNull public android.net.wifi.QosPolicyParams.Builder setIpVersion(int); method @NonNull public android.net.wifi.QosPolicyParams.Builder setProtocol(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.QosPolicyParams.Builder setQosCharacteristics(@Nullable android.net.wifi.QosCharacteristics); method @NonNull public android.net.wifi.QosPolicyParams.Builder setSourceAddress(@Nullable java.net.InetAddress); method @NonNull public android.net.wifi.QosPolicyParams.Builder setSourcePort(@IntRange(from=android.net.DscpPolicy.SOURCE_PORT_ANY, to=65535) int); method @NonNull public android.net.wifi.QosPolicyParams.Builder setUserPriority(int); @@ -362,7 +429,7 @@ package android.net.wifi { method public int getMaxNumberOfClients(); method @NonNull public android.net.MacAddress getPersistentRandomizedMacAddress(); method public long getShutdownTimeoutMillis(); - method @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); method @NonNull public java.util.List<android.net.wifi.ScanResult.InformationElement> getVendorElements(); method public boolean isAutoShutdownEnabled(); method public boolean isBridgedModeOpportunisticShutdownEnabled(); @@ -407,7 +474,7 @@ package android.net.wifi { method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0xffffffff) long); method @Deprecated @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String); - method @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") @NonNull public android.net.wifi.SoftApConfiguration.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.SoftApConfiguration.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setVendorElements(@NonNull java.util.List<android.net.wifi.ScanResult.InformationElement>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWifiSsid(@Nullable android.net.wifi.WifiSsid); } @@ -418,7 +485,9 @@ package android.net.wifi { method public int getBandwidth(); method @Nullable public android.net.MacAddress getBssid(); method public int getFrequency(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); method public int getWifiStandard(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int CHANNEL_WIDTH_160MHZ = 6; // 0x6 field public static final int CHANNEL_WIDTH_20MHZ = 2; // 0x2 @@ -446,6 +515,18 @@ package android.net.wifi { field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApState> CREATOR; } + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class UriParserResults implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @Nullable public String getInformation(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @Nullable public String getPublicKey(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getUriScheme(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @Nullable public android.net.wifi.WifiConfiguration getWifiConfiguration(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.UriParserResults> CREATOR; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int URI_SCHEME_DPP = 2; // 0x2 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG = 1; // 0x1 + } + public final class WifiClient implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.net.MacAddress getMacAddress(); @@ -467,15 +548,21 @@ package android.net.wifi { method @Deprecated @NonNull public String getPrintableSsid(); method @Deprecated @NonNull public String getProfileKey(); method @Deprecated public int getRecentFailureReason(); + method @Deprecated @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); method @Deprecated public boolean hasNoInternetAccess(); method @Deprecated public boolean isEphemeral(); method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo); method @Deprecated public boolean isNoInternetAccessExpected(); method @Deprecated public boolean isRepeaterEnabled(); + method @Deprecated @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isSendDhcpHostnameEnabled(); + method @Deprecated @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isWifi7Enabled(); method @Deprecated public void setBssidAllowlist(@Nullable java.util.List<android.net.MacAddress>); method @Deprecated public void setDeletionPriority(int) throws java.lang.IllegalArgumentException; method @Deprecated public void setNetworkSelectionStatus(@NonNull android.net.wifi.WifiConfiguration.NetworkSelectionStatus); method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setRepeaterEnabled(boolean); + method @Deprecated @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setSendDhcpHostnameEnabled(boolean); + method @Deprecated @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + method @Deprecated @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setWifi7Enabled(boolean); field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiConfiguration> CREATOR; field @Deprecated public static final int INVALID_NETWORK_ID = -1; // 0xffffffff field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1 @@ -540,7 +627,7 @@ package android.net.wifi { field @Deprecated public static final int DISABLED_NO_INTERNET_PERMANENT = 6; // 0x6 field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4 field @Deprecated public static final int DISABLED_TRANSITION_DISABLE_INDICATION = 13; // 0xd - field @Deprecated @FlaggedApi("com.android.wifi.flags.disable_reason_unwanted_low_rssi") public static final int DISABLED_UNWANTED_LOW_RSSI = 14; // 0xe + field @Deprecated @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int DISABLED_UNWANTED_LOW_RSSI = 14; // 0xe field @Deprecated public static final int NETWORK_SELECTION_ENABLED = 0; // 0x0 field @Deprecated public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; // 0x2 field @Deprecated public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; // 0x1 @@ -596,6 +683,7 @@ package android.net.wifi { method public int getScore(); method public double getSuccessfulRxPacketsPerSecond(); method public double getSuccessfulTxPacketsPerSecond(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); method public boolean isApTidToLinkMappingNegotiationSupported(); method public boolean isCarrierMerged(); method public boolean isEphemeral(); @@ -606,6 +694,7 @@ package android.net.wifi { method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean isPrimary(); method public boolean isTrusted(); method @Nullable public static String sanitizeSsid(@Nullable String); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); field public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; field public static final int INVALID_RSSI = -127; // 0xffffff81 } @@ -613,7 +702,7 @@ package android.net.wifi { public class WifiManager { method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void addQosPolicies(@NonNull java.util.List<android.net.wifi.QosPolicyParams>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<java.lang.Integer>>); - method @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void addWifiLowLatencyLockListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiLowLatencyLockListener); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void addWifiLowLatencyLockListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiLowLatencyLockListener); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void addWifiNetworkStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiNetworkStateChangedListener); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void addWifiVerboseLoggingStatusChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiVerboseLoggingStatusChangedListener); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean); @@ -625,6 +714,8 @@ package android.net.wifi { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void disableMscs(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void enableMscs(@NonNull android.net.wifi.MscsParams); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>); @@ -637,8 +728,8 @@ package android.net.wifi { method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>); method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>); - method @FlaggedApi("com.android.wifi.flags.mlo_link_capabilities_info") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getMaxMloAssociationLinkCount(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @FlaggedApi("com.android.wifi.flags.mlo_link_capabilities_info") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getMaxMloStrLinkCount(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getMaxMloAssociationLinkCount(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getMaxMloStrLinkCount(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method public static int getMaxNumberOfPoliciesPerQosRequest(); method @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getMloMode(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void getNetworkSelectionConfig(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.net.wifi.WifiNetworkSelectionConfig>); @@ -647,7 +738,8 @@ package android.net.wifi { method @Nullable @RequiresPermission(allOf={android.Manifest.permission.NEARBY_WIFI_DEVICES, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}, conditional=true) public android.net.wifi.WifiConfiguration getPrivilegedConnectedNetwork(); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public android.net.wifi.SoftApConfiguration getSoftApConfiguration(); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional=true) public java.util.Set<android.net.wifi.WifiSsid> getSsidsAllowlist(); - method @FlaggedApi("com.android.wifi.flags.mlo_link_capabilities_info") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getSupportedSimultaneousBandCombinations(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<int[]>>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getSupportedSimultaneousBandCombinations(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<int[]>>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void getTwtCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.os.Bundle>); method public int getVerboseLoggingLevel(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener); method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration(); @@ -656,7 +748,7 @@ package android.net.wifi { method public boolean isApMacRandomizationSupported(); method public boolean isConnectedMacRandomizationSupported(); method @Deprecated public boolean isDeviceToDeviceRttSupported(); - method @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") public boolean isLowLatencyModeSupported(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public boolean isLowLatencyModeSupported(); method public boolean isPortableHotspotSupported(); method public boolean isStaConcurrencyForRestrictedConnectionsSupported(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean isThirdPartyAppEnablingWifiConfirmationDialogEnabled(); @@ -665,8 +757,9 @@ package android.net.wifi { method public boolean isWifiScannerSupported(); method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public void notifyMinimumRequiredWifiSecurityLevelChanged(int); method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public void notifyWifiSsidPolicyChanged(@NonNull android.app.admin.WifiSsidPolicy); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void queryD2dAllowedWhenInfraStaDisabled(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void queryLastConfiguredTetheredApPassphraseSinceBoot(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.String>); - method @FlaggedApi("com.android.wifi.flags.wep_usage") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void queryWepAllowed(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void queryWepAllowed(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void registerActiveCountryCodeChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.ActiveCountryCodeChangedCallback); method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void registerCoexCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.CoexCallback); method @RequiresPermission(android.Manifest.permission.NEARBY_WIFI_DEVICES) public void registerLocalOnlyHotspotSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback); @@ -677,19 +770,22 @@ package android.net.wifi { method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void removeAppState(int, @NonNull String); method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void removeQosPolicies(@NonNull int[]); - method @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") public void removeWifiLowLatencyLockListener(@NonNull android.net.wifi.WifiManager.WifiLowLatencyLockListener); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void removeWifiLowLatencyLockListener(@NonNull android.net.wifi.WifiManager.WifiLowLatencyLockListener); method public void removeWifiNetworkStateChangedListener(@NonNull android.net.wifi.WifiManager.WifiNetworkStateChangedListener); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeWifiVerboseLoggingStatusChangedListener(@NonNull android.net.wifi.WifiManager.WifiVerboseLoggingStatusChangedListener); method @RequiresPermission(android.Manifest.permission.RESTART_WIFI_SUBSYSTEM) public void restartWifiSubsystem(); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]); method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration restoreSoftApBackupData(@NonNull byte[]); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreWifiBackupData(@NonNull byte[]); method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData(); method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void retrieveWifiBackupData(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setCarrierNetworkOffloadEnabled(int, boolean, boolean); method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS) public void setCoexUnsafeChannels(@NonNull java.util.List<android.net.wifi.CoexUnsafeChannel>, int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setD2dAllowedWhenInfraStaDisabled(boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE) public void setDefaultCountryCode(@NonNull String); method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}) public void setExternalPnoScanRequest(@NonNull java.util.List<android.net.wifi.WifiSsid>, @Nullable int[], @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.PnoScanResultsCallback); @@ -700,7 +796,7 @@ package android.net.wifi { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void setOneShotScreenOnConnectivityScanDelayMillis(@IntRange(from=0) int); method @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE) public void setOverrideCountryCode(@NonNull String); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int); - method @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setPnoScanState(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setPnoScanState(int); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanThrottleEnabled(boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}) public void setScreenOnScanSchedule(@Nullable java.util.List<android.net.wifi.WifiManager.ScreenOnScanSchedule>); @@ -710,11 +806,12 @@ package android.net.wifi { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.DUMP}) public void setVerboseLoggingEnabled(boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.DUMP}) public void setVerboseLoggingLevel(int); - method @FlaggedApi("com.android.wifi.flags.wep_usage") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setWepAllowed(boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setWepAllowed(boolean); method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration); method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setWifiPasspointEnabled(boolean); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setWifiScoringEnabled(boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void setupTwtSession(@NonNull android.net.wifi.twt.TwtRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.twt.TwtSessionCallback); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeResponder(@Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback); @@ -722,7 +819,7 @@ package android.net.wifi { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startRestrictingAutoJoinToSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback); - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration); method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspotRequest(@NonNull android.net.TetheringManager.TetheringRequest); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopRestrictingAutoJoinToSubscriptionId(); @@ -756,6 +853,7 @@ package android.net.wifi { field public static final int API_P2P_DISCOVER_PEERS = 21; // 0x15 field public static final int API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS = 22; // 0x16 field public static final int API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY = 23; // 0x17 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS = 37; // 0x25 field public static final int API_P2P_REMOVE_GROUP = 29; // 0x1d field public static final int API_P2P_SET_CHANNELS = 32; // 0x20 field public static final int API_P2P_START_LISTENING = 30; // 0x1e @@ -765,7 +863,7 @@ package android.net.wifi { field public static final int API_SCANNING_ENABLED = 1; // 0x1 field public static final int API_SET_NETWORK_SELECTION_CONFIG = 8; // 0x8 field public static final int API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY = 7; // 0x7 - field @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") public static final int API_SET_PNO_SCAN_ENABLED = 36; // 0x24 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int API_SET_PNO_SCAN_ENABLED = 36; // 0x24 field public static final int API_SET_SCAN_SCHEDULE = 6; // 0x6 field public static final int API_SET_TDLS_ENABLED = 34; // 0x22 field public static final int API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS = 35; // 0x23 @@ -819,9 +917,9 @@ package android.net.wifi { field public static final int MLO_MODE_LOW_POWER = 3; // 0x3 field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0 field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1 - field @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") public static final int PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT = 0; // 0x0 - field @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") public static final int PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE = 1; // 0x1 - field @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") public static final int PNO_SCAN_STATE_ENABLED = 2; // 0x2 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT = 0; // 0x0 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE = 1; // 0x1 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int PNO_SCAN_STATE_ENABLED = 2; // 0x2 field public static final int QOS_REQUEST_STATUS_ALREADY_ACTIVE = 1; // 0x1 field public static final int QOS_REQUEST_STATUS_FAILURE_UNKNOWN = 4; // 0x4 field public static final int QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES = 2; // 0x2 @@ -833,10 +931,15 @@ package android.net.wifi { field public static final int SAP_START_FAILURE_NO_CHANNEL = 1; // 0x1 field public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2; // 0x2 field public static final int SAP_START_FAILURE_USER_REJECTED = 3; // 0x3 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final String TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER = "key_requester"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final String TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS = "key_max_wake_duration"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final String TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS = "key_min_wake_duration"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final String TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS = "key_max_wake_interval"; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final String TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS = "key_min_wake_interval"; field public static final int VERBOSE_LOGGING_LEVEL_DISABLED = 0; // 0x0 field public static final int VERBOSE_LOGGING_LEVEL_ENABLED = 1; // 0x1 field public static final int VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY = 2; // 0x2 - field @FlaggedApi("com.android.wifi.flags.verbose_logging_for_aware_only") public static final int VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY = 3; // 0x3 + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final int VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY = 3; // 0x3 field @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED"; field public static final int WIFI_AP_STATE_DISABLED = 11; // 0xb field public static final int WIFI_AP_STATE_DISABLING = 10; // 0xa @@ -945,10 +1048,10 @@ package android.net.wifi { method public void onStop(int); } - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") public static interface WifiManager.WifiLowLatencyLockListener { - method @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") public void onActivatedStateChanged(boolean); - method @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") public default void onActiveUsersChanged(@NonNull int[]); - method @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") public default void onOwnershipChanged(@NonNull int[]); + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static interface WifiManager.WifiLowLatencyLockListener { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void onActivatedStateChanged(boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onActiveUsersChanged(@NonNull int[]); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onOwnershipChanged(@NonNull int[]); } public static interface WifiManager.WifiNetworkStateChangedListener { @@ -1029,6 +1132,7 @@ package android.net.wifi { method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]); method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings); method @NonNull @RequiresPermission(android.Manifest.permission.NEARBY_WIFI_DEVICES) public java.util.List<java.lang.Integer> getAvailableChannels(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public void getCachedScanData(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.net.wifi.WifiScanner.ScanData>); method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults(); method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.net.wifi.ScanResult> getSingleScanResults(); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean isScanning(); @@ -1192,6 +1296,10 @@ package android.net.wifi { field @Deprecated public int unchangedSampleSize; } + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public class WifiUriParser { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static android.net.wifi.UriParserResults parseUri(@NonNull String); + } + public final class WifiUsabilityStatsEntry implements android.os.Parcelable { method public int describeContents(); method public int getCellularDataNetworkType(); @@ -1220,12 +1328,12 @@ package android.net.wifi { method public long getTotalBeaconRx(); method public long getTotalBeaconRx(int); method public long getTotalCcaBusyFreqTimeMillis(); - method @FlaggedApi("com.android.wifi.flags.add_channel_stats_per_link") public long getTotalCcaBusyFreqTimeMillis(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public long getTotalCcaBusyFreqTimeMillis(int); method public long getTotalHotspot2ScanTimeMillis(); method public long getTotalNanScanTimeMillis(); method public long getTotalPnoScanTimeMillis(); method public long getTotalRadioOnFreqTimeMillis(); - method @FlaggedApi("com.android.wifi.flags.add_channel_stats_per_link") public long getTotalRadioOnFreqTimeMillis(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public long getTotalRadioOnFreqTimeMillis(int); method public long getTotalRadioOnTimeMillis(); method public long getTotalRadioRxTimeMillis(); method public long getTotalRadioTxTimeMillis(); @@ -1350,6 +1458,19 @@ package android.net.wifi.aware { field public static final int UNSET_PARAMETER = -1; // 0xffffffff } + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class ConfigRequest implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.ConfigRequest> CREATOR; + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class ConfigRequest.Builder { + ctor public ConfigRequest.Builder(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.aware.ConfigRequest build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.aware.ConfigRequest.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + } + public class DiscoverySession implements java.lang.AutoCloseable { method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]); method @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public void resume(); @@ -1364,22 +1485,31 @@ package android.net.wifi.aware { } public final class PublishConfig implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); method public boolean isSuspendable(); } public static final class PublishConfig.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public android.net.wifi.aware.PublishConfig.Builder setSuspendable(boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.aware.PublishConfig.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + } + + public final class ServiceDiscoveryInfo { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); } public final class SubscribeConfig implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); method public boolean isSuspendable(); } public static final class SubscribeConfig.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION) public android.net.wifi.aware.SubscribeConfig.Builder setSuspendable(boolean); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.aware.SubscribeConfig.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); } public class WifiAwareManager { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(allOf={android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.NEARBY_WIFI_DEVICES, android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional=true) public void attach(@NonNull android.net.wifi.aware.ConfigRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.aware.AttachCallback, @NonNull android.net.wifi.aware.IdentityChangedListener); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void attachOffload(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.aware.AttachCallback); method @RequiresPermission(allOf={android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void enableInstantCommunicationMode(boolean); method @RequiresPermission(allOf={android.Manifest.permission.OVERRIDE_WIFI_CONFIG, android.Manifest.permission.CHANGE_WIFI_STATE}) public void setAwareParams(@Nullable android.net.wifi.aware.AwareParams); @@ -1462,13 +1592,46 @@ package android.net.wifi.hotspot2 { package android.net.wifi.p2p { public class WifiP2pConfig implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); method public boolean isJoinExistingGroup(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); } public static final class WifiP2pConfig.Builder { method @NonNull public android.net.wifi.p2p.WifiP2pConfig.Builder setJoinExistingGroup(boolean); } + public class WifiP2pDevice implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class WifiP2pDiscoveryConfig implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class WifiP2pDiscoveryConfig.Builder { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.p2p.WifiP2pDiscoveryConfig.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class WifiP2pExtListenParams implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pExtListenParams> CREATOR; + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class WifiP2pExtListenParams.Builder { + ctor @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public WifiP2pExtListenParams.Builder(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.p2p.WifiP2pExtListenParams build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.p2p.WifiP2pExtListenParams.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + } + + public class WifiP2pGroup implements android.os.Parcelable { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); + } + public final class WifiP2pGroupList implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List<android.net.wifi.p2p.WifiP2pGroup> getGroupList(); @@ -1483,6 +1646,7 @@ package android.net.wifi.p2p { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setMiracastMode(int); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @RequiresPermission(allOf={android.Manifest.permission.NEARBY_WIFI_DEVICES, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pExtListenParams, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); field public static final String ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED = "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED"; field public static final int MIRACAST_DISABLED = 0; // 0x0 field public static final int MIRACAST_SINK = 2; // 0x2 @@ -1493,17 +1657,29 @@ package android.net.wifi.p2p { method public void onPersistentGroupInfoAvailable(@NonNull android.net.wifi.p2p.WifiP2pGroupList); } + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static interface WifiP2pManager.WifiP2pListener { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public default void onPersistentGroupsChanged(@NonNull android.net.wifi.p2p.WifiP2pGroupList); + } + } package android.net.wifi.rtt { public final class RangingRequest implements android.os.Parcelable { method @NonNull public java.util.List<android.net.wifi.rtt.ResponderConfig> getRttResponders(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + } + + public static final class RangingRequest.Builder { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingRequest.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); } public final class RangingResult implements android.os.Parcelable { - method @NonNull public byte[] getLci(); - method @NonNull public byte[] getLcr(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public java.util.List<android.net.wifi.OuiKeyedData> getVendorData(); + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class RangingResult.Builder { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.rtt.RangingResult.Builder setVendorData(@NonNull java.util.List<android.net.wifi.OuiKeyedData>); } public final class ResponderConfig implements android.os.Parcelable { @@ -1533,6 +1709,7 @@ package android.net.wifi.rtt { field @Nullable public final android.net.wifi.aware.PeerHandle peerHandle; field public final int preamble; field public final int responderType; + field @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final boolean supports80211azNtb; field public final boolean supports80211mc; } @@ -1547,3 +1724,57 @@ package android.net.wifi.rtt { } +package android.net.wifi.twt { + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class TwtRequest implements android.os.Parcelable { + method public int describeContents(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @IntRange(from=android.net.wifi.MloLink.INVALID_MLO_LINK_ID, to=0xf) public int getLinkId(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getMaxWakeDurationMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public long getMaxWakeIntervalMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getMinWakeDurationMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public long getMinWakeIntervalMicros(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.twt.TwtRequest> CREATOR; + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public static final class TwtRequest.Builder { + ctor @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public TwtRequest.Builder(int, int, long, long); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.twt.TwtRequest build(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") @NonNull public android.net.wifi.twt.TwtRequest.Builder setLinkId(@IntRange(from=0x0, to=0xf) int); + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public interface TwtSession { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getMloLinkId(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void getStats(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.os.Bundle>); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public int getWakeDurationMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public long getWakeIntervalMicros(); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void teardown(); + field public static final String TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS = "key_avg_eosp_dur"; + field public static final String TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT = "key_avg_rx_pkt_count"; + field public static final String TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE = "key_avg_rx_pkt_size"; + field public static final String TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT = "key_avg_tx_pkt_count"; + field public static final String TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE = "key_avg_tx_pkt_size"; + field public static final String TWT_STATS_KEY_INT_EOSP_COUNT = "key_eosp_count"; + } + + @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public interface TwtSessionCallback { + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void onCreate(@NonNull android.net.wifi.twt.TwtSession); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void onFailure(int); + method @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public void onTeardown(int); + field public static final int TWT_ERROR_CODE_AP_NOT_SUPPORTED = 1; // 0x1 + field public static final int TWT_ERROR_CODE_AP_OUI_BLOCKLISTED = 2; // 0x2 + field public static final int TWT_ERROR_CODE_AP_REJECTED = 3; // 0x3 + field public static final int TWT_ERROR_CODE_FAIL = 0; // 0x0 + field public static final int TWT_ERROR_CODE_INVALID_PARAMS = 4; // 0x4 + field public static final int TWT_ERROR_CODE_MAX_SESSIONS_REACHED = 5; // 0x5 + field public static final int TWT_ERROR_CODE_NOT_AVAILABLE = 6; // 0x6 + field public static final int TWT_ERROR_CODE_NOT_SUPPORTED = 7; // 0x7 + field public static final int TWT_ERROR_CODE_TIMEOUT = 8; // 0x8 + field public static final int TWT_REASON_CODE_INTERNALLY_INITIATED = 2; // 0x2 + field public static final int TWT_REASON_CODE_LOCALLY_REQUESTED = 1; // 0x1 + field public static final int TWT_REASON_CODE_PEER_INITIATED = 3; // 0x3 + field public static final int TWT_REASON_CODE_UNKNOWN = 0; // 0x0 + } + +} + diff --git a/framework/api/system-lint-baseline.txt b/framework/api/system-lint-baseline.txt index 8bfe131555..4de89f0285 100644 --- a/framework/api/system-lint-baseline.txt +++ b/framework/api/system-lint-baseline.txt @@ -47,6 +47,10 @@ DeprecationMismatch: android.net.wifi.WifiScanner.WifiChangeSettings: Class android.net.wifi.WifiScanner.WifiChangeSettings: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match +MissingGetterMatchingBuilder: android.net.wifi.QosCharacteristics.Builder#setMsduDeliveryInfo(int, int): + android.net.wifi.QosCharacteristics does not declare a `getMsduDeliveryInfo()` method matching method android.net.wifi.QosCharacteristics.Builder.setMsduDeliveryInfo(int,int) +MissingGetterMatchingBuilder: android.net.wifi.QosCharacteristics.Builder#setServiceStartTimeInfo(int, int): + android.net.wifi.QosCharacteristics does not declare a `getServiceStartTimeInfo()` method matching method android.net.wifi.QosCharacteristics.Builder.setServiceStartTimeInfo(int,int) MissingGetterMatchingBuilder: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig): @@ -155,6 +159,8 @@ RequiresPermission: android.net.wifi.p2p.WifiP2pManager#requestPersistentGroupIn Method 'requestPersistentGroupInfo' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.p2p.WifiP2pManager#startListening(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener): Method 'startListening' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.net.wifi.p2p.WifiP2pManager#startPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pDiscoveryConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener): + Method 'startPeerDiscovery' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.rtt.WifiRttManager#startRanging(android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback): Method 'startRanging' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.wifi.rtt.WifiRttManager#startRanging(android.os.WorkSource, android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback): diff --git a/framework/jarjar-rules.txt b/framework/jarjar-rules.txt index 8c826dc9c9..f1b4000737 100644 --- a/framework/jarjar-rules.txt +++ b/framework/jarjar-rules.txt @@ -86,6 +86,8 @@ rule android.util.BackupUtils* com.android.wifi.x.@0 rule android.util.LocalLog* com.android.wifi.x.@0 rule android.util.Rational* com.android.wifi.x.@0 +rule com.android.wifi.flags.** com.android.wifi.x.@0 + # Use our statically linked bouncy castle library rule org.bouncycastle.** com.android.wifi.x.@0 # Use our statically linked protobuf library diff --git a/framework/java/android/net/wifi/BaseWifiService.java b/framework/java/android/net/wifi/BaseWifiService.java index 7dc7caccc7..3e8ccdd37f 100644 --- a/framework/java/android/net/wifi/BaseWifiService.java +++ b/framework/java/android/net/wifi/BaseWifiService.java @@ -21,9 +21,11 @@ import android.annotation.Nullable; import android.net.DhcpInfo; import android.net.DhcpOption; import android.net.Network; +import android.net.TetheringManager; import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.twt.TwtRequest; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -470,12 +472,24 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } + /** + * Following method is deprecated with + * {@link #startTetheredHotspotRequest(TetheringManager.TetheringRequest, String)} + * @deprecated This is no longer supported. + */ + @Deprecated @Override public boolean startTetheredHotspot(SoftApConfiguration softApConfig, String packageName) { throw new UnsupportedOperationException(); } @Override + public boolean startTetheredHotspotRequest( + TetheringManager.TetheringRequest request, String packageName) { + throw new UnsupportedOperationException(); + } + + @Override public boolean stopSoftAp() { throw new UnsupportedOperationException(); } @@ -619,6 +633,16 @@ public class BaseWifiService extends IWifiManager.Stub { } @Override + public void retrieveWifiBackupData(@NonNull IByteArrayListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public void restoreWifiBackupData(byte[] data) { + throw new UnsupportedOperationException(); + } + + @Override public byte[] retrieveBackupData() { throw new UnsupportedOperationException(); } @@ -774,11 +798,16 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - @Override + /** TO BE REMOVED */ public void connect(WifiConfiguration config, int netId, IActionListener callback, @NonNull String packageName) { throw new UnsupportedOperationException(); } + @Override + public void connect(WifiConfiguration config, int netId, IActionListener callback, + @NonNull String packageName, Bundle extras) { + throw new UnsupportedOperationException(); + } @Override public void startRestrictingAutoJoinToSubscriptionId(int subId) { @@ -1103,4 +1132,78 @@ public class BaseWifiService extends IWifiManager.Stub { public void queryWepAllowed(@NonNull IBooleanListener listener) { throw new UnsupportedOperationException(); } + + @Override + public void enableMscs(@NonNull MscsParams mscsParams) { + throw new UnsupportedOperationException(); + } + + @Override + public void disableMscs() { + throw new UnsupportedOperationException(); + } + + @Override + public void setSendDhcpHostnameRestriction(@NonNull String packageName, + @WifiManager.SendDhcpHostnameRestriction int restriction) { + throw new UnsupportedOperationException(); + } + + @Override + public void querySendDhcpHostnameRestriction(@NonNull String packageName, + @NonNull IIntegerListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public void setPerSsidRoamingMode(WifiSsid ssid, @WifiManager.RoamingMode int roamingMode, + @NonNull String packageName) { + throw new UnsupportedOperationException(); + } + + @Override + public void removePerSsidRoamingMode(WifiSsid ssid, @NonNull String packageName) { + throw new UnsupportedOperationException(); + } + + @Override + public void getPerSsidRoamingModes(@NonNull String packageName, IMapListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public void setupTwtSession(TwtRequest twtRequest, ITwtCallback iTwtCallback, Bundle extras) { + throw new UnsupportedOperationException(); + } + + @Override + public void getTwtCapabilities(ITwtCapabilitiesListener listener, Bundle extras) { + throw new UnsupportedOperationException(); + } + + @Override + public void getStatsTwtSession(int sessionId, ITwtStatsListener iTwtStatsListener, + Bundle extras) { + throw new UnsupportedOperationException(); + } + + @Override + public void teardownTwtSession(int sessionId, Bundle extras) { + throw new UnsupportedOperationException(); + } + + @Override + public void setD2dAllowedWhenInfraStaDisabled(boolean isAllowed) { + throw new UnsupportedOperationException(); + } + + @Override + public void queryD2dAllowedWhenInfraStaDisabled(@NonNull IBooleanListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isPnoSupported() { + throw new UnsupportedOperationException(); + } } diff --git a/framework/java/android/net/wifi/IBooleanListener.aidl b/framework/java/android/net/wifi/IBooleanListener.aidl index c1f83fc161..0d933f5188 100644 --- a/framework/java/android/net/wifi/IBooleanListener.aidl +++ b/framework/java/android/net/wifi/IBooleanListener.aidl @@ -24,4 +24,4 @@ package android.net.wifi; oneway interface IBooleanListener { void onResult(boolean value); -}
\ No newline at end of file +} diff --git a/framework/java/android/net/wifi/IByteArrayListener.aidl b/framework/java/android/net/wifi/IByteArrayListener.aidl new file mode 100644 index 0000000000..ab7c59ee93 --- /dev/null +++ b/framework/java/android/net/wifi/IByteArrayListener.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +/** + * Interface for IByteArrayListener. + * + * @hide + */ +oneway interface IByteArrayListener +{ + void onResult(in byte[] byteArray); +} diff --git a/framework/java/android/net/wifi/IMapListener.aidl b/framework/java/android/net/wifi/IMapListener.aidl new file mode 100644 index 0000000000..eb914eb993 --- /dev/null +++ b/framework/java/android/net/wifi/IMapListener.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +/** + * Interface for IMapListener. + * + * @hide + */ +oneway interface IMapListener +{ + void onResult(in Map value); +} diff --git a/framework/java/android/net/wifi/IScanDataListener.aidl b/framework/java/android/net/wifi/IScanDataListener.aidl new file mode 100644 index 0000000000..eaf845d0a9 --- /dev/null +++ b/framework/java/android/net/wifi/IScanDataListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 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 android.net.wifi; + +import android.net.wifi.WifiScanner.ScanData; + +/** @hide */ + +oneway interface IScanDataListener +{ + void onResult(in ScanData scanData); +} diff --git a/framework/java/android/net/wifi/ISoftApCallback.aidl b/framework/java/android/net/wifi/ISoftApCallback.aidl index 3db0a5dfe9..4190e4f3ad 100644 --- a/framework/java/android/net/wifi/ISoftApCallback.aidl +++ b/framework/java/android/net/wifi/ISoftApCallback.aidl @@ -15,10 +15,11 @@ */ package android.net.wifi; + import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApInfo; - import android.net.wifi.WifiClient; +import android.net.wifi.SoftApState; /** * Interface for Soft AP callback. @@ -31,13 +32,9 @@ oneway interface ISoftApCallback * Service to manager callback providing current soft AP state. The possible * parameter values listed are defined in WifiManager.java * - * @param state new AP state. One of WIFI_AP_STATE_DISABLED, - * WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, - * WIFI_AP_STATE_ENABLING, WIFI_AP_STATE_FAILED - * @param failureReason reason when in failed state. One of - * SAP_START_FAILURE_GENERAL, SAP_START_FAILURE_NO_CHANNEL + * @param new SoftApState */ - void onStateChanged(int state, int failureReason); + void onStateChanged(in SoftApState state); /** * Service to manager callback providing informations of softap. diff --git a/framework/java/android/net/wifi/ITwtCallback.aidl b/framework/java/android/net/wifi/ITwtCallback.aidl new file mode 100644 index 0000000000..8adf79ad68 --- /dev/null +++ b/framework/java/android/net/wifi/ITwtCallback.aidl @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +/** + * Interface for target wake time (TWT) callback + * + * @hide + */ +oneway interface ITwtCallback +{ + /** + * Called when a TWT session setup operation fails. + * + * @param errorCode setup error code + * @hide + */ + void onFailure(int errorCode); + /** + * Called when a TWT session is torndown. Can be called as a response to + * {@link TwtSession#teardown()} or unsolicited. Check the {@link TwtReasonCode} for more + * details. + * + * @param reasonCode Teardown reason code + * @hide + */ + void onTeardown(int reasonCode); + /** + * Called when the TWT session is created. + * + * @param wakeDuration TWT session wake duration + * @param wakeInterval TWT session wake interval + * @param mloLinkId Multi link operation link id + * @param owner Owner of this session + * @param sessionId TWT session id + * @hide + */ + void onCreate(int wakeDuration, long wakeInterval, int mloLinkId, int owner, int sessionId); +} diff --git a/framework/java/android/net/wifi/ITwtCapabilitiesListener.aidl b/framework/java/android/net/wifi/ITwtCapabilitiesListener.aidl new file mode 100644 index 0000000000..d0d93c1d7e --- /dev/null +++ b/framework/java/android/net/wifi/ITwtCapabilitiesListener.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import android.os.Bundle; + +/** + * Interface for TwtCapabilities callback + * + * @hide + */ +oneway interface ITwtCapabilitiesListener +{ + void onResult(in Bundle value); +} diff --git a/framework/java/android/net/wifi/ITwtStatsListener.aidl b/framework/java/android/net/wifi/ITwtStatsListener.aidl new file mode 100644 index 0000000000..3b286f21c0 --- /dev/null +++ b/framework/java/android/net/wifi/ITwtStatsListener.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import android.os.Bundle; + +/** + * Interface for TwtStats callback + * + * @hide + */ +oneway interface ITwtStatsListener +{ + void onResult(in Bundle value); +} diff --git a/framework/java/android/net/wifi/IWifiManager.aidl b/framework/java/android/net/wifi/IWifiManager.aidl index 6e62c226fa..e3066d7d4b 100644 --- a/framework/java/android/net/wifi/IWifiManager.aidl +++ b/framework/java/android/net/wifi/IWifiManager.aidl @@ -23,9 +23,11 @@ import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.DhcpInfo; import android.net.DhcpOption; import android.net.Network; +import android.net.TetheringManager.TetheringRequest; import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.IActionListener; import android.net.wifi.IBooleanListener; +import android.net.wifi.IByteArrayListener; import android.net.wifi.ICoexCallback; import android.net.wifi.IDppCallback; import android.net.wifi.IIntegerListener; @@ -34,6 +36,7 @@ import android.net.wifi.ILastCallerListener; import android.net.wifi.IListListener; import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.ILocalOnlyConnectionStatusListener; +import android.net.wifi.IMapListener; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.IOnWifiActivityEnergyInfoListener; import android.net.wifi.IOnWifiDriverCountryCodeChangedListener; @@ -47,11 +50,15 @@ import android.net.wifi.ISubsystemRestartCallback; import android.net.wifi.ISuggestionConnectionStatusListener; import android.net.wifi.ISuggestionUserApprovalStatusListener; import android.net.wifi.ITrafficStateCallback; +import android.net.wifi.ITwtCallback; +import android.net.wifi.ITwtCapabilitiesListener; +import android.net.wifi.ITwtStatsListener; import android.net.wifi.IWifiBandsListener; import android.net.wifi.IWifiConnectedNetworkScorer; import android.net.wifi.IWifiLowLatencyLockListener; import android.net.wifi.IWifiNetworkSelectionConfigListener; import android.net.wifi.IWifiVerboseLoggingStatusChangedListener; +import android.net.wifi.MscsParams; import android.net.wifi.QosPolicyParams; import android.net.wifi.ScanResult; import android.net.wifi.SoftApConfiguration; @@ -63,6 +70,8 @@ import android.net.wifi.WifiNetworkSelectionConfig; import android.net.wifi.WifiNetworkSuggestion; import android.net.wifi.WifiSsid; +import android.net.wifi.twt.TwtRequest; + import android.os.Bundle; import android.os.Messenger; import android.os.ResultReceiver; @@ -226,6 +235,8 @@ interface IWifiManager boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName); + boolean startTetheredHotspotRequest(in TetheringRequest request, String packageName); + boolean stopSoftAp(); boolean validateSoftApConfiguration(in SoftApConfiguration config); @@ -342,7 +353,7 @@ interface IWifiManager void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec); - oneway void connect(in WifiConfiguration config, int netId, in IActionListener listener, in String packageName); + oneway void connect(in WifiConfiguration config, int netId, in IActionListener listener, in String packageName, in Bundle extras); oneway void save(in WifiConfiguration config, in IActionListener listener, in String packageName); @@ -472,4 +483,36 @@ interface IWifiManager void setWepAllowed(boolean isAllowed); void queryWepAllowed(in IBooleanListener listener); + + void enableMscs(in MscsParams mscsParams); + + void disableMscs(); + + void setSendDhcpHostnameRestriction(String packageName, int restriction); + + void querySendDhcpHostnameRestriction(String packageName, in IIntegerListener listener); + + void setPerSsidRoamingMode(in WifiSsid ssid, int roamingMode, String packageName); + + void removePerSsidRoamingMode(in WifiSsid ssid, String packageName); + + void getPerSsidRoamingModes(String packageName,in IMapListener listener); + + void getTwtCapabilities(in ITwtCapabilitiesListener listener, in Bundle extras); + + void setupTwtSession(in TwtRequest twtRequest, in ITwtCallback callback, in Bundle extras); + + void getStatsTwtSession(in int sessionId, in ITwtStatsListener listener, in Bundle extras); + + void teardownTwtSession(in int sessionId, in Bundle extras); + + void setD2dAllowedWhenInfraStaDisabled(boolean isAllowed); + + void queryD2dAllowedWhenInfraStaDisabled(in IBooleanListener listener); + + void retrieveWifiBackupData(in IByteArrayListener listener); + + void restoreWifiBackupData(in byte[] data); + + boolean isPnoSupported(); } diff --git a/framework/java/android/net/wifi/IWifiScanner.aidl b/framework/java/android/net/wifi/IWifiScanner.aidl index c819eea101..a0294fc63c 100644 --- a/framework/java/android/net/wifi/IWifiScanner.aidl +++ b/framework/java/android/net/wifi/IWifiScanner.aidl @@ -21,6 +21,7 @@ import android.os.Bundle; import android.os.WorkSource; import android.net.wifi.WifiScanner; import android.net.wifi.ScanResult; +import android.net.wifi.IScanDataListener; import android.net.wifi.IWifiScannerListener; /** @@ -56,6 +57,8 @@ interface IWifiScanner List<ScanResult> getSingleScanResults(String packageName, String featureId); + void getCachedScanData(String packageName, String featureId, in IScanDataListener listener); + void startPnoScan(in IWifiScannerListener listener, in WifiScanner.ScanSettings scanSettings, in WifiScanner.PnoSettings pnoSettings, diff --git a/framework/java/android/net/wifi/MscsParams.java b/framework/java/android/net/wifi/MscsParams.java new file mode 100644 index 0000000000..ee32ab8e2a --- /dev/null +++ b/framework/java/android/net/wifi/MscsParams.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2023 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 android.net.wifi; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.wifi.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Mirrored Stream Classification Service (MSCS) parameters. + * Refer to section 3.1 of the Wi-Fi QoS Management Specification v3.0. + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +public final class MscsParams implements Parcelable { + /** IP version used by the traffic stream */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_IP_VERSION = 1 << 0; + + /** Source IP address used by the traffic stream */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_SRC_IP_ADDR = 1 << 1; + + /** Destination IP address used by the traffic stream */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_DST_IP_ADDR = 1 << 2; + + /** Source port used by the traffic stream */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_SRC_PORT = 1 << 3; + + /** Destination port used by the traffic stream */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_DST_PORT = 1 << 4; + + /** DSCP value used by the traffic stream */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_DSCP = 1 << 5; + + /** Indicates Protocol if using IPv4, or Next Header if using IPv6 */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_PROTOCOL_NEXT_HDR = 1 << 6; + + /** Flow label. Only applicable if using IPv6 */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FRAME_CLASSIFIER_FLOW_LABEL = 1 << 7; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "FRAME_CLASSIFIER_" }, value = { + FRAME_CLASSIFIER_IP_VERSION, + FRAME_CLASSIFIER_SRC_IP_ADDR, + FRAME_CLASSIFIER_DST_IP_ADDR, + FRAME_CLASSIFIER_SRC_PORT, + FRAME_CLASSIFIER_DST_PORT, + FRAME_CLASSIFIER_DSCP, + FRAME_CLASSIFIER_PROTOCOL_NEXT_HDR, + FRAME_CLASSIFIER_FLOW_LABEL, + }) + public @interface FrameClassifierField {} + + /** @hide */ + public static final int DEFAULT_FRAME_CLASSIFIER_FIELDS = + FRAME_CLASSIFIER_IP_VERSION + | FRAME_CLASSIFIER_SRC_IP_ADDR + | FRAME_CLASSIFIER_DST_IP_ADDR + | FRAME_CLASSIFIER_SRC_PORT + | FRAME_CLASSIFIER_DST_PORT + | FRAME_CLASSIFIER_PROTOCOL_NEXT_HDR; + /** @hide */ + public static final int DEFAULT_USER_PRIORITY_BITMAP = (1 << 6) | (1 << 7); + /** @hide */ + public static final int DEFAULT_USER_PRIORITY_LIMIT = 7; // keep the original priority + /** @hide */ + public static final int MAX_STREAM_TIMEOUT_US = 60_000_000; // 60 seconds + + private final int mFrameClassifierFields; + private final int mUserPriorityBitmap; + private final int mUserPriorityLimit; + private final int mStreamTimeoutUs; + + private MscsParams(int frameClassifierFields, int userPriorityBitmap, + int userPriorityLimit, int streamTimeoutUs) { + mFrameClassifierFields = frameClassifierFields; + mUserPriorityBitmap = userPriorityBitmap; + mUserPriorityLimit = userPriorityLimit; + mStreamTimeoutUs = streamTimeoutUs; + } + + /** + * Get the frame classifier fields bitmap. + * See {@link Builder#setFrameClassifierFields(int)} + * + * @return Bitmap of {@link FrameClassifierField} represented as an int. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @FrameClassifierField int getFrameClassifierFields() { + return mFrameClassifierFields; + } + + /** + * Get the user priority bitmap. See {@link Builder#setUserPriorityBitmap(int)} + * + * @return Bitmap of user priorities represented as an int. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int getUserPriorityBitmap() { + return mUserPriorityBitmap; + } + + /** + * Get the user priority limit. See {@link Builder#setUserPriorityLimit(int)} + * + * @return User priority limit. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 0, to = 7) + public int getUserPriorityLimit() { + return mUserPriorityLimit; + } + + /** + * Get the stream timeout in microseconds. See {@link Builder#setStreamTimeoutUs(int)} + * + * @return Stream timeout in microseconds. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 0, to = MAX_STREAM_TIMEOUT_US) + public int getStreamTimeoutUs() { + return mStreamTimeoutUs; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MscsParams that = (MscsParams) o; + return mFrameClassifierFields == that.mFrameClassifierFields + && mUserPriorityBitmap == that.mUserPriorityBitmap + && mUserPriorityLimit == that.mUserPriorityLimit + && mStreamTimeoutUs == that.mStreamTimeoutUs; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + public int hashCode() { + return Objects.hash(mFrameClassifierFields, mUserPriorityBitmap, + mUserPriorityLimit, mStreamTimeoutUs); + } + + @Override + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mFrameClassifierFields); + dest.writeInt(mUserPriorityBitmap); + dest.writeInt(mUserPriorityLimit); + dest.writeInt(mStreamTimeoutUs); + } + + /** @hide */ + MscsParams(@NonNull Parcel in) { + this.mFrameClassifierFields = in.readInt(); + this.mUserPriorityBitmap = in.readInt(); + this.mUserPriorityLimit = in.readInt(); + this.mStreamTimeoutUs = in.readInt(); + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final @NonNull Parcelable.Creator<MscsParams> CREATOR = + new Parcelable.Creator<MscsParams>() { + @Override + public MscsParams createFromParcel(Parcel in) { + return new MscsParams(in); + } + + @Override + public MscsParams[] newArray(int size) { + return new MscsParams[size]; + } + }; + + /** Builder for {@link MscsParams}. */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final class Builder { + private int mFrameClassifierFields = DEFAULT_FRAME_CLASSIFIER_FIELDS; + private int mUserPriorityBitmap = DEFAULT_USER_PRIORITY_BITMAP; + private int mUserPriorityLimit = DEFAULT_USER_PRIORITY_LIMIT; + private int mStreamTimeoutUs = MAX_STREAM_TIMEOUT_US; + + /** + * Constructor for {@link Builder}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public Builder() {} + + /** + * Sets a bitmap of {@link FrameClassifierField} indicating which TCLAS Type 4 frame + * classifier fields should be used to build a classifier. + * + * @param frameClassifierFields Bitmap indicating the requested fields. + * @throws IllegalArgumentException if any bits other than bits 0-7 are set. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setFrameClassifierFields(@FrameClassifierField int frameClassifierFields) { + if ((frameClassifierFields & 0xFFFFFF00) != 0) { + throw new IllegalArgumentException("frameClassifierFields can only use bits 0-7"); + } + mFrameClassifierFields = frameClassifierFields; + return this; + } + + /** + * Sets a bitmap indicating which User Priorities (UPs) should be classified using MSCS. + * The least significant bit corresponds to UP 0, and the most significant + * bit to UP 7. Setting a bit to 1 indicates that UP should be classified. + * + * @param userPriorityBitmap Bitmap indicating which UPs should be classified. + * @throws IllegalArgumentException if any bits other than bits 0-7 are set. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setUserPriorityBitmap(int userPriorityBitmap) { + if ((userPriorityBitmap & 0xFFFFFF00) != 0) { + throw new IllegalArgumentException("userPriorityBitmap can only use bits 0-7"); + } + mUserPriorityBitmap = userPriorityBitmap; + return this; + } + + /** + * Sets the maximum user priority that can be assigned using the MSCS service. + * Value must be between 0 and 7 (inclusive). + * + * @param userPriorityLimit Maximum user priority that can be assigned by MSCS. + * @throws IllegalArgumentException if the provided value is outside the expected range of + * 0-7 (inclusive). + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setUserPriorityLimit(@IntRange(from = 0, to = 7) int userPriorityLimit) { + if (userPriorityLimit < 0 || userPriorityLimit > 7) { + throw new IllegalArgumentException( + "userPriorityLimit must be between 0-7 (inclusive)"); + } + mUserPriorityLimit = userPriorityLimit; + return this; + } + + /** + * Set the minimum timeout (in microseconds) to keep this request in the MSCS list. + * + * @param streamTimeoutUs Minimum timeout in microseconds. + * @throws IllegalArgumentException if the provided value is outside the expected range of + * 0-60 seconds (inclusive). + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setStreamTimeoutUs( + @IntRange(from = 0, to = MAX_STREAM_TIMEOUT_US) int streamTimeoutUs) { + if (streamTimeoutUs < 0 || streamTimeoutUs > MAX_STREAM_TIMEOUT_US) { + throw new IllegalArgumentException("streamTimeoutUs must be 60 seconds or less"); + } + mStreamTimeoutUs = streamTimeoutUs; + return this; + } + + /** + * Construct an MscsParams object using the specified parameters. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public MscsParams build() { + return new MscsParams(mFrameClassifierFields, mUserPriorityBitmap, + mUserPriorityLimit, mStreamTimeoutUs); + } + } +} diff --git a/framework/java/android/net/wifi/OuiKeyedData.java b/framework/java/android/net/wifi/OuiKeyedData.java index 8f2a153a33..8cd599a5da 100644 --- a/framework/java/android/net/wifi/OuiKeyedData.java +++ b/framework/java/android/net/wifi/OuiKeyedData.java @@ -25,6 +25,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import com.android.wifi.flags.Flags; + import java.util.Objects; /** @@ -32,7 +34,7 @@ import java.util.Objects; * * @hide */ -@FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public final class OuiKeyedData implements Parcelable { private static final String TAG = "OuiKeyedData"; @@ -52,7 +54,7 @@ public final class OuiKeyedData implements Parcelable { * * <p>See {@link Builder#Builder(int, PersistableBundle)}} */ - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public int getOui() { return mOui; } @@ -62,7 +64,7 @@ public final class OuiKeyedData implements Parcelable { * * <p>See {@link Builder#Builder(int, PersistableBundle)}} */ - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public @NonNull PersistableBundle getData() { return mData; } @@ -82,7 +84,7 @@ public final class OuiKeyedData implements Parcelable { return validateOui(mOui) && (getData() != null); } - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public boolean equals(@Nullable Object o) { if (this == o) return true; @@ -91,25 +93,25 @@ public final class OuiKeyedData implements Parcelable { return mOui == that.mOui && PersistableBundleUtils.isEqual(mData, that.mData); } - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public int hashCode() { return Objects.hash(mOui, PersistableBundleUtils.getHashCode(mData)); } - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public String toString() { return "{oui=" + Integer.toHexString(mOui) + ", data=" + getData() + "}"; } - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public int describeContents() { return 0; } - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mOui); @@ -122,7 +124,7 @@ public final class OuiKeyedData implements Parcelable { this.mData = in.readPersistableBundle(); } - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @NonNull public static final Parcelable.Creator<OuiKeyedData> CREATOR = new Parcelable.Creator<OuiKeyedData>() { @@ -138,7 +140,7 @@ public final class OuiKeyedData implements Parcelable { }; /** Builder for {@link OuiKeyedData}. */ - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public static final class Builder { private final int mOui; private final @NonNull PersistableBundle mData; @@ -152,14 +154,14 @@ public final class OuiKeyedData implements Parcelable { * should be provided by the vendor, and should be known to both the caller and to the * vendor's implementation of the Wi-Fi HALs. */ - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public Builder(int oui, @NonNull PersistableBundle data) { mOui = oui; mData = data; } /** Construct an OuiKeyedData object with the specified parameters. */ - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @NonNull public OuiKeyedData build() { OuiKeyedData ouiKeyedData = new OuiKeyedData(mOui, mData); diff --git a/framework/java/android/net/wifi/ParcelUtil.java b/framework/java/android/net/wifi/ParcelUtil.java index a26877d9b0..470f8a435a 100644 --- a/framework/java/android/net/wifi/ParcelUtil.java +++ b/framework/java/android/net/wifi/ParcelUtil.java @@ -16,8 +16,11 @@ package android.net.wifi; +import android.annotation.NonNull; import android.os.Parcel; +import com.android.modules.utils.build.SdkLevel; + import java.io.ByteArrayInputStream; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; @@ -28,6 +31,8 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.ArrayList; +import java.util.List; /** * Provides utilities for writing/reading a non-Parcelable objects to/from @@ -162,4 +167,16 @@ public class ParcelUtil { } return certs; } + + /** Read List<OuiKeyedData> from a Parcel. */ + @NonNull + public static List<OuiKeyedData> readOuiKeyedDataList(@NonNull Parcel in) { + List<OuiKeyedData> dataList = new ArrayList<>(); + if (SdkLevel.isAtLeastT()) { + in.readList(dataList, OuiKeyedData.class.getClassLoader(), OuiKeyedData.class); + } else { + in.readList(dataList, OuiKeyedData.class.getClassLoader()); + } + return dataList; + } } diff --git a/framework/java/android/net/wifi/QosCharacteristics.java b/framework/java/android/net/wifi/QosCharacteristics.java new file mode 100644 index 0000000000..210d212418 --- /dev/null +++ b/framework/java/android/net/wifi/QosCharacteristics.java @@ -0,0 +1,726 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import com.android.wifi.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Additional QoS parameters as defined in Section 9.4.2.316 + * of the IEEE P802.11be/D4.0 Standard. + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +public final class QosCharacteristics implements Parcelable { + private static final String TAG = "QosCharacteristics"; + + /** + * Maximum size of an MSDU. + * @hide + */ + public static final int MAX_MSDU_SIZE = 1 << 0; + + /** + * Anticipated time and link ID indicating when traffic starts for the associated TID. + * @hide + */ + public static final int SERVICE_START_TIME = 1 << 1; + + + /** + * Data rate specified for transport of MSDUs or A-MSDUs belonging to the traffic flow. + * @hide + */ + public static final int MEAN_DATA_RATE = 1 << 2; + + /** + * Maximum burst of the MSDUs or A-MSDUs belonging to the traffic flow. + * @hide + */ + public static final int BURST_SIZE = 1 << 3; + + /** + * Maximum amount of time beyond which the MSDU is not useful. + * @hide + */ + public static final int MSDU_LIFETIME = 1 << 4; + + /** + * MSDU delivery information. + * @hide + */ + public static final int MSDU_DELIVERY_INFO = 1 << 5; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = { + MAX_MSDU_SIZE, + SERVICE_START_TIME, + MEAN_DATA_RATE, + BURST_SIZE, + MSDU_LIFETIME, + MSDU_DELIVERY_INFO, + }) + public @interface QosCharacteristicsOptionalField {} + + /** + * Indicates that 95% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_95 = 0; + + /** + * Indicates that 96% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_96 = 1; + + /** + * Indicates that 97% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_97 = 2; + + /** + * Indicates that 98% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_98 = 3; + + /** + * Indicates that 99% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_99 = 5; + + /** + * Indicates that 99.9% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_99_9 = 6; + + /** + * Indicates that 99.99% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_99_99 = 7; + + /** + * Indicates that 99.999% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_99_999 = 8; + + /** + * Indicates that 99.9999% of MSDUs are expected to be delivered. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int DELIVERY_RATIO_99_9999 = 9; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + DELIVERY_RATIO_95, + DELIVERY_RATIO_96, + DELIVERY_RATIO_97, + DELIVERY_RATIO_98, + DELIVERY_RATIO_99, + DELIVERY_RATIO_99_9, + DELIVERY_RATIO_99_99, + DELIVERY_RATIO_99_999, + DELIVERY_RATIO_99_9999, + }) + public @interface DeliveryRatio {} + + private final int mMinServiceIntervalMicros; + private final int mMaxServiceIntervalMicros; + private final int mMinDataRateKbps; + private final int mDelayBoundMicros; + private final int mOptionalFieldBitmap; + private final int mMaxMsduSizeOctets; + private final int mServiceStartTimeMicros; + private final int mServiceStartTimeLinkId; + private final int mMeanDataRateKbps; + private final int mBurstSizeOctets; + private final int mMsduLifetimeMillis; + private final @DeliveryRatio int mDeliveryRatio; + private final int mCountExponent; + + private QosCharacteristics(int minServiceIntervalMicros, int maxServiceIntervalMicros, + int minDataRateKbps, int delayBoundMicros, int optionalFieldBitmap, + int maxMsduSizeOctets, int serviceStartTimeMicros, int serviceStartTimeLinkId, + int meanDataRateKbps, int burstSizeOctets, int msduLifetimeMillis, + @DeliveryRatio int deliveryRatio, int countExponent) { + mMinServiceIntervalMicros = minServiceIntervalMicros; + mMaxServiceIntervalMicros = maxServiceIntervalMicros; + mMinDataRateKbps = minDataRateKbps; + mDelayBoundMicros = delayBoundMicros; + mOptionalFieldBitmap = optionalFieldBitmap; + mMaxMsduSizeOctets = maxMsduSizeOctets; + mServiceStartTimeMicros = serviceStartTimeMicros; + mServiceStartTimeLinkId = serviceStartTimeLinkId; + mMeanDataRateKbps = meanDataRateKbps; + mBurstSizeOctets = burstSizeOctets; + mMsduLifetimeMillis = msduLifetimeMillis; + mDeliveryRatio = deliveryRatio; + mCountExponent = countExponent; + } + + /** + * Check whether this instance contains the indicated optional field. + * @hide + */ + public boolean containsOptionalField(@QosCharacteristicsOptionalField int field) { + return (mOptionalFieldBitmap & field) != 0; + } + + /** + * Check that the value can be cast to an unsigned integer of size |expectedSizeInBits|. + */ + private static boolean checkSizeInBits(int value, int expectedSizeInBits) { + int bitmask = (0x1 << expectedSizeInBits) - 1; + return (bitmask & value) == value; + } + + /** + * Check that the value falls within the provided inclusive range. + */ + private static boolean checkIntRange(int value, int min, int max) { + return (value >= min) && (value <= max); + } + + /** + * Validate the parameters in this instance. + * @hide + */ + public boolean validate() { + if (mMinServiceIntervalMicros <= 0 || mMaxServiceIntervalMicros <= 0 + || mMinDataRateKbps <= 0 || mDelayBoundMicros <= 0) { + Log.e(TAG, "All mandatory fields must be positive integers"); + return false; + } + if (mMinServiceIntervalMicros > mMaxServiceIntervalMicros) { + Log.e(TAG, "Minimum service interval must be less than or equal to" + + " the maximum service interval"); + return false; + } + if (containsOptionalField(MAX_MSDU_SIZE) + && !checkIntRange(mMaxMsduSizeOctets, 1, Short.MAX_VALUE)) { + Log.e(TAG, "Invalid value provided for maxMsduSize"); + return false; + } + if (containsOptionalField(SERVICE_START_TIME) + && (mServiceStartTimeMicros < 0 + || !checkSizeInBits(mServiceStartTimeLinkId, 4))) { + Log.e(TAG, "serviceStartTime information is invalid"); + return false; + } + if (containsOptionalField(MEAN_DATA_RATE) && mMeanDataRateKbps <= 0) { + Log.e(TAG, "meanDataRateKbps must be a positive integer"); + return false; + } + if (containsOptionalField(BURST_SIZE) && mBurstSizeOctets == 0) { + Log.e(TAG, "burstSizeOctets must be non-zero"); + return false; + } + if (containsOptionalField(MSDU_LIFETIME) + && !checkIntRange(mMsduLifetimeMillis, 1, Short.MAX_VALUE)) { + Log.e(TAG, "Invalid value provided for msduLifetimeMillis"); + return false; + } + if (containsOptionalField(MSDU_LIFETIME) + && (mMsduLifetimeMillis * 1000) < mDelayBoundMicros) { + Log.e(TAG, "MSDU lifetime must be greater than or equal to the delay bound"); + return false; + } + if (containsOptionalField(MSDU_DELIVERY_INFO) + && !checkIntRange(mDeliveryRatio, DELIVERY_RATIO_95, DELIVERY_RATIO_99_9999)) { + Log.e(TAG, "MSDU delivery ratio must be a valid enum value"); + return false; + } + if (containsOptionalField(MSDU_DELIVERY_INFO) + && !checkIntRange(mCountExponent, 0, 15)) { + Log.e(TAG, "MSDU count exponent must be between 0 and 15 (inclusive)"); + return false; + } + return true; + } + + /** + * Get the minimum service interval in microseconds. + * + * See {@link Builder#Builder(int, int, int, int)} for more information. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Integer.MAX_VALUE) + public int getMinServiceIntervalMicros() { + return mMinServiceIntervalMicros; + } + + /** + * Get the maximum service interval in microseconds. + * + * See {@link Builder#Builder(int, int, int, int)} for more information. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Integer.MAX_VALUE) + public int getMaxServiceIntervalMicros() { + return mMaxServiceIntervalMicros; + } + + /** + * Get the minimum data rate in kilobits per second. + * + * See {@link Builder#Builder(int, int, int, int)} for more information. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Integer.MAX_VALUE) + public int getMinDataRateKbps() { + return mMinDataRateKbps; + } + + /** + * Get the delay bound in microseconds. + * + * See {@link Builder#Builder(int, int, int, int)} for more information. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Integer.MAX_VALUE) + public int getDelayBoundMicros() { + return mDelayBoundMicros; + } + + /** + * Get the maximum MSDU size in octets. See {@link Builder#setMaxMsduSizeOctets(int)} + * for more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Short.MAX_VALUE) + public int getMaxMsduSizeOctets() { + if (!containsOptionalField(MAX_MSDU_SIZE)) { + throw new IllegalStateException("maxMsduSize was not provided in the builder"); + } + return mMaxMsduSizeOctets; + } + + /** + * Get the service start time in microseconds. + * See {@link Builder#setServiceStartTimeInfo(int, int)} for more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 0, to = Integer.MAX_VALUE) + public int getServiceStartTimeMicros() { + if (!containsOptionalField(SERVICE_START_TIME)) { + throw new IllegalStateException("serviceStartTime was not provided in the builder"); + } + return mServiceStartTimeMicros; + } + + /** + * Get the service start time link ID. See {@link Builder#setServiceStartTimeInfo(int, int)} + * for more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int getServiceStartTimeLinkId() { + if (!containsOptionalField(SERVICE_START_TIME)) { + throw new IllegalStateException("serviceStartTime was not provided in the builder"); + } + return mServiceStartTimeLinkId; + } + + /** + * Get the mean data rate in kilobits per second. See {@link Builder#setMeanDataRateKbps(int)} + * for more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Integer.MAX_VALUE) + public int getMeanDataRateKbps() { + if (!containsOptionalField(MEAN_DATA_RATE)) { + throw new IllegalStateException("meanDataRate was not provided in the builder"); + } + return mMeanDataRateKbps; + } + + /** + * Get the burst size in octets. See {@link Builder#setBurstSizeOctets(int)} for + * more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Integer.MAX_VALUE) + public int getBurstSizeOctets() { + if (!containsOptionalField(BURST_SIZE)) { + throw new IllegalStateException("burstSize was not provided in the builder"); + } + return mBurstSizeOctets; + } + + /** + * Get the MSDU lifetime in milliseconds. See {@link Builder#setMsduLifetimeMillis(int)} + * for more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 1, to = Short.MAX_VALUE) + public int getMsduLifetimeMillis() { + if (!containsOptionalField(MSDU_LIFETIME)) { + throw new IllegalStateException("msduLifetime was not provided in the builder"); + } + return mMsduLifetimeMillis; + } + + /** + * Get the delivery ratio enum. See {@link Builder#setMsduDeliveryInfo(int, int)} for + * more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @DeliveryRatio int getDeliveryRatio() { + if (!containsOptionalField(MSDU_DELIVERY_INFO)) { + throw new IllegalStateException("msduDeliveryInfo was not provided in the builder"); + } + return mDeliveryRatio; + } + + /** + * Get the count exponent. See {@link Builder#setMsduDeliveryInfo(int, int)} for + * more information. + * + * @throws IllegalStateException if this field was not set in the Builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @IntRange(from = 0, to = 15) + public int getCountExponent() { + if (!containsOptionalField(MSDU_DELIVERY_INFO)) { + throw new IllegalStateException("msduDeliveryInfo was not provided in the builder"); + } + return mCountExponent; + } + + @Override + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + QosCharacteristics that = (QosCharacteristics) o; + return mMinServiceIntervalMicros == that.mMinServiceIntervalMicros + && mMaxServiceIntervalMicros == that.mMaxServiceIntervalMicros + && mMinDataRateKbps == that.mMinDataRateKbps + && mDelayBoundMicros == that.mDelayBoundMicros + && mOptionalFieldBitmap == that.mOptionalFieldBitmap + && mMaxMsduSizeOctets == that.mMaxMsduSizeOctets + && mServiceStartTimeMicros == that.mServiceStartTimeMicros + && mServiceStartTimeLinkId == that.mServiceStartTimeLinkId + && mMeanDataRateKbps == that.mMeanDataRateKbps + && mBurstSizeOctets == that.mBurstSizeOctets + && mMsduLifetimeMillis == that.mMsduLifetimeMillis + && mDeliveryRatio == that.mDeliveryRatio + && mCountExponent == that.mCountExponent; + } + + @Override + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int hashCode() { + return Objects.hash(mMinServiceIntervalMicros, mMaxServiceIntervalMicros, mMinDataRateKbps, + mDelayBoundMicros, mOptionalFieldBitmap, mMaxMsduSizeOctets, + mServiceStartTimeMicros, mServiceStartTimeLinkId, mMeanDataRateKbps, + mBurstSizeOctets, mMsduLifetimeMillis, mDeliveryRatio, mCountExponent); + } + + @Override + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public String toString() { + StringBuilder sb = new StringBuilder("{"); + sb.append("mMinServiceIntervalMicros=").append(mMinServiceIntervalMicros); + sb.append(", mMaxServiceIntervalMicros=").append(mMaxServiceIntervalMicros); + sb.append(", mMinDataRateKbps=").append(mMinDataRateKbps); + sb.append(", mDelayBoundMicros=").append(mDelayBoundMicros); + sb.append(", mOptionalFieldBitmap=").append(String.format("%02x", mOptionalFieldBitmap)); + if (containsOptionalField(MAX_MSDU_SIZE)) { + sb.append(", mMaxMsduSizeOctets=").append(mMaxMsduSizeOctets); + } + if (containsOptionalField(SERVICE_START_TIME)) { + sb.append(", mServiceStartTimeMicros=").append(mServiceStartTimeMicros); + sb.append(", mServiceStartTimeLinkId="); + sb.append(String.format("%01x", mServiceStartTimeLinkId)); + } + if (containsOptionalField(MEAN_DATA_RATE)) { + sb.append(", mMeanDataRateKbps=").append(mMeanDataRateKbps); + } + if (containsOptionalField(BURST_SIZE)) { + sb.append(", mBurstSizeOctets=").append(mBurstSizeOctets); + } + if (containsOptionalField(MSDU_LIFETIME)) { + sb.append(", mMsduLifetimeMillis=").append(mMsduLifetimeMillis); + } + if (containsOptionalField(MSDU_DELIVERY_INFO)) { + sb.append(", mDeliveryRatio=").append(mDeliveryRatio); + sb.append(", mCountExponent=").append(mCountExponent); + } + return sb.append("}").toString(); + } + + @Override + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mMinServiceIntervalMicros); + dest.writeInt(mMaxServiceIntervalMicros); + dest.writeInt(mMinDataRateKbps); + dest.writeInt(mDelayBoundMicros); + dest.writeInt(mOptionalFieldBitmap); + dest.writeInt(mMaxMsduSizeOctets); + dest.writeInt(mServiceStartTimeMicros); + dest.writeInt(mServiceStartTimeLinkId); + dest.writeInt(mMeanDataRateKbps); + dest.writeInt(mBurstSizeOctets); + dest.writeInt(mMsduLifetimeMillis); + dest.writeInt(mDeliveryRatio); + dest.writeInt(mCountExponent); + } + + /** @hide */ + QosCharacteristics(@NonNull Parcel in) { + this.mMinServiceIntervalMicros = in.readInt(); + this.mMaxServiceIntervalMicros = in.readInt(); + this.mMinDataRateKbps = in.readInt(); + this.mDelayBoundMicros = in.readInt(); + this.mOptionalFieldBitmap = in.readInt(); + this.mMaxMsduSizeOctets = in.readInt(); + this.mServiceStartTimeMicros = in.readInt(); + this.mServiceStartTimeLinkId = in.readInt(); + this.mMeanDataRateKbps = in.readInt(); + this.mBurstSizeOctets = in.readInt(); + this.mMsduLifetimeMillis = in.readInt(); + this.mDeliveryRatio = in.readInt(); + this.mCountExponent = in.readInt(); + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final @NonNull Parcelable.Creator<QosCharacteristics> CREATOR = + new Parcelable.Creator<QosCharacteristics>() { + @Override + public QosCharacteristics createFromParcel(Parcel in) { + return new QosCharacteristics(in); + } + + @Override + public QosCharacteristics[] newArray(int size) { + return new QosCharacteristics[size]; + } + }; + + /** + * Builder for {@link QosCharacteristics}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final class Builder { + // Mandatory fields + private final int mMinServiceIntervalMicros; + private final int mMaxServiceIntervalMicros; + private final int mMinDataRateKbps; + private final int mDelayBoundMicros; + + // Optional fields + private int mOptionalFieldBitmap; + private int mMaxMsduSizeOctets; + private int mServiceStartTimeMicros; + private int mServiceStartTimeLinkId; + private int mMeanDataRateKbps; + private int mBurstSizeOctets; + private int mMsduLifetimeMillis; + private @DeliveryRatio int mDeliveryRatio; + private int mCountExponent; + + /** + * Constructor for {@link Builder}. + * + * @param minServiceIntervalMicros Positive integer specifying the minimum interval (in + * microseconds) between the start of two consecutive service + * periods (SPs) that are allocated for frame exchanges. + * @param maxServiceIntervalMicros Positive integer specifying the maximum interval (in + * microseconds) between the start of two consecutive SPs that + * are allocated for frame exchanges. + * @param minDataRateKbps Positive integer specifying the lowest data rate (in kilobits/sec) + * for the transport of MSDUs or A-MSDUs belonging to the traffic + * flow. + * @param delayBoundMicros Positive integer specifying the maximum amount of time (in + * microseconds) targeted to transport an MSDU or A-MSDU belonging to + * the traffic flow. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public Builder(@IntRange(from = 1, to = Integer.MAX_VALUE) int minServiceIntervalMicros, + @IntRange(from = 1, to = Integer.MAX_VALUE) int maxServiceIntervalMicros, + @IntRange(from = 1, to = Integer.MAX_VALUE) int minDataRateKbps, + @IntRange(from = 1, to = Integer.MAX_VALUE) int delayBoundMicros) { + mMinServiceIntervalMicros = minServiceIntervalMicros; + mMaxServiceIntervalMicros = maxServiceIntervalMicros; + mMinDataRateKbps = minDataRateKbps; + mDelayBoundMicros = delayBoundMicros; + } + + /** + * Set the maximum MSDU size in octets. + * + * @param maxMsduSizeOctets Positive integer specifying the maximum size (in octets) + * of an MSDU belonging to the traffic flow. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull Builder setMaxMsduSizeOctets( + @IntRange(from = 1, to = Short.MAX_VALUE) int maxMsduSizeOctets) { + mOptionalFieldBitmap |= MAX_MSDU_SIZE; + mMaxMsduSizeOctets = maxMsduSizeOctets; + return this; + } + + /** + * Set the service start time information. + * + * @param serviceStartTimeMicros Integer specifying the anticipated time (in microseconds) + * when the traffic starts for the associated TID. + * @param serviceStartTimeLinkId Bitmap in which the four LSBs indicate the link identifier + * that corresponds to the link for which the TSF timer is + * used to indicate the Service Start Time. No other bits + * should be used. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull Builder setServiceStartTimeInfo( + @IntRange(from = 0, to = Integer.MAX_VALUE) int serviceStartTimeMicros, + int serviceStartTimeLinkId) { + mOptionalFieldBitmap |= SERVICE_START_TIME; + mServiceStartTimeMicros = serviceStartTimeMicros; + mServiceStartTimeLinkId = serviceStartTimeLinkId; + return this; + } + + /** + * Set the mean data rate in kilobits per second. + * + * @param meanDataRateKbps Positive integer indicating the data rate specified (in + * kilobits/sec) for transport of MSDUs or A-MSDUs belonging to the + * traffic flow. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull Builder setMeanDataRateKbps( + @IntRange(from = 1, to = Integer.MAX_VALUE) int meanDataRateKbps) { + mOptionalFieldBitmap |= MEAN_DATA_RATE; + mMeanDataRateKbps = meanDataRateKbps; + return this; + } + + /** + * Set the burst size in octets. + * + * @param burstSizeOctets Positive integer specifying the maximum burst (in octets) of + * the MSDUs or A-MSDUs belonging to the traffic flow that arrive at + * the MAC SAP within any time duration equal to the value specified + * in the |delayBound| field. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull Builder setBurstSizeOctets( + @IntRange(from = 1, to = Integer.MAX_VALUE) int burstSizeOctets) { + mOptionalFieldBitmap |= BURST_SIZE; + mBurstSizeOctets = burstSizeOctets; + return this; + } + + /** + * Set the MSDU lifetime in milliseconds. + * + * @param msduLifetimeMillis Positive integer specifying the maximum amount of time (in + * milliseconds) since the arrival of the MSDU at the MAC data service + * interface beyond which the MSDU is not useful even if received by + * the receiver. The amount of time specified in this field is larger + * than or equal to the amount of time specified in the |delayBound| + * field, if present. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull Builder setMsduLifetimeMillis( + @IntRange(from = 1, to = Short.MAX_VALUE) int msduLifetimeMillis) { + mOptionalFieldBitmap |= MSDU_LIFETIME; + mMsduLifetimeMillis = msduLifetimeMillis; + return this; + } + + /** + * Set the MSDU delivery information. + * + * @param deliveryRatio Enum indicating the percentage of the MSDUs that are expected to be + * delivered successfully. + * @param countExponent Exponent from which the number of incoming MSDUs is computed. The + * number of incoming MSDUs is 10^|countExponent|, and is used to + * determine the MSDU delivery ratio. Must be a number between + * 0 and 15 (inclusive). + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull Builder setMsduDeliveryInfo( + @DeliveryRatio int deliveryRatio, @IntRange(from = 0, to = 15) int countExponent) { + mOptionalFieldBitmap |= MSDU_DELIVERY_INFO; + mDeliveryRatio = deliveryRatio; + mCountExponent = countExponent; + return this; + } + + /** + * Construct a QosCharacteristics object with the specified parameters. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull QosCharacteristics build() { + QosCharacteristics qosCharacteristics = new QosCharacteristics( + mMinServiceIntervalMicros, mMaxServiceIntervalMicros, + mMinDataRateKbps, mDelayBoundMicros, mOptionalFieldBitmap, + mMaxMsduSizeOctets, mServiceStartTimeMicros, mServiceStartTimeLinkId, + mMeanDataRateKbps, mBurstSizeOctets, mMsduLifetimeMillis, + mDeliveryRatio, mCountExponent); + if (!qosCharacteristics.validate()) { + throw new IllegalArgumentException("Provided parameters are invalid"); + } + return qosCharacteristics; + } + } +} diff --git a/framework/java/android/net/wifi/QosPolicyParams.java b/framework/java/android/net/wifi/QosPolicyParams.java index b46abf87e2..29e853bd42 100644 --- a/framework/java/android/net/wifi/QosPolicyParams.java +++ b/framework/java/android/net/wifi/QosPolicyParams.java @@ -16,16 +16,23 @@ package android.net.wifi; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.DscpPolicy; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import androidx.annotation.RequiresApi; + +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.Inet4Address; @@ -229,10 +236,14 @@ public final class QosPolicyParams implements Parcelable { // Flow label. Only applicable to downlink requests using IPv6. private final @Nullable byte[] mFlowLabel; + // QoS characteristics. Mandatory for uplink requests. + private final @Nullable QosCharacteristics mQosCharacteristics; + private QosPolicyParams(int policyId, int dscp, @UserPriority int userPriority, @Nullable InetAddress srcIp, @Nullable InetAddress dstIp, int srcPort, @Protocol int protocol, @Nullable int[] dstPortRange, @Direction int direction, - @IpVersion int ipVersion, int dstPort, @Nullable byte[] flowLabel) { + @IpVersion int ipVersion, int dstPort, @Nullable byte[] flowLabel, + @Nullable QosCharacteristics qosCharacteristics) { this.mPolicyId = policyId; this.mDscp = dscp; this.mUserPriority = userPriority; @@ -245,6 +256,7 @@ public final class QosPolicyParams implements Parcelable { this.mDirection = direction; this.mIpVersion = ipVersion; this.mFlowLabel = flowLabel; + this.mQosCharacteristics = qosCharacteristics; } /** @@ -309,11 +321,15 @@ public final class QosPolicyParams implements Parcelable { return false; } } + if (mQosCharacteristics != null && !mQosCharacteristics.validate()) { + Log.e(TAG, "Invalid QoS characteristics provided"); + return false; + } // Check required parameters based on direction. if (mDirection == DIRECTION_UPLINK) { - if (mDscp == DSCP_ANY) { - Log.e(TAG, "DSCP must be provided for uplink requests"); + if (mQosCharacteristics == null) { + Log.e(TAG, "QoS characteristics must be provided for uplink requests"); return false; } if (mIpVersion != IP_VERSION_ANY) { @@ -509,6 +525,22 @@ public final class QosPolicyParams implements Parcelable { return mFlowLabel; } + /** + * Get the QoS characteristics for this policy. + * + * See {@link Builder#setQosCharacteristics(QosCharacteristics)} for more information. + * + * @return QoS characteristics object, or null if not assigned. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @Nullable QosCharacteristics getQosCharacteristics() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mQosCharacteristics; + } + @Override public boolean equals(@Nullable Object o) { if (this == o) return true; @@ -525,14 +557,15 @@ public final class QosPolicyParams implements Parcelable { && Arrays.equals(mDstPortRange, that.mDstPortRange) && mDirection == that.mDirection && mIpVersion == that.mIpVersion - && mFlowLabel == that.mFlowLabel; + && mFlowLabel == that.mFlowLabel + && Objects.equals(mQosCharacteristics, that.mQosCharacteristics); } @Override public int hashCode() { return Objects.hash(mPolicyId, mDscp, mUserPriority, mSrcIp, mDstIp, mSrcPort, mProtocol, Arrays.hashCode(mDstPortRange), mDirection, mIpVersion, mDstPort, - Arrays.hashCode(mFlowLabel)); + Arrays.hashCode(mFlowLabel), mQosCharacteristics); } @Override @@ -548,7 +581,8 @@ public final class QosPolicyParams implements Parcelable { + "dstPortRange=" + Arrays.toString(mDstPortRange) + ", " + "direction=" + mDirection + ", " + "ipVersion=" + mIpVersion + ", " - + "flowLabel=" + Arrays.toString(mFlowLabel) + "}"; + + "flowLabel=" + Arrays.toString(mFlowLabel) + ", " + + "qosCharacteristics=" + mQosCharacteristics + "}"; } /** @hide */ @@ -581,6 +615,9 @@ public final class QosPolicyParams implements Parcelable { dest.writeInt(mDirection); dest.writeInt(mIpVersion); dest.writeByteArray(mFlowLabel); + if (SdkLevel.isAtLeastV()) { + dest.writeParcelable(mQosCharacteristics, 0); + } } /** @hide */ @@ -597,6 +634,12 @@ public final class QosPolicyParams implements Parcelable { this.mDirection = in.readInt(); this.mIpVersion = in.readInt(); this.mFlowLabel = in.createByteArray(); + if (SdkLevel.isAtLeastV()) { + this.mQosCharacteristics = in.readParcelable( + QosCharacteristics.class.getClassLoader(), QosCharacteristics.class); + } else { + this.mQosCharacteristics = null; + } } public static final @NonNull Parcelable.Creator<QosPolicyParams> CREATOR = @@ -628,6 +671,7 @@ public final class QosPolicyParams implements Parcelable { private @Nullable int[] mDstPortRange; private @IpVersion int mIpVersion = IP_VERSION_ANY; private byte[] mFlowLabel; + private @Nullable QosCharacteristics mQosCharacteristics; /** * Constructor for {@link Builder}. @@ -737,12 +781,27 @@ public final class QosPolicyParams implements Parcelable { } /** + * Specifies traffic flow parameters to use for this policy request. + * This argument is mandatory for uplink requests, but optional for downlink requests. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public @NonNull Builder setQosCharacteristics( + @Nullable QosCharacteristics qosCharacteristics) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + mQosCharacteristics = qosCharacteristics; + return this; + } + + /** * Construct a QosPolicyParams object with the specified parameters. */ public @NonNull QosPolicyParams build() { QosPolicyParams params = new QosPolicyParams(mPolicyId, mDscp, mUserPriority, mSrcIp, mDstIp, mSrcPort, mProtocol, mDstPortRange, mDirection, mIpVersion, mDstPort, - mFlowLabel); + mFlowLabel, mQosCharacteristics); if (!params.validate()) { throw new IllegalArgumentException("Provided parameters are invalid"); } diff --git a/framework/java/android/net/wifi/ScanResult.java b/framework/java/android/net/wifi/ScanResult.java index 1eb35e4c9c..161928fac2 100644 --- a/framework/java/android/net/wifi/ScanResult.java +++ b/framework/java/android/net/wifi/ScanResult.java @@ -16,6 +16,7 @@ package android.net.wifi; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -32,6 +33,7 @@ import android.os.Parcelable; import android.util.Log; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -729,6 +731,11 @@ public final class ScanResult implements Parcelable { /** {@hide} */ public static final long FLAG_80211mc_RESPONDER = 0x0000000000000002; + /** @hide */ + public static final long FLAG_80211az_NTB_RESPONDER = 0x0000000000000004; + + /** @hide */ + public static final long FLAG_TWT_RESPONDER = 0x0000000000000008; /* * These flags are specific to the ScanResult class, and are not related to the |flags| * field of the per-BSS scan results from WPA supplicant. @@ -762,11 +769,27 @@ public final class ScanResult implements Parcelable { return (flags & FLAG_80211mc_RESPONDER) != 0; } + /** + * @return whether AP is a IEEE802.11az Non-Trigger based Ranging Responder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean is80211azNtbResponder() { + return (flags & FLAG_80211az_NTB_RESPONDER) != 0; + } + public boolean isPasspointNetwork() { return (flags & FLAG_PASSPOINT_NETWORK) != 0; } /** + * @return whether AP is Target Wake Time (TWT) Responder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean isTwtResponder() { + return (flags & FLAG_TWT_RESPONDER) != 0; + } + + /** * Indicates venue name (such as 'San Francisco Airport') published by access point; only * available on Passpoint network and if published by access point. * @deprecated - This information is not provided @@ -1410,7 +1433,235 @@ public final class ScanResult implements Parcelable { return true; } - /** {@hide} */ + /** + * Builder class used to construct {@link ScanResult} objects. + * + * @hide + */ + public static final class Builder { + private WifiSsid mWifiSsid; + private String mBssid; + private long mHessid = 0; + private int mAnqpDomainId = 0; + private byte[] mOsuProviders = null; + private String mCaps = null; + private int mRssi = UNSPECIFIED; + private int mFrequency = UNSPECIFIED; + private long mTsf = 0; + private int mDistanceCm = UNSPECIFIED; + private int mDistanceSdCm = UNSPECIFIED; + private @ChannelWidth int mChannelWidth = ScanResult.CHANNEL_WIDTH_20MHZ; + private int mCenterFreq0 = UNSPECIFIED; + private int mCenterFreq1 = UNSPECIFIED; + private boolean mIs80211McRTTResponder = false; + private boolean mIs80211azNtbRTTResponder = false; + private boolean mIsTwtResponder = false; + /** @hide */ + @NonNull + public Builder setHessid(long hessid) { + mHessid = hessid; + return this; + } + + /** @hide */ + @NonNull + public Builder setOsuProviders(@Nullable byte[] osuProviders) { + mOsuProviders = osuProviders; + return this; + } + + /** @hide */ + @NonNull + public Builder setAnqpDomainId(int anqpDomainId) { + mAnqpDomainId = anqpDomainId; + return this; + } + + /** @hide */ + @NonNull + public Builder setCaps(@Nullable String caps) { + mCaps = caps; + return this; + } + + /** @hide */ + @NonNull + public Builder setRssi(int rssi) { + mRssi = rssi; + return this; + } + + /** @hide */ + @NonNull + public Builder setFrequency(int frequency) { + mFrequency = frequency; + return this; + } + + /** @hide */ + @NonNull + public Builder setTsf(long tsf) { + mTsf = tsf; + return this; + } + + /** @hide */ + @NonNull + public Builder setDistanceCm(int distanceCm) { + mDistanceCm = distanceCm; + return this; + } + + /** @hide */ + @NonNull + public Builder setDistanceSdCm(int distanceSdCm) { + mDistanceSdCm = distanceSdCm; + return this; + } + + /** @hide */ + @NonNull + public Builder setChannelWidth(@ChannelWidth int channelWidth) { + mChannelWidth = channelWidth; + return this; + } + + /** @hide */ + @NonNull + public Builder setCenterFreq0(int centerFreq0) { + mCenterFreq0 = centerFreq0; + return this; + } + + /** @hide */ + @NonNull + public Builder setCenterFreq1(int centerFreq1) { + mCenterFreq1 = centerFreq1; + return this; + } + + /** @hide */ + @NonNull + public Builder setIs80211McRTTResponder(boolean is80211McRTTResponder) { + mIs80211McRTTResponder = is80211McRTTResponder; + return this; + } + + /** @hide */ + @NonNull + public Builder setIs80211azNtbRTTResponder(boolean is80211azNtbRTTResponder) { + mIs80211azNtbRTTResponder = is80211azNtbRTTResponder; + return this; + } + + /** @hide */ + @NonNull + public Builder setIsTwtResponder(boolean isTwtResponder) { + mIsTwtResponder = isTwtResponder; + return this; + } + + /** @hide */ + public Builder(WifiSsid wifiSsid, String bssid) { + mWifiSsid = wifiSsid; + mBssid = bssid; + } + + /** + * @hide + * + */ + public Builder() { + + } + + /** + * @hide + */ + public Builder setWifiSsid(WifiSsid wifiSsid) { + mWifiSsid = wifiSsid; + return this; + } + + /** + * @hide + */ + public Builder setBssid(String bssid) { + mBssid = bssid; + return this; + } + + /** + * @hide + */ + public void clear() { + mWifiSsid = null; + mBssid = null; + mHessid = 0; + mAnqpDomainId = 0; + mOsuProviders = null; + mCaps = null; + mRssi = UNSPECIFIED; + mFrequency = UNSPECIFIED; + mTsf = 0; + mDistanceCm = UNSPECIFIED; + mDistanceSdCm = UNSPECIFIED; + mChannelWidth = ScanResult.CHANNEL_WIDTH_20MHZ; + mCenterFreq0 = UNSPECIFIED; + mCenterFreq1 = UNSPECIFIED; + mIs80211McRTTResponder = false; + mIs80211azNtbRTTResponder = false; + mIsTwtResponder = false; + } + + /** @hide */ + public ScanResult build() { + return new ScanResult(this); + } + } + + /** + * @hide + */ + private ScanResult(Builder builder) { + this.wifiSsid = builder.mWifiSsid; + if (wifiSsid != null && isHiddenSsid(wifiSsid)) { + // Retain the legacy behavior of setting SSID to "" if the SSID is all zero values. + this.SSID = ""; + } else { + final CharSequence utf8Ssid = (wifiSsid != null) ? wifiSsid.getUtf8Text() : null; + this.SSID = (utf8Ssid != null) ? utf8Ssid.toString() : WifiManager.UNKNOWN_SSID; + } + this.BSSID = builder.mBssid; + this.hessid = builder.mHessid; + this.anqpDomainId = builder.mAnqpDomainId; + if (builder.mOsuProviders != null) { + this.anqpElements = new AnqpInformationElement[1]; + this.anqpElements[0] = new AnqpInformationElement( + AnqpInformationElement.HOTSPOT20_VENDOR_ID, + AnqpInformationElement.HS_OSU_PROVIDERS, builder.mOsuProviders); + } + this.capabilities = builder.mCaps; + this.level = builder.mRssi; + this.frequency = builder.mFrequency; + this.timestamp = builder.mTsf; + this.distanceCm = builder.mDistanceCm; + this.distanceSdCm = builder.mDistanceSdCm; + this.channelWidth = builder.mChannelWidth; + this.centerFreq0 = builder.mCenterFreq0; + this.centerFreq1 = builder.mCenterFreq1; + this.flags = 0; + this.flags |= (builder.mIs80211McRTTResponder) ? FLAG_80211mc_RESPONDER : 0; + this.flags |= (builder.mIs80211azNtbRTTResponder) ? FLAG_80211az_NTB_RESPONDER : 0; + this.flags |= (builder.mIsTwtResponder) ? FLAG_TWT_RESPONDER : 0; + this.radioChainInfos = null; + this.mApMldMacAddress = null; + } + + /** + * @hide + * @deprecated Use {@link ScanResult.Builder} + */ public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId, byte[] osuProviders, String caps, int level, int frequency, long tsf) { this.wifiSsid = wifiSsid; @@ -1444,7 +1695,10 @@ public final class ScanResult implements Parcelable { this.mApMldMacAddress = null; } - /** {@hide} */ + /** + * @hide + * @deprecated Use {@link ScanResult.Builder} + */ public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, long tsf, int distCm, int distSdCm) { this.wifiSsid = wifiSsid; @@ -1470,7 +1724,10 @@ public final class ScanResult implements Parcelable { this.mApMldMacAddress = null; } - /** {@hide} */ + /** + * @hide + * @deprecated Use {@link ScanResult.Builder} + */ public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, @@ -1497,7 +1754,10 @@ public final class ScanResult implements Parcelable { this.mApMldMacAddress = null; } - /** {@hide} */ + /** + * @hide + * @deprecated Use {@link ScanResult.Builder} + */ public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, @@ -1576,6 +1836,11 @@ public final class ScanResult implements Parcelable { sb.append(", standard: ").append(wifiStandardToString(mWifiStandard)); sb.append(", 80211mcResponder: "); sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported"); + sb.append(", 80211azNtbResponder: "); + sb.append( + ((flags & FLAG_80211az_NTB_RESPONDER) != 0) ? "is supported" : "is not supported"); + sb.append(", TWT Responder: "); + sb.append(((flags & FLAG_TWT_RESPONDER) != 0) ? "yes" : "no"); sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos)); sb.append(", interface name: ").append(ifaceName); @@ -1683,80 +1948,78 @@ public final class ScanResult implements Parcelable { /** Implement the Parcelable interface */ public static final @NonNull Creator<ScanResult> CREATOR = - new Creator<ScanResult>() { - public ScanResult createFromParcel(Parcel in) { - WifiSsid wifiSsid = null; - if (in.readInt() == 1) { - wifiSsid = WifiSsid.CREATOR.createFromParcel(in); - } - ScanResult sr = new ScanResult( - wifiSsid, - in.readString(), /* SSID */ - in.readString(), /* BSSID */ - in.readLong(), /* HESSID */ - in.readInt(), /* ANQP Domain ID */ - in.readString(), /* capabilities */ - in.readInt(), /* level */ - in.readInt(), /* frequency */ - in.readLong(), /* timestamp */ - in.readInt(), /* distanceCm */ - in.readInt(), /* distanceSdCm */ - in.readInt(), /* channelWidth */ - in.readInt(), /* centerFreq0 */ - in.readInt(), /* centerFreq1 */ - false /* rtt responder, + new Creator<ScanResult>() { + public ScanResult createFromParcel(Parcel in) { + WifiSsid wifiSsid = null; + if (in.readInt() == 1) { + wifiSsid = WifiSsid.CREATOR.createFromParcel(in); + } + ScanResult sr = new ScanResult( + wifiSsid, + in.readString(), /* SSID */ + in.readString(), /* BSSID */ + in.readLong(), /* HESSID */ + in.readInt(), /* ANQP Domain ID */ + in.readString(), /* capabilities */ + in.readInt(), /* level */ + in.readInt(), /* frequency */ + in.readLong(), /* timestamp */ + in.readInt(), /* distanceCm */ + in.readInt(), /* distanceSdCm */ + in.readInt(), /* channelWidth */ + in.readInt(), /* centerFreq0 */ + in.readInt(), /* centerFreq1 */ + false /* rtt responder, fixed with flags below */ - ); - - sr.mWifiStandard = in.readInt(); - sr.seen = in.readLong(); - sr.untrusted = in.readInt() != 0; - sr.numUsage = in.readInt(); - sr.venueName = in.readString(); - sr.operatorFriendlyName = in.readString(); - sr.flags = in.readLong(); - sr.informationElements = in.createTypedArray(InformationElement.CREATOR); - - int n = in.readInt(); - if (n != 0) { - sr.anqpLines = new ArrayList<String>(); - for (int i = 0; i < n; i++) { - sr.anqpLines.add(in.readString()); + ); + + sr.mWifiStandard = in.readInt(); + sr.seen = in.readLong(); + sr.untrusted = in.readInt() != 0; + sr.numUsage = in.readInt(); + sr.venueName = in.readString(); + sr.operatorFriendlyName = in.readString(); + sr.flags = in.readLong(); + sr.informationElements = in.createTypedArray(InformationElement.CREATOR); + + int n = in.readInt(); + if (n != 0) { + sr.anqpLines = new ArrayList<String>(); + for (int i = 0; i < n; i++) { + sr.anqpLines.add(in.readString()); + } } - } - n = in.readInt(); - if (n != 0) { - sr.anqpElements = new AnqpInformationElement[n]; - for (int i = 0; i < n; i++) { - int vendorId = in.readInt(); - int elementId = in.readInt(); - int len = in.readInt(); - byte[] payload = new byte[len]; - in.readByteArray(payload); - sr.anqpElements[i] = - new AnqpInformationElement(vendorId, elementId, payload); + n = in.readInt(); + if (n != 0) { + sr.anqpElements = new AnqpInformationElement[n]; + for (int i = 0; i < n; i++) { + int vendorId = in.readInt(); + int elementId = in.readInt(); + int len = in.readInt(); + byte[] payload = new byte[len]; + in.readByteArray(payload); + sr.anqpElements[i] = + new AnqpInformationElement(vendorId, elementId, payload); + } } - } - n = in.readInt(); - if (n != 0) { - sr.radioChainInfos = new RadioChainInfo[n]; - for (int i = 0; i < n; i++) { - sr.radioChainInfos[i] = new RadioChainInfo(); - sr.radioChainInfos[i].id = in.readInt(); - sr.radioChainInfos[i].level = in.readInt(); + n = in.readInt(); + if (n != 0) { + sr.radioChainInfos = new RadioChainInfo[n]; + for (int i = 0; i < n; i++) { + sr.radioChainInfos[i] = new RadioChainInfo(); + sr.radioChainInfos[i].id = in.readInt(); + sr.radioChainInfos[i].level = in.readInt(); + } } - } - sr.ifaceName = in.readString(); + sr.ifaceName = in.readString(); + // Read MLO related attributes + sr.mApMldMacAddress = in.readParcelable(MacAddress.class.getClassLoader()); + sr.mApMloLinkId = in.readInt(); + sr.mAffiliatedMloLinks = in.createTypedArrayList(MloLink.CREATOR); - // Read MLO related attributes - sr.mApMldMacAddress = in.readParcelable(MacAddress.class.getClassLoader()); - sr.mApMloLinkId = in.readInt(); - sr.mAffiliatedMloLinks = in.createTypedArrayList(MloLink.CREATOR); - - return sr; - } - + return sr; + } public ScanResult[] newArray(int size) { return new ScanResult[size]; } diff --git a/framework/java/android/net/wifi/SoftApConfiguration.java b/framework/java/android/net/wifi/SoftApConfiguration.java index dde9891d9d..5432484b6a 100644 --- a/framework/java/android/net/wifi/SoftApConfiguration.java +++ b/framework/java/android/net/wifi/SoftApConfiguration.java @@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.util.Preconditions; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1206,7 +1207,7 @@ public final class SoftApConfiguration implements Parcelable { * @hide */ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @NonNull @SystemApi public List<OuiKeyedData> getVendorData() { @@ -2312,7 +2313,7 @@ public final class SoftApConfiguration implements Parcelable { * @return Builder for chaining. */ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) - @FlaggedApi("com.android.wifi.flags.vendor_parcelable_parameters") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @NonNull public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { if (!SdkLevel.isAtLeastV()) { diff --git a/framework/java/android/net/wifi/SoftApInfo.java b/framework/java/android/net/wifi/SoftApInfo.java index 89d4782ff9..f4440e9e74 100644 --- a/framework/java/android/net/wifi/SoftApInfo.java +++ b/framework/java/android/net/wifi/SoftApInfo.java @@ -16,6 +16,7 @@ package android.net.wifi; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -28,11 +29,17 @@ import androidx.annotation.RequiresApi; import com.android.internal.util.Preconditions; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; /** - * A class representing information about SoftAp. + * A class representing information about a specific SoftAP instance. A SoftAP instance may be a + * single band AP or a bridged AP (across multiple bands). To get the state of the AP interface + * itself, use {@link android.net.wifi.WifiManager.SoftApCallback#onStateChanged(SoftApState)}. * {@see WifiManager} * * @hide @@ -156,6 +163,9 @@ public final class SoftApInfo implements Parcelable { */ private long mIdleShutdownTimeoutMillis; + /** List of {@link OuiKeyedData} containing vendor-specific configuration data. */ + private List<OuiKeyedData> mVendorData = Collections.emptyList(); + /** * Get the frequency which AP resides on. */ @@ -307,6 +317,44 @@ public final class SoftApInfo implements Parcelable { } /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = new ArrayList<>(vendorData); + } + + /** + * Get the vendor-provided configuration data, if it exists. + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + + /** * @hide */ public SoftApInfo(@Nullable SoftApInfo source) { @@ -317,6 +365,7 @@ public final class SoftApInfo implements Parcelable { mWifiStandard = source.mWifiStandard; mApInstanceIdentifier = source.mApInstanceIdentifier; mIdleShutdownTimeoutMillis = source.mIdleShutdownTimeoutMillis; + mVendorData = new ArrayList<>(source.mVendorData); } } @@ -341,6 +390,7 @@ public final class SoftApInfo implements Parcelable { dest.writeInt(mWifiStandard); dest.writeString(mApInstanceIdentifier); dest.writeLong(mIdleShutdownTimeoutMillis); + dest.writeList(mVendorData); } @NonNull @@ -354,6 +404,7 @@ public final class SoftApInfo implements Parcelable { info.mWifiStandard = in.readInt(); info.mApInstanceIdentifier = in.readString(); info.mIdleShutdownTimeoutMillis = in.readLong(); + info.mVendorData = ParcelUtil.readOuiKeyedDataList(in); return info; } @@ -373,6 +424,7 @@ public final class SoftApInfo implements Parcelable { sbuf.append(", wifiStandard= ").append(mWifiStandard); sbuf.append(", mApInstanceIdentifier= ").append(mApInstanceIdentifier); sbuf.append(", mIdleShutdownTimeoutMillis= ").append(mIdleShutdownTimeoutMillis); + sbuf.append(", mVendorData= ").append(mVendorData); sbuf.append("}"); return sbuf.toString(); } @@ -387,12 +439,13 @@ public final class SoftApInfo implements Parcelable { && Objects.equals(mBssid, softApInfo.mBssid) && mWifiStandard == softApInfo.mWifiStandard && Objects.equals(mApInstanceIdentifier, softApInfo.mApInstanceIdentifier) - && mIdleShutdownTimeoutMillis == softApInfo.mIdleShutdownTimeoutMillis; + && mIdleShutdownTimeoutMillis == softApInfo.mIdleShutdownTimeoutMillis + && Objects.equals(mVendorData, softApInfo.mVendorData); } @Override public int hashCode() { return Objects.hash(mFrequency, mBandwidth, mBssid, mWifiStandard, mApInstanceIdentifier, - mIdleShutdownTimeoutMillis); + mIdleShutdownTimeoutMillis, mVendorData); } } diff --git a/framework/java/android/net/wifi/SoftApState.aidl b/framework/java/android/net/wifi/SoftApState.aidl new file mode 100644 index 0000000000..61a27f1be9 --- /dev/null +++ b/framework/java/android/net/wifi/SoftApState.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import android.net.wifi.SoftApState; + +parcelable SoftApState; diff --git a/framework/java/android/net/wifi/SoftApState.java b/framework/java/android/net/wifi/SoftApState.java index 54dc45cc59..07e194c234 100644 --- a/framework/java/android/net/wifi/SoftApState.java +++ b/framework/java/android/net/wifi/SoftApState.java @@ -25,6 +25,7 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.util.Objects; @@ -34,19 +35,32 @@ import java.util.Objects; * * @hide */ +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi -@FlaggedApi("com.android.wifi.flags.android_v_wifi_api") public final class SoftApState implements Parcelable { + @WifiManager.WifiApState final int mState; + @WifiManager.SapStartFailure final int mFailureReason; + @Nullable final TetheringManager.TetheringRequest mTetheringRequest; + @Nullable final String mIface; /** + * SoftApState constructor. + * + * @param state Current state of the Soft AP. + * @param failureReason Failure reason if the current state is + * {@link WifiManager#WIFI_AP_STATE_FAILED}. + * @param tetheringRequest TetheringRequest if one was specified when Soft AP was requested, + * else {@code null}. + * @param iface Interface name if an interface was created, else {@code null}. * @hide */ - public SoftApState(int state, int failureReason, + public SoftApState(@WifiManager.WifiApState int state, + @WifiManager.SapStartFailure int failureReason, @Nullable TetheringManager.TetheringRequest tetheringRequest, @Nullable String iface) { mState = state; @@ -108,7 +122,8 @@ public final class SoftApState implements Parcelable { * {@link WifiManager#WIFI_AP_STATE_ENABLING}, * {@link WifiManager#WIFI_AP_STATE_FAILED} */ - public @WifiManager.WifiApState int getState() { + @WifiManager.WifiApState + public int getState() { return mState; } @@ -119,13 +134,29 @@ public final class SoftApState implements Parcelable { * {@link WifiManager#SAP_START_FAILURE_NO_CHANNEL}, * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}, * {@link WifiManager#SAP_START_FAILURE_USER_REJECTED} + * @throws IllegalStateException if the state is not {@link WifiManager#WIFI_AP_STATE_FAILED}. + */ + @WifiManager.SapStartFailure + public int getFailureReason() { + if (mState != WifiManager.WIFI_AP_STATE_FAILED) { + throw new IllegalStateException("Called getFailureReason() when state is not" + + " WIFI_AP_STATE_FAILED. Actual state is " + mState); + } + return getFailureReasonInternal(); + } + + /** + * @hide */ - public @WifiManager.SapStartFailure int getFailureReason() { + @WifiManager.SapStartFailure + public int getFailureReasonInternal() { return mFailureReason; } /** - * Gets the TetheringRequest of the Soft AP. + * Gets the TetheringRequest of the Soft AP, if one was specified via + * {@link WifiManager#startTetheredHotspotRequest(TetheringManager.TetheringRequest)}. + * Otherwise, returns {@code null}. */ @Nullable public TetheringManager.TetheringRequest getTetheringRequest() { @@ -133,7 +164,10 @@ public final class SoftApState implements Parcelable { } /** - * Gets the iface of the Soft AP. + * Gets the interface name of the Soft AP (e.g. "wlan0") once the Soft AP starts enabling, i.e. + * {@link #getState()} returns {@link WifiManager#WIFI_AP_STATE_ENABLING}). Returns {@code null} + * if the Soft AP hasn't started enabling yet, or if it failed with + * {@link WifiManager#WIFI_AP_STATE_FAILED} without starting enabling. */ @Nullable public String getIface() { diff --git a/framework/java/android/net/wifi/UriParserResults.java b/framework/java/android/net/wifi/UriParserResults.java new file mode 100644 index 0000000000..75086c840e --- /dev/null +++ b/framework/java/android/net/wifi/UriParserResults.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.wifi.flags.Flags; + +import java.util.Objects; + +/** + * Contains information extracted from URI + * + * @hide + */ +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +@SystemApi +public final class UriParserResults implements Parcelable { + + /** + * Return value for {@link #getUriScheme()} indicating that the URI contains + * a ZXing WiFi configuration. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG = 1; + + /** + * Return value for {@link #getUriScheme()} indicating that the URI contains + * a DPP (Easy Connect) configuration. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int URI_SCHEME_DPP = 2; + + /** + * URI_SCHEME_DPP for standard Wi-Fi device provision protocol; + * URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG for ZXing reader library's Wi-Fi Network config format. + */ + @WifiAnnotations.UriScheme private int mScheme; + + /** Public key from parsed Wi-Fi DPP URI, it is valid when mScheme is URI_SCHEME_DPP. */ + @Nullable private String mPublicKey; + + /** + * Optional device specific information from the Wi-Fi DPP URI, + * it is valid when mScheme is URI_SCHEME_DPP + */ + @Nullable private String mInformation; + + /** + * WifiConfiguration from parsed ZXing reader library's Wi-Fi Network config format. Valid or + * Not null when mScheme is URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG + */ + @Nullable private WifiConfiguration mWifiConfig; + + /** @hide */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public UriParserResults( + int scheme, + @Nullable String publicKey, + @Nullable String information, + @Nullable WifiConfiguration config) { + mScheme = scheme; + mPublicKey = publicKey; + mInformation = information; + if (config != null) { + mWifiConfig = new WifiConfiguration(config); + } + } + + /** + * The scheme described by the URI. + * + * <p>URI_SCHEME_DPP for standard Wi-Fi device provision protocol. + * URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG for ZXing reader library's Wi-Fi Network config format. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @WifiAnnotations.UriScheme + public int getUriScheme() { + return mScheme; + } + + /** + * The public key of the DPP (Wi-Fi Easy Connect). + * + * If {@code getUriScheme()} returns URI_SCHEME_DPP, this field contains the public key + * of the DPP (Wi-Fi Easy Connect). Otherwise, it is null. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Nullable + public String getPublicKey() { + return mPublicKey; + } + + /** + * The information of the DPP (Wi-Fi Easy Connect). + * + * If {@code getUriScheme()} returns URI_SCHEME_DPP, this field contains the information + * of the DPP (Wi-Fi Easy Connect). Otherwise, it is null. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Nullable + public String getInformation() { + return mInformation; + } + + /** + * The WifiConfiguration of the zxing wifi network. + * + * If {@code getUriScheme()} returns URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG, this field contains + * the WifiConfiguration of the zxing wifi network. Otherwise, it is null. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Nullable + public WifiConfiguration getWifiConfiguration() { + return mWifiConfig; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + /** + * Implement the Parcelable interface. + */ + public int describeContents() { + return 0; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + /** + * Implement the Parcelable interface. + */ + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mScheme); + dest.writeString(mPublicKey); + dest.writeString(mInformation); + dest.writeParcelable(mWifiConfig, flags); + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + /** + * Implement the Parcelable interface. + */ + public static final Creator<UriParserResults> CREATOR = + new Creator<UriParserResults>() { + public UriParserResults createFromParcel(Parcel in) { + return new UriParserResults( + in.readInt(), + in.readString(), + in.readString(), + in.readParcelable(WifiConfiguration.class.getClassLoader())); + } + + public UriParserResults[] newArray(int size) { + return new UriParserResults[size]; + } + }; + + @NonNull + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append("UriParserResults{"); + sbuf.append(", mScheme= ").append(mScheme); + sbuf.append(", mPublicKey= ").append(mPublicKey); + sbuf.append(", mInformation= ").append(mInformation); + if (mWifiConfig != null) sbuf.append(", mWifiConfig=").append(mWifiConfig.toString()); + sbuf.append("}"); + return sbuf.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UriParserResults)) return false; + UriParserResults results = (UriParserResults) o; + return mScheme == results.mScheme + && Objects.equals(mPublicKey, results.mPublicKey) + && Objects.equals(mInformation, results.mInformation) + && Objects.equals( + mWifiConfig != null ? mWifiConfig.toString() : null, + results.mWifiConfig != null ? results.mWifiConfig.toString() : null); + } + + @Override + public int hashCode() { + return Objects.hash( + mScheme, + mPublicKey, + mInformation, + mWifiConfig != null ? mWifiConfig.toString() : null); + } +} diff --git a/framework/java/android/net/wifi/WifiAnnotations.java b/framework/java/android/net/wifi/WifiAnnotations.java index 602226da4a..2a92c31361 100644 --- a/framework/java/android/net/wifi/WifiAnnotations.java +++ b/framework/java/android/net/wifi/WifiAnnotations.java @@ -166,4 +166,14 @@ public final class WifiAnnotations { WifiInfo.SECURITY_TYPE_DPP, }) public @interface SecurityType {} + + /** + * The type of wifi uri scheme. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"URI_SCHEME_"}, value = { + UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG, + UriParserResults.URI_SCHEME_DPP, + }) + public @interface UriScheme {} } diff --git a/framework/java/android/net/wifi/WifiConfiguration.java b/framework/java/android/net/wifi/WifiConfiguration.java index 0b63780ca2..88582dde76 100644 --- a/framework/java/android/net/wifi/WifiConfiguration.java +++ b/framework/java/android/net/wifi/WifiConfiguration.java @@ -45,9 +45,12 @@ import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; +import androidx.annotation.RequiresApi; + import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.MacAddressUtils; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -62,6 +65,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -1192,9 +1196,8 @@ public class WifiConfiguration implements Parcelable { /** * Four WEP keys. For each of the four values, provide either an ASCII - * string enclosed in double quotation marks (e.g., {@code "abcdef"}), - * a string of hex digits (e.g., {@code 0102030405}), or an empty string - * (e.g., {@code ""}). + * string enclosed in double quotation marks (e.g., {@code "abcdef"}) + * or a string of hex digits (e.g., {@code 0102030405}). * <p/> * When the value of one of these keys is read, the actual key is * not returned, just a "*" if the key has a value, or the null @@ -1474,6 +1477,12 @@ public class WifiConfiguration implements Parcelable { public boolean allowAutojoin = true; /** + * Wi-Fi7 is enabled by user for this network. + * Default true. + */ + private boolean mWifi7Enabled = true; + + /** * @hide */ public void setIpProvisioningTimedOut(boolean value) { @@ -1972,6 +1981,34 @@ public class WifiConfiguration implements Parcelable { mRandomizedMacAddress = mac; } + private boolean mIsSendDhcpHostnameEnabled = true; + + /** + * Set whether to send the hostname of the device to this network's DHCP server. + * + * @param enabled {@code true} to send the hostname during DHCP, + * {@code false} to not send the hostname during DHCP. + * @hide + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD}) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void setSendDhcpHostnameEnabled(boolean enabled) { + mIsSendDhcpHostnameEnabled = enabled; + } + + /** + * Whether to send the hostname of the device to this network's DHCP server. + * @hide + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public boolean isSendDhcpHostnameEnabled() { + return mIsSendDhcpHostnameEnabled; + } + /** * This network supports DPP AKM and the device is configured to * onboard peer enrollee devices with {@link #SECURITY_TYPE_DPP} @@ -2150,7 +2187,8 @@ public class WifiConfiguration implements Parcelable { DISABLED_AUTHENTICATION_PRIVATE_EAP_ERROR, DISABLED_NETWORK_NOT_FOUND, DISABLED_CONSECUTIVE_FAILURES, - DISABLED_UNWANTED_LOW_RSSI}) + DISABLED_UNWANTED_LOW_RSSI, + DISABLED_REPEATED_NUD_FAILURES}) public @interface NetworkSelectionDisableReason {} // Quality Network disabled reasons @@ -2204,13 +2242,18 @@ public class WifiConfiguration implements Parcelable { /** * This network is temporarily disabled because of unwanted network under sufficient rssi. */ - @FlaggedApi("com.android.wifi.flags.disable_reason_unwanted_low_rssi") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public static final int DISABLED_UNWANTED_LOW_RSSI = 14; /** + * This network is temporarily disabled due to repeated IP reachability failures. + * @hide + */ + public static final int DISABLED_REPEATED_NUD_FAILURES = 15; + /** * All other disable reasons should be strictly less than this value. * @hide */ - public static final int NETWORK_SELECTION_DISABLED_MAX = 15; + public static final int NETWORK_SELECTION_DISABLED_MAX = 16; /** * Get an integer that is equal to the maximum integer value of all the @@ -2388,6 +2431,10 @@ public class WifiConfiguration implements Parcelable { new DisableReasonInfo("NETWORK_SELECTION_DISABLED_UNWANTED_LOW_RSSI", 1, 30 * 1000)); + reasons.append(DISABLED_REPEATED_NUD_FAILURES, + new DisableReasonInfo("NETWORK_SELECTION_DISABLED_REPEATED_NUD_FAILURES", + 1, + 15 * 60 * 1000)); return reasons; } @@ -3280,6 +3327,9 @@ public class WifiConfiguration implements Parcelable { */ public HashMap<String, Integer> linkedConfigurations; + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private @NonNull List<OuiKeyedData> mVendorData; + public WifiConfiguration() { networkId = INVALID_NETWORK_ID; SSID = null; @@ -3332,6 +3382,7 @@ public class WifiConfiguration implements Parcelable { mEncryptedPreSharedKey = new byte[0]; mEncryptedPreSharedKeyIv = new byte[0]; mIpProvisioningTimedOut = false; + mVendorData = Collections.emptyList(); } /** @@ -3490,6 +3541,8 @@ public class WifiConfiguration implements Parcelable { sbuf.append(" randomizedMacLastModifiedTimeMs: ") .append(randomizedMacLastModifiedTimeMs == 0 ? "<none>" : logTimeOfDay(randomizedMacLastModifiedTimeMs)).append("\n"); + sbuf.append(" mIsSendDhcpHostnameEnabled: ").append(mIsSendDhcpHostnameEnabled) + .append("\n"); sbuf.append(" deletionPriority: ").append(mDeletionPriority).append("\n"); sbuf.append(" KeyMgmt:"); for (int k = 0; k < this.allowedKeyManagement.size(); k++) { @@ -3657,8 +3710,15 @@ public class WifiConfiguration implements Parcelable { sbuf.append("bssidAllowlist unset"); } sbuf.append("\n"); + if (mVendorData != null && !mVendorData.isEmpty()) { + sbuf.append("vendorData: ").append(mVendorData); + } else { + sbuf.append("vendorData unset"); + } + sbuf.append("\n"); sbuf.append("IsDppConfigurator: ").append(this.mIsDppConfigurator).append("\n"); sbuf.append("HasEncryptedPreSharedKey: ").append(hasEncryptedPreSharedKey()).append("\n"); + sbuf.append(" setWifi7Enabled=").append(mWifi7Enabled); return sbuf.toString(); } @@ -4081,6 +4141,7 @@ public class WifiConfiguration implements Parcelable { macRandomizationSetting = source.macRandomizationSetting; randomizedMacExpirationTimeMs = source.randomizedMacExpirationTimeMs; randomizedMacLastModifiedTimeMs = source.randomizedMacLastModifiedTimeMs; + mIsSendDhcpHostnameEnabled = source.mIsSendDhcpHostnameEnabled; requirePmf = source.requirePmf; updateIdentifier = source.updateIdentifier; carrierId = source.carrierId; @@ -4105,6 +4166,8 @@ public class WifiConfiguration implements Parcelable { mEncryptedPreSharedKeyIv = source.mEncryptedPreSharedKeyIv != null ? source.mEncryptedPreSharedKeyIv.clone() : new byte[0]; mIpProvisioningTimedOut = source.mIpProvisioningTimedOut; + mVendorData = new ArrayList<>(source.mVendorData); + mWifi7Enabled = source.mWifi7Enabled; } } @@ -4182,6 +4245,7 @@ public class WifiConfiguration implements Parcelable { dest.writeLong(recentFailure.getLastUpdateTimeSinceBootMillis()); dest.writeParcelable(mRandomizedMacAddress, flags); dest.writeInt(macRandomizationSetting); + dest.writeBoolean(mIsSendDhcpHostnameEnabled); dest.writeInt(osu ? 1 : 0); dest.writeLong(randomizedMacExpirationTimeMs); dest.writeLong(randomizedMacLastModifiedTimeMs); @@ -4202,131 +4266,141 @@ public class WifiConfiguration implements Parcelable { dest.writeByteArray(mEncryptedPreSharedKey); dest.writeByteArray(mEncryptedPreSharedKeyIv); dest.writeBoolean(mIpProvisioningTimedOut); + dest.writeList(mVendorData); + dest.writeBoolean(mWifi7Enabled); } /** Implement the Parcelable interface {@hide} */ @SystemApi public static final @android.annotation.NonNull Creator<WifiConfiguration> CREATOR = - new Creator<WifiConfiguration>() { - public WifiConfiguration createFromParcel(Parcel in) { - WifiConfiguration config = new WifiConfiguration(); - config.networkId = in.readInt(); - config.status = in.readInt(); - config.mNetworkSelectionStatus.readFromParcel(in); - config.SSID = in.readString(); - config.BSSID = in.readString(); - config.apBand = in.readInt(); - config.apChannel = in.readInt(); - config.FQDN = in.readString(); - config.providerFriendlyName = in.readString(); - config.isHomeProviderNetwork = in.readInt() != 0; - int numRoamingConsortiumIds = in.readInt(); - config.roamingConsortiumIds = new long[numRoamingConsortiumIds]; - for (int i = 0; i < numRoamingConsortiumIds; i++) { - config.roamingConsortiumIds[i] = in.readLong(); - } - config.preSharedKey = in.readString(); - for (int i = 0; i < config.wepKeys.length; i++) { - config.wepKeys[i] = in.readString(); - } - config.wepTxKeyIndex = in.readInt(); - config.priority = in.readInt(); - config.mDeletionPriority = in.readInt(); - config.hiddenSSID = in.readInt() != 0; - config.requirePmf = in.readInt() != 0; - config.updateIdentifier = in.readString(); - - config.allowedKeyManagement = readBitSet(in); - config.allowedProtocols = readBitSet(in); - config.allowedAuthAlgorithms = readBitSet(in); - config.allowedPairwiseCiphers = readBitSet(in); - config.allowedGroupCiphers = readBitSet(in); - config.allowedGroupManagementCiphers = readBitSet(in); - config.allowedSuiteBCiphers = readBitSet(in); - - int numSecurityParams = in.readInt(); - for (int i = 0; i < numSecurityParams; i++) { - config.mSecurityParamsList.add(in.readParcelable(null)); + new Creator<WifiConfiguration>() { + public WifiConfiguration createFromParcel(Parcel in) { + WifiConfiguration config = new WifiConfiguration(); + config.networkId = in.readInt(); + config.status = in.readInt(); + config.mNetworkSelectionStatus.readFromParcel(in); + config.SSID = in.readString(); + config.BSSID = in.readString(); + config.apBand = in.readInt(); + config.apChannel = in.readInt(); + config.FQDN = in.readString(); + config.providerFriendlyName = in.readString(); + config.isHomeProviderNetwork = in.readInt() != 0; + int numRoamingConsortiumIds = in.readInt(); + config.roamingConsortiumIds = new long[numRoamingConsortiumIds]; + for (int i = 0; i < numRoamingConsortiumIds; i++) { + config.roamingConsortiumIds[i] = in.readLong(); + } + config.preSharedKey = in.readString(); + for (int i = 0; i < config.wepKeys.length; i++) { + config.wepKeys[i] = in.readString(); + } + config.wepTxKeyIndex = in.readInt(); + config.priority = in.readInt(); + config.mDeletionPriority = in.readInt(); + config.hiddenSSID = in.readInt() != 0; + config.requirePmf = in.readInt() != 0; + config.updateIdentifier = in.readString(); + + config.allowedKeyManagement = readBitSet(in); + config.allowedProtocols = readBitSet(in); + config.allowedAuthAlgorithms = readBitSet(in); + config.allowedPairwiseCiphers = readBitSet(in); + config.allowedGroupCiphers = readBitSet(in); + config.allowedGroupManagementCiphers = readBitSet(in); + config.allowedSuiteBCiphers = readBitSet(in); + + int numSecurityParams = in.readInt(); + for (int i = 0; i < numSecurityParams; i++) { + config.mSecurityParamsList.add( + in.readParcelable(SecurityParams.class.getClassLoader())); + } + + config.enterpriseConfig = in.readParcelable( + WifiEnterpriseConfig.class.getClassLoader()); + config.setIpConfiguration( + in.readParcelable(IpConfiguration.class.getClassLoader())); + config.dhcpServer = in.readString(); + config.defaultGwMacAddress = in.readString(); + config.validatedInternetAccess = in.readInt() != 0; + config.isLegacyPasspointConfig = in.readInt() != 0; + config.ephemeral = in.readInt() != 0; + config.trusted = in.readInt() != 0; + config.oemPaid = in.readInt() != 0; + config.oemPrivate = in.readInt() != 0; + config.carrierMerged = in.readInt() != 0; + config.fromWifiNetworkSuggestion = in.readInt() != 0; + config.fromWifiNetworkSpecifier = in.readInt() != 0; + config.meteredHint = in.readInt() != 0; + config.mIsRepeaterEnabled = in.readBoolean(); + config.meteredOverride = in.readInt(); + config.useExternalScores = in.readInt() != 0; + config.creatorUid = in.readInt(); + config.lastConnectUid = in.readInt(); + config.lastUpdateUid = in.readInt(); + config.creatorName = in.readString(); + config.lastUpdateName = in.readString(); + config.numScorerOverride = in.readInt(); + config.numScorerOverrideAndSwitchedNetwork = in.readInt(); + config.numAssociation = in.readInt(); + config.allowAutojoin = in.readBoolean(); + config.numNoInternetAccessReports = in.readInt(); + config.noInternetAccessExpected = in.readInt() != 0; + config.shared = in.readInt() != 0; + config.mPasspointManagementObjectTree = in.readString(); + config.recentFailure.setAssociationStatus(in.readInt(), in.readLong()); + config.mRandomizedMacAddress = in.readParcelable( + MacAddress.class.getClassLoader()); + config.macRandomizationSetting = in.readInt(); + config.mIsSendDhcpHostnameEnabled = in.readBoolean(); + config.osu = in.readInt() != 0; + config.randomizedMacExpirationTimeMs = in.readLong(); + config.randomizedMacLastModifiedTimeMs = in.readLong(); + config.carrierId = in.readInt(); + config.mPasspointUniqueId = in.readString(); + config.subscriptionId = in.readInt(); + config.restricted = in.readBoolean(); + config.mSubscriptionGroup = in.readParcelable( + ParcelUuid.class.getClassLoader()); + config.mBssidAllowlist = in.readArrayList(MacAddress.class.getClassLoader()); + config.mIsDppConfigurator = in.readBoolean(); + config.mDppPrivateEcKey = in.createByteArray(); + if (config.mDppPrivateEcKey == null) { + config.mDppPrivateEcKey = new byte[0]; + } + config.mDppConnector = in.createByteArray(); + if (config.mDppConnector == null) { + config.mDppConnector = new byte[0]; + } + config.mDppCSignKey = in.createByteArray(); + if (config.mDppCSignKey == null) { + config.mDppCSignKey = new byte[0]; + } + config.mDppNetAccessKey = in.createByteArray(); + if (config.mDppNetAccessKey == null) { + config.mDppNetAccessKey = new byte[0]; + } + config.isCurrentlyConnected = in.readBoolean(); + config.mIsUserSelected = in.readBoolean(); + config.mHasPreSharedKeyChanged = in.readBoolean(); + config.mEncryptedPreSharedKey = in.createByteArray(); + if (config.mEncryptedPreSharedKey == null) { + config.mEncryptedPreSharedKey = new byte[0]; + } + config.mEncryptedPreSharedKeyIv = in.createByteArray(); + if (config.mEncryptedPreSharedKeyIv == null) { + config.mEncryptedPreSharedKeyIv = new byte[0]; + } + config.mIpProvisioningTimedOut = in.readBoolean(); + config.mVendorData = ParcelUtil.readOuiKeyedDataList(in); + config.mWifi7Enabled = in.readBoolean(); + return config; } - config.enterpriseConfig = in.readParcelable(null); - config.setIpConfiguration(in.readParcelable(null)); - config.dhcpServer = in.readString(); - config.defaultGwMacAddress = in.readString(); - config.validatedInternetAccess = in.readInt() != 0; - config.isLegacyPasspointConfig = in.readInt() != 0; - config.ephemeral = in.readInt() != 0; - config.trusted = in.readInt() != 0; - config.oemPaid = in.readInt() != 0; - config.oemPrivate = in.readInt() != 0; - config.carrierMerged = in.readInt() != 0; - config.fromWifiNetworkSuggestion = in.readInt() != 0; - config.fromWifiNetworkSpecifier = in.readInt() != 0; - config.meteredHint = in.readInt() != 0; - config.mIsRepeaterEnabled = in.readBoolean(); - config.meteredOverride = in.readInt(); - config.useExternalScores = in.readInt() != 0; - config.creatorUid = in.readInt(); - config.lastConnectUid = in.readInt(); - config.lastUpdateUid = in.readInt(); - config.creatorName = in.readString(); - config.lastUpdateName = in.readString(); - config.numScorerOverride = in.readInt(); - config.numScorerOverrideAndSwitchedNetwork = in.readInt(); - config.numAssociation = in.readInt(); - config.allowAutojoin = in.readBoolean(); - config.numNoInternetAccessReports = in.readInt(); - config.noInternetAccessExpected = in.readInt() != 0; - config.shared = in.readInt() != 0; - config.mPasspointManagementObjectTree = in.readString(); - config.recentFailure.setAssociationStatus(in.readInt(), in.readLong()); - config.mRandomizedMacAddress = in.readParcelable(null); - config.macRandomizationSetting = in.readInt(); - config.osu = in.readInt() != 0; - config.randomizedMacExpirationTimeMs = in.readLong(); - config.randomizedMacLastModifiedTimeMs = in.readLong(); - config.carrierId = in.readInt(); - config.mPasspointUniqueId = in.readString(); - config.subscriptionId = in.readInt(); - config.restricted = in.readBoolean(); - config.mSubscriptionGroup = in.readParcelable(null); - config.mBssidAllowlist = in.readArrayList(MacAddress.class.getClassLoader()); - config.mIsDppConfigurator = in.readBoolean(); - config.mDppPrivateEcKey = in.createByteArray(); - if (config.mDppPrivateEcKey == null) { - config.mDppPrivateEcKey = new byte[0]; - } - config.mDppConnector = in.createByteArray(); - if (config.mDppConnector == null) { - config.mDppConnector = new byte[0]; - } - config.mDppCSignKey = in.createByteArray(); - if (config.mDppCSignKey == null) { - config.mDppCSignKey = new byte[0]; - } - config.mDppNetAccessKey = in.createByteArray(); - if (config.mDppNetAccessKey == null) { - config.mDppNetAccessKey = new byte[0]; - } - config.isCurrentlyConnected = in.readBoolean(); - config.mIsUserSelected = in.readBoolean(); - config.mHasPreSharedKeyChanged = in.readBoolean(); - config.mEncryptedPreSharedKey = in.createByteArray(); - if (config.mEncryptedPreSharedKey == null) { - config.mEncryptedPreSharedKey = new byte[0]; - } - config.mEncryptedPreSharedKeyIv = in.createByteArray(); - if (config.mEncryptedPreSharedKeyIv == null) { - config.mEncryptedPreSharedKeyIv = new byte[0]; + public WifiConfiguration[] newArray(int size) { + return new WifiConfiguration[size]; } - config.mIpProvisioningTimedOut = in.readBoolean(); - return config; - } - - public WifiConfiguration[] newArray(int size) { - return new WifiConfiguration[size]; - } - }; + }; /** * Passpoint Unique identifier @@ -4630,4 +4704,67 @@ public class WifiConfiguration implements Parcelable { public @Nullable ParcelUuid getSubscriptionGroup() { return this.mSubscriptionGroup; } + + /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * #setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + + /** + * Set additional vendor-provided configuration data. + * + * Setting this field requires the MANAGE_WIFI_NETWORK_SELECTION permission. Otherwise, + * if this data is set, the configuration will be rejected upon add or update. + * + * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided + * configuration data. Note that multiple elements with the same OUI are allowed. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + Objects.requireNonNull(vendorData); + mVendorData = new ArrayList<>(vendorData); + } + + /** + * Whether Wi-Fi 7 is enabled for this network. + * + * @return true if enabled; false otherwise + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean isWifi7Enabled() { + return mWifi7Enabled; + } + + /** + * Sets whether Wi-Fi 7 is enabled for this network. + * + * @param enabled true if enabled; false otherwise + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void setWifi7Enabled(boolean enabled) { + mWifi7Enabled = enabled; + } } diff --git a/framework/java/android/net/wifi/WifiInfo.java b/framework/java/android/net/wifi/WifiInfo.java index 82ab9ace78..8e233d74d6 100644 --- a/framework/java/android/net/wifi/WifiInfo.java +++ b/framework/java/android/net/wifi/WifiInfo.java @@ -48,6 +48,7 @@ import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.Inet4AddressUtils; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -492,6 +493,9 @@ public class WifiInfo implements TransportInfo, Parcelable { */ private String mNetworkKey; + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private @NonNull List<OuiKeyedData> mVendorData; + /** @hide */ @UnsupportedAppUsage public WifiInfo() { @@ -510,6 +514,7 @@ public class WifiInfo implements TransportInfo, Parcelable { mIsPrimary = IS_PRIMARY_FALSE; mNetworkKey = null; mApMloLinkId = MloLink.INVALID_MLO_LINK_ID; + mVendorData = Collections.emptyList(); } /** @hide */ @@ -555,6 +560,7 @@ public class WifiInfo implements TransportInfo, Parcelable { mNetworkKey = null; resetMultiLinkInfo(); enableApTidToLinkMappingNegotiationSupport(false); + mVendorData = Collections.emptyList(); } /** @hide */ @@ -646,6 +652,7 @@ public class WifiInfo implements TransportInfo, Parcelable { ? null : source.mNetworkKey; mApTidToLinkMappingNegotiationSupported = source.mApTidToLinkMappingNegotiationSupported; + mVendorData = new ArrayList<>(source.mVendorData); } } @@ -729,7 +736,7 @@ public class WifiInfo implements TransportInfo, Parcelable { * Set the subscription ID. * @see WifiInfo#getSubscriptionId() */ - @FlaggedApi("com.android.wifi.flags.add_subscription_id") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @NonNull public Builder setSubscriptionId(int subId) { mWifiInfo.setSubscriptionId(subId); @@ -1544,7 +1551,7 @@ public class WifiInfo implements TransportInfo, Parcelable { .append(", Security type: ").append(mSecurityType) .append(", Supplicant state: ") .append(mSupplicantState == null ? none : mSupplicantState) - .append(", Wi-Fi standard: ").append(mWifiStandard) + .append(", Wi-Fi standard: ").append(ScanResult.wifiStandardToString(mWifiStandard)) .append(", RSSI: ").append(mRssi) .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS) .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS) @@ -1581,7 +1588,9 @@ public class WifiInfo implements TransportInfo, Parcelable { .append(", AP MLO Link Id: ").append( mApMldMacAddress == null ? none : mApMloLinkId) .append(", AP MLO Affiliated links: ").append( - mApMldMacAddress == null ? none : mAffiliatedMloLinks); + mApMldMacAddress == null ? none : mAffiliatedMloLinks) + .append(", Vendor Data: ").append( + mVendorData == null || mVendorData.isEmpty() ? none : mVendorData); return sb.toString(); } @@ -1662,6 +1671,7 @@ public class WifiInfo implements TransportInfo, Parcelable { dest.writeInt(mApMloLinkId); dest.writeTypedList(mAffiliatedMloLinks); dest.writeBoolean(mApTidToLinkMappingNegotiationSupported); + dest.writeList(mVendorData); } /** Implement the Parcelable interface {@hide} */ @@ -1725,6 +1735,7 @@ public class WifiInfo implements TransportInfo, Parcelable { info.mApMloLinkId = in.readInt(); info.mAffiliatedMloLinks = in.createTypedArrayList(MloLink.CREATOR); info.mApTidToLinkMappingNegotiationSupported = in.readBoolean(); + info.mVendorData = ParcelUtil.readOuiKeyedDataList(in); return info; } @@ -1746,9 +1757,9 @@ public class WifiInfo implements TransportInfo, Parcelable { /** * Get the Passpoint unique identifier for the current connection * - * @return Passpoint unique identifier - * @hide + * @return Passpoint unique identifier, or null if this connection is not Passpoint. */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public @Nullable String getPasspointUniqueId() { return mPasspointUniqueId; } @@ -1894,7 +1905,8 @@ public class WifiInfo implements TransportInfo, Parcelable { && mRestricted == thatWifiInfo.mRestricted && Objects.equals(mNetworkKey, thatWifiInfo.mNetworkKey) && mApTidToLinkMappingNegotiationSupported - == thatWifiInfo.mApTidToLinkMappingNegotiationSupported; + == thatWifiInfo.mApTidToLinkMappingNegotiationSupported + && Objects.equals(mVendorData, thatWifiInfo.mVendorData); } @Override @@ -1946,7 +1958,8 @@ public class WifiInfo implements TransportInfo, Parcelable { mSecurityType, mRestricted, mNetworkKey, - mApTidToLinkMappingNegotiationSupported); + mApTidToLinkMappingNegotiationSupported, + mVendorData); } /** @@ -2116,4 +2129,42 @@ public class WifiInfo implements TransportInfo, Parcelable { public void enableApTidToLinkMappingNegotiationSupport(boolean enable) { mApTidToLinkMappingNegotiationSupported = enable; } + + /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * #setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + + /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided + * configuration data. Note that multiple elements with the same OUI are allowed. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = new ArrayList<>(vendorData); + } } diff --git a/framework/java/android/net/wifi/WifiManager.java b/framework/java/android/net/wifi/WifiManager.java index e8cf5fc111..411a0f8615 100644 --- a/framework/java/android/net/wifi/WifiManager.java +++ b/framework/java/android/net/wifi/WifiManager.java @@ -36,6 +36,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.StringDef; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -62,7 +63,11 @@ import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.ProvisioningCallback; import android.net.wifi.p2p.WifiP2pConfig; +import android.net.wifi.p2p.WifiP2pDiscoveryConfig; import android.net.wifi.p2p.WifiP2pManager; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSession; +import android.net.wifi.twt.TwtSessionCallback; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -89,6 +94,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.HandlerExecutor; import com.android.modules.utils.ParceledListSlice; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -108,6 +114,7 @@ import java.util.StringTokenizer; import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.IntConsumer; /** * This class provides the primary API for managing all aspects of Wi-Fi @@ -391,7 +398,7 @@ public class WifiManager { * Disable PNO scan until device reboot. * @hide */ - @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public static final int PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT = 0; @@ -399,7 +406,7 @@ public class WifiManager { * Disable PNO scan until device reboot or Wi-Fi is toggled. * @hide */ - @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public static final int PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE = 1; @@ -407,7 +414,7 @@ public class WifiManager { * Enable PNO scan. * @hide */ - @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public static final int PNO_SCAN_STATE_ENABLED = 2; @@ -532,7 +539,8 @@ public class WifiManager { API_P2P_SET_CHANNELS, API_WIFI_SCANNER_START_SCAN, API_SET_TDLS_ENABLED, - API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS + API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS, + API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS }) public @interface ApiType {} @@ -889,15 +897,26 @@ public class WifiManager { * * @hide */ - @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public static final int API_SET_PNO_SCAN_ENABLED = 36; /** + * A constant used in {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)} + * Tracks usage of {@link WifiP2pManager#discoverPeersWithConfigParams( + * WifiP2pManager.Channel, WifiP2pDiscoveryConfig, WifiP2pManager.ActionListener)} + * + * @hide + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public static final int API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS = 37; + + /** * Used internally to keep track of boundary. * @hide */ - public static final int API_MAX = 37; + public static final int API_MAX = 38; /** * Broadcast intent action indicating that a Passpoint provider icon has been received. @@ -2136,6 +2155,38 @@ public class WifiManager { } /** + * Roaming is disabled. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int ROAMING_MODE_NONE = 0; + + /** + * Chipset has roaming trigger capability based on the score calculated + * using multiple parameters. If device is configured to this mode then it + * will be using chipset's normal (default) roaming. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int ROAMING_MODE_NORMAL = 1; + + /** + * Allows the device to roam more quickly than the normal roaming mode. + * Used in cases such as where APs are installed in a high density. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int ROAMING_MODE_AGGRESSIVE = 2; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"ROAMING_MODE_"}, value = { + ROAMING_MODE_NONE, + ROAMING_MODE_NORMAL, + ROAMING_MODE_AGGRESSIVE}) + public @interface RoamingMode { + } + + /** * Create a new WifiManager instance. * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve @@ -3968,6 +4019,18 @@ public class WifiManager { */ public static final long WIFI_FEATURE_WPA_PERSONAL = 1L << 60; + /** + * Support for Roaming Mode + * @hide + */ + public static final long WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT = 1L << 61; + + /** + * Supports device-to-device connections when infra STA is disabled. + * @hide + */ + public static final long WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED = 1L << 62; + private long getSupportedFeatures() { try { return mService.getSupportedFeatures(); @@ -4109,7 +4172,11 @@ public class WifiManager { * @return true if this adapter supports offloaded connectivity scan */ public boolean isPreferredNetworkOffloadSupported() { - return isFeatureSupported(WIFI_FEATURE_PNO); + try { + return mService.isPnoSupported(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -4156,7 +4223,7 @@ public class WifiManager { * @return true if this device supports Low latency mode. * @hide */ - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public boolean isLowLatencyModeSupported() { return isFeatureSupported(WIFI_FEATURE_LOW_LATENCY); @@ -4249,6 +4316,15 @@ public class WifiManager { } /** + * @return true if this devices supports device-to-device (D2d) Wi-Fi use-cases + * such as Wi-Fi Direct when infra station (STA) is disabled. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean isD2dSupportedWhenInfraStaDisabled() { + return isFeatureSupported(WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED); + } + + /** * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}. * @@ -5612,6 +5688,8 @@ public class WifiManager { * using {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}. * @return {@code true} if the operation succeeded, {@code false} otherwise * + * @deprecated Use {@link #startTetheredHotspotRequest(TetheringManager.TetheringRequest)} + * instead. * @hide */ @SystemApi @@ -5619,6 +5697,7 @@ public class WifiManager { android.Manifest.permission.NETWORK_STACK, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK }) + @Deprecated public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) { try { return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName()); @@ -5648,14 +5727,18 @@ public class WifiManager { * * @hide */ - @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_STACK, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK }) public boolean startTetheredHotspotRequest(@NonNull TetheringManager.TetheringRequest request) { - throw new UnsupportedOperationException("Not supported before API 35"); + try { + return mService.startTetheredHotspotRequest(request, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -6550,10 +6633,14 @@ public class WifiManager { /** * Called when soft AP state changes. + * <p> + * This provides the same state and failure reason as {@link #onStateChanged(int, int)}, but + * also provides extra information such as interface name and TetheringRequest in order to + * replace usage of the WIFI_AP_STATE_CHANGED_ACTION broadcast. * * @param state the new state. */ - @FlaggedApi("com.android.wifi.flags.android_v_wifi_api") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) default void onStateChanged(@NonNull SoftApState state) {} /** @@ -6690,15 +6777,16 @@ public class WifiManager { } @Override - public void onStateChanged(int state, int failureReason) { + public void onStateChanged(SoftApState state) { if (mVerboseLoggingEnabled) { - Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode + ", onStateChanged: state=" - + state + ", failureReason=" + failureReason); + Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode + + ", onStateChanged: " + state); } Binder.clearCallingIdentity(); mExecutor.execute(() -> { - mCallback.onStateChanged(state, failureReason); + mCallback.onStateChanged(state); + mCallback.onStateChanged(state.getState(), state.getFailureReasonInternal()); }); } @@ -7275,7 +7363,12 @@ public class WifiManager { listenerProxy = new ActionListenerProxy("connect", mLooper, listener); } try { - mService.connect(config, networkId, listenerProxy, mContext.getOpPackageName()); + Bundle extras = new Bundle(); + if (SdkLevel.isAtLeastS()) { + extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, + mContext.getAttributionSource()); + } + mService.connect(config, networkId, listenerProxy, mContext.getOpPackageName(), extras); } catch (RemoteException e) { if (listenerProxy != null) { listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR); @@ -7921,7 +8014,7 @@ public class WifiManager { * * @hide */ - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public interface WifiLowLatencyLockListener { /** @@ -7930,7 +8023,7 @@ public class WifiManager { * * <p>Note: Always called with current state when a new listener gets registered. */ - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) void onActivatedStateChanged(boolean activated); /** @@ -7942,7 +8035,7 @@ public class WifiManager { * * @param ownerUids An array of UIDs. */ - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) default void onOwnershipChanged(@NonNull int[] ownerUids) {} /** @@ -7958,7 +8051,7 @@ public class WifiManager { * * @param activeUids An array of UIDs. */ - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) default void onActiveUsersChanged(@NonNull int[] activeUids) {} } @@ -8015,7 +8108,7 @@ public class WifiManager { * @throws SecurityException if the caller is not allowed to call this API * @hide */ - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi @RequiresApi(Build.VERSION_CODES.TIRAMISU) @RequiresPermission( @@ -8053,7 +8146,7 @@ public class WifiManager { * @throws IllegalArgumentException if incorrect input arguments are provided. * @hide */ - @FlaggedApi("com.android.wifi.flags.low_latency_lock_listener") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void removeWifiLowLatencyLockListener(@NonNull WifiLowLatencyLockListener listener) { @@ -8453,6 +8546,60 @@ public class WifiManager { /** * Returns a byte stream representing the data that needs to be backed up to save the * current Wifi state. + * This Wifi state can be restored by calling {@link #restoreWifiBackupData(byte[])}. + * @hide + */ + @SystemApi + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void retrieveWifiBackupData(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<byte[]> resultsCallback) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); + try { + mService.retrieveWifiBackupData( + new IByteArrayListener.Stub() { + @Override + public void onResult(byte[] value) { + Binder.clearCallingIdentity(); + executor.execute(() -> { + resultsCallback.accept(value); + }); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Restore state from the backed up data. + * @param data byte stream in the same format produced by {@link #retrieveWifiBackupData()} + * @hide + */ + @SystemApi + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void restoreWifiBackupData(@NonNull byte[] data) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + try { + mService.restoreWifiBackupData(data); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns a byte stream representing the data that needs to be backed up to save the + * current Wifi state. * This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}. * @hide */ @@ -8873,7 +9020,7 @@ public class WifiManager { /** * @return true if this device supports connections to Wi-Fi WEP networks. */ - @FlaggedApi("com.android.wifi.flags.wep_usage") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public boolean isWepSupported() { return isFeatureSupported(WIFI_FEATURE_WEP); } @@ -8884,7 +9031,7 @@ public class WifiManager { * Note that this is the older and less secure WPA-Personal protocol, not WPA2-Personal * or later protocols. */ - @FlaggedApi("com.android.wifi.flags.wpa_personal_usage") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public boolean isWpaPersonalSupported() { return isFeatureSupported(WIFI_FEATURE_WPA_PERSONAL); } @@ -9099,7 +9246,7 @@ public class WifiManager { * * @hide */ - @FlaggedApi("com.android.wifi.flags.verbose_logging_for_aware_only") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi public static final int VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY = 3; @@ -10446,7 +10593,7 @@ public class WifiManager { * @throws SecurityException if the caller does not have permission. * @hide */ - @FlaggedApi("com.android.wifi.flags.runtime_disable_pno_scan") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi @RequiresPermission( anyOf = {MANAGE_WIFI_NETWORK_SELECTION, NETWORK_SETTINGS, NETWORK_SETUP_WIZARD}) @@ -11673,7 +11820,9 @@ public class WifiManager { * * Note: All policies in a single request must have the same {@link QosPolicyParams.Direction}. * - * Note: Currently, only the {@link QosPolicyParams#DIRECTION_DOWNLINK} direction is supported. + * Note: Support for the {@link QosPolicyParams#DIRECTION_UPLINK} direction is added in + * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}. For earlier releases, + * only the {@link QosPolicyParams#DIRECTION_DOWNLINK} direction is supported. * * @param policyParamsList List of {@link QosPolicyParams} objects describing the requested * policies. Must have a maximum length of @@ -11926,7 +12075,7 @@ public class WifiManager { * @hide */ @SystemApi - @FlaggedApi("com.android.wifi.flags.mlo_link_capabilities_info") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION) public void getMaxMloAssociationLinkCount(@NonNull @CallbackExecutor Executor executor, @@ -11973,7 +12122,7 @@ public class WifiManager { * @hide */ @SystemApi - @FlaggedApi("com.android.wifi.flags.mlo_link_capabilities_info") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION) public void getMaxMloStrLinkCount(@NonNull @CallbackExecutor Executor executor, @@ -12016,7 +12165,7 @@ public class WifiManager { * @hide */ @SystemApi - @FlaggedApi("com.android.wifi.flags.mlo_link_capabilities_info") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION) public void getSupportedSimultaneousBandCombinations( @@ -12060,7 +12209,7 @@ public class WifiManager { * @throws SecurityException if the caller does not have permission. * @hide */ - @FlaggedApi("com.android.wifi.flags.wep_usage") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_SETTINGS, @@ -12087,10 +12236,9 @@ public class WifiManager { * whether wep network support is enabled/disabled. * * @throws SecurityException if the caller does not have permission. - * @throws NullPointerException if the caller provided invalid inputs. * @hide */ - @FlaggedApi("com.android.wifi.flags.wep_usage") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_SETTINGS, @@ -12115,4 +12263,556 @@ public class WifiManager { throw e.rethrowFromSystemServer(); } } + + /** + * Enable Mirrored Stream Classification Service (MSCS) and configure using + * the provided configuration values. + * + * If MSCS has already been enabled/configured, this will override the + * existing configuration. + * + * Refer to Section 11.25.3 of the IEEE 802.11-2020 standard for more information. + * + * @param mscsParams {@link MscsParams} object containing the configuration parameters. + * @hide + */ + @SystemApi + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresPermission(anyOf = {MANAGE_WIFI_NETWORK_SELECTION}) + public void enableMscs(@NonNull MscsParams mscsParams) { + Objects.requireNonNull(mscsParams); + try { + mService.enableMscs(mscsParams); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Disable Mirrored Stream Classification Service (MSCS). + * + * If MSCS is enabled/configured, this will send a remove request to the AP. + * + * Refer to Section 11.25.3 of the IEEE 802.11-2020 standard for more information. + * @hide + */ + @SystemApi + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresPermission(anyOf = {MANAGE_WIFI_NETWORK_SELECTION}) + public void disableMscs() { + try { + mService.disableMscs(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Do not send the DHCP hostname to open networks. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN = 1 << 0; + + /** + * Do not send the DHCP hostname to secure network. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE = 1 << 1; + + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_" }, value = { + FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN, + FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SendDhcpHostnameRestriction {} + + /** + * Sets the global restrictions on which networks to send the device hostname to during DHCP. + * + * @param restriction Bitmask of {@link SendDhcpHostnameRestriction}, or none to indicate no + * restriction. + * @throws IllegalArgumentException if input is invalid + * @throws SecurityException if the calling app is not a Device Owner (DO), or a privileged app + * that has one of the permissions required by this API. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) + public void setSendDhcpHostnameRestriction(@SendDhcpHostnameRestriction int restriction) { + try { + mService.setSendDhcpHostnameRestriction(mContext.getOpPackageName(), restriction); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Query the global restriction on which networks to send the device hostname to during DHCP. + * @see #setSendDhcpHostnameRestriction(int) + * + * @param executor The executor on which callback will be invoked. + * @param resultsCallback An asynchronous callback that will return a bitmask of + * {@link SendDhcpHostnameRestriction}. + * + * @throws SecurityException if the calling app is not a Device Owner (DO), or a privileged app + * that has one of the permissions required by this API. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) + public void querySendDhcpHostnameRestriction(@NonNull @CallbackExecutor Executor executor, + @NonNull IntConsumer resultsCallback) { + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); + try { + mService.querySendDhcpHostnameRestriction(mContext.getOpPackageName(), + new IIntegerListener.Stub() { + @Override + public void onResult(int value) { + Binder.clearCallingIdentity(); + executor.execute(() -> { + resultsCallback.accept(value); + }); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @return true if this device supports Aggressive roaming mode + * {@link #setPerSsidRoamingMode(WifiSsid, int)} + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean isAggressiveRoamingModeSupported() { + return isFeatureSupported(WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT); + } + + /** + * This API allows a privileged application to set roaming mode per SSID. + * + * Available for DO/COPE apps. + * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or + * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission. + * + * @param ssid SSID to be mapped to apply roaming policy + * @param roamingMode refer {@link RoamingMode} for supported modes. + * @throws IllegalArgumentException if mode value is not in {@link RoamingMode}. + * @throws NullPointerException if the caller provided a null input. + * @throws SecurityException if caller does not have the required permission. + * @throws UnsupportedOperationException if the set operation is not supported on this SDK or + * if the feature is not available + * {@link #isAggressiveRoamingModeSupported()}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @SuppressLint("RequiresPermission") + public void setPerSsidRoamingMode(@NonNull WifiSsid ssid, @RoamingMode int roamingMode) { + if (roamingMode < ROAMING_MODE_NONE || roamingMode > ROAMING_MODE_AGGRESSIVE) { + throw new IllegalArgumentException("invalid roaming mode: " + roamingMode); + } + Objects.requireNonNull(ssid, "ssid cannot be null"); + try { + mService.setPerSsidRoamingMode(ssid, roamingMode, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * This API allows a privileged application to remove roaming mode policy + * configured using the {@link #setPerSsidRoamingMode(WifiSsid, int)}. + * + * Available for DO/COPE apps. + * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or + * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission. + * + * @param ssid SSID to be removed from the roaming mode policy. + * @throws NullPointerException if the caller provided a null input. + * @throws SecurityException if caller does not have the required permission. + * @throws UnsupportedOperationException if the set operation is not supported on this SDK or + * if the feature is not available + * {@link #isAggressiveRoamingModeSupported()}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @SuppressLint("RequiresPermission") + public void removePerSsidRoamingMode(@NonNull WifiSsid ssid) { + Objects.requireNonNull(ssid, "ssid cannot be null"); + try { + mService.removePerSsidRoamingMode(ssid, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * This API allows a privileged application to get roaming mode policies + * configured using the {@link #setPerSsidRoamingMode(WifiSsid, int)}. + * + * Available for DO/COPE apps. + * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or + * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission. + * + * @param executor The executor on which callback will be invoked. + * @param resultsCallback An asynchronous callback that will return the corresponding + * roaming policies for the API caller. + * @throws SecurityException if caller does not have the required permission. + * @throws UnsupportedOperationException if the get operation is not supported on this SDK or + * if the feature is not available + * {@link #isAggressiveRoamingModeSupported()}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @SuppressLint("RequiresPermission") + public void getPerSsidRoamingModes(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Map<String, Integer>> resultsCallback) { + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); + try { + mService.getPerSsidRoamingModes(mContext.getOpPackageName(), new IMapListener.Stub() { + @Override + public void onResult(Map roamingPolicies) { + Binder.clearCallingIdentity(); + executor.execute(() -> { + resultsCallback.accept(roamingPolicies); + }); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Bundle key to check target wake time requester mode supported or not + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final String TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER = + "key_requester"; + + /** + * Bundle key to get minimum wake duration supported in microseconds + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final String TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS = + "key_min_wake_duration"; + /** + * Bundle key to get maximum wake duration supported in microseconds + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final String TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS = + "key_max_wake_duration"; + /** + * Bundle key to get minimum wake interval supported in microseconds + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final String TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS = + "key_min_wake_interval"; + /** + * Bundle key to get maximum wake interval supported in microseconds + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final String TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS = + "key_max_wake_interval"; + + /** @hide */ + @StringDef(prefix = { "TWT_CAPABILITIES_KEY_"}, value = { + TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER, + TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS, + TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS, + TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS, + TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TwtCapabilities {} + + /** + * Get target wake time (TWT) capabilities of the primary station interface. + * + * Note: Target wake time feature is only supported for primary station. If Wi-Fi is off or the + * capability is not available the asynchronous callback will be called with the bundle + * with values { false, -1, -1, -1, -1 }. + * + * @param executor Executor to execute listener callback + * @param resultCallback An asynchronous callback that will return a bundle for target wake time + * capabilities. See {@link TwtCapabilities} for the string keys for + * the bundle. + * @throws SecurityException if the caller does not have permission. + * @throws NullPointerException if the caller provided null inputs. + * @throws UnsupportedOperationException if the API is not supported. + * @hide + */ + @SystemApi + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void getTwtCapabilities(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Bundle> resultCallback) { + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(resultCallback, "resultCallback cannot be null"); + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + try { + Bundle extras = new Bundle(); + extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, + mContext.getAttributionSource()); + mService.getTwtCapabilities( + new ITwtCapabilitiesListener.Stub() { + @Override + public void onResult(Bundle value) { + Binder.clearCallingIdentity(); + executor.execute(() -> { + resultCallback.accept(value); + }); + } + }, extras); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private class TwtCallbackProxy extends ITwtCallback.Stub { + private final Executor mExecutor; + private final TwtSessionCallback mCallback; + + private TwtCallbackProxy(Executor executor, TwtSessionCallback callback) { + mExecutor = executor; + mCallback = callback; + } + + @Override + public void onFailure(@TwtSessionCallback.TwtErrorCode int errorCode) + throws RemoteException { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "TwtCallbackProxy: onFailure(errorCode = " + errorCode + " )"); + } + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onFailure(errorCode)); + } + + @Override + public void onTeardown(@TwtSessionCallback.TwtReasonCode int reasonCode) + throws RemoteException { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "TwtCallbackProxy: onTeardown(errorCode = " + reasonCode + " )"); + } + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onTeardown(reasonCode)); + } + + @Override + public void onCreate(int wakeDuration, long wakeInterval, int mloLinkId, int owner, + int sessionId) throws RemoteException { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "TwtCallbackProxy: onCreate " + sessionId); + } + + WifiTwtSession wifiTwtSession = new WifiTwtSession(WifiManager.this, wakeDuration, + wakeInterval, mloLinkId, owner, sessionId); + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onCreate(wifiTwtSession)); + } + } + + /** + * Set up a TWT session with a TWT responder capable AP. Only supported for primary connected + * station which is a TWT requester. See {@link #getTwtCapabilities(Executor, Consumer)} and + * {@link ScanResult#isTwtResponder()} to check station and AP support. + * + * Following callbacks are invoked, + * - {@link TwtSessionCallback#onFailure(int)} upon error with error code. + * - {@link TwtSessionCallback#onCreate(TwtSession)} upon TWT session creation. + * - {@link TwtSessionCallback#onTeardown(int)} upon TWT session teardown. + * + * Note: {@link #getTwtCapabilities(Executor, Consumer)} gives {@link TwtCapabilities} which can + * be used to fill in the valid TWT wake interval and duration ranges for {@link TwtRequest}. + * + * @param twtRequest TWT request + * @param executor Executor to execute listener callback on + * @param callback Callback to register + * @throws SecurityException if the caller does not have permission. + * @throws NullPointerException if the caller provided null inputs. + * @throws UnsupportedOperationException if the API is not supported. + * @hide + */ + @SystemApi + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void setupTwtSession(@NonNull TwtRequest twtRequest, + @NonNull @CallbackExecutor Executor executor, @NonNull TwtSessionCallback callback) { + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(callback, "callback cannot be null"); + Objects.requireNonNull(twtRequest, "twtRequest cannot be null"); + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + try { + ITwtCallback.Stub binderCallback = new TwtCallbackProxy(executor, callback); + Bundle extras = new Bundle(); + extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, + mContext.getAttributionSource()); + mService.setupTwtSession(twtRequest, binderCallback, extras); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get stats of the target wake time session. + * + * Note: For Internal use only. Expected to be called through + * {@link TwtSession#getStats(Executor, Consumer)}. If the command fails, -1 will be returned + * for all stats values. + * + * @param sessionId TWT session id + * @param executor The executor on which callback will be invoked. + * @param resultCallback The asynchronous callback that will return bundle with key string + * {@link TwtSession.TwtStats}. + * + * @throws SecurityException if the caller does not have permission. + * @throws NullPointerException if the caller provided null inputs. + * @throws UnsupportedOperationException if the API is not supported or primary station is + * not connected. + * @hide + */ + public void getStatsTwtSession(@NonNull int sessionId, @NonNull Executor executor, + @NonNull Consumer<Bundle> resultCallback) { + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(resultCallback, "resultsCallback cannot be null"); + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + try { + Bundle extras = new Bundle(); + if (SdkLevel.isAtLeastS()) { + extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, + mContext.getAttributionSource()); + } + mService.getStatsTwtSession(sessionId, + new ITwtStatsListener.Stub() { + @Override + public void onResult(Bundle value) { + Binder.clearCallingIdentity(); + executor.execute(() -> { + resultCallback.accept(value); + }); + } + }, extras); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Teardown the target wake time session. Only owner can teardown the session. + * + * Note: For internal use only. Expected to be called through + * {@link TwtSessionCallback#onTeardown(int)}. + * + * @param sessionId TWT session id + * @throws SecurityException if the caller does not have permission. + * @throws UnsupportedOperationException if the API is not supported or primary station is not + * connected. + * @hide + */ + public void teardownTwtSession(int sessionId) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + try { + Bundle extras = new Bundle(); + if (SdkLevel.isAtLeastS()) { + extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, + mContext.getAttributionSource()); + } + mService.teardownTwtSession(sessionId, extras); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Allows a privileged application to set whether or not this device allows + * device-to-device connections when infra STA is disabled. Callers can use + * {@link #queryD2dAllowedWhenInfraStaDisabled(Executor, Consumer)} to check the currently + * set value. + * + * Note: This functionality is supported only when the device support device-to-device + * when infra STA is disabled. Use {@link #isD2dSupportedWhenInfraStaDisabled()} to + * know if device supported device-to-device when infra STA is disabled. + * + * @param isAllowed whether or not the device allows to device-to-device connectivity when + * infra STA is disabled. + * @throws SecurityException if the caller does not have permission. + * @hide + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public void setD2dAllowedWhenInfraStaDisabled(boolean isAllowed) { + try { + mService.setD2dAllowedWhenInfraStaDisabled(isAllowed); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Query whether or not this device is configured to allow D2d connection when + * infra STA is disabled. + * see: {@link #setD2dAllowedWhenInfraStaDisabled(boolean)}. + * + * + * @param executor The executor on which callback will be invoked. + * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating + * whether device-to-device connection is allowed or disallowed + * when infra STA is disabled. + * @hide + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void queryD2dAllowedWhenInfraStaDisabled(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> resultsCallback) { + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); + try { + mService.queryD2dAllowedWhenInfraStaDisabled( + new IBooleanListener.Stub() { + @Override + public void onResult(boolean value) { + Binder.clearCallingIdentity(); + executor.execute(() -> { + resultsCallback.accept(value); + }); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/framework/java/android/net/wifi/WifiNetworkSuggestion.java b/framework/java/android/net/wifi/WifiNetworkSuggestion.java index be666815aa..eb7405f36c 100644 --- a/framework/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/framework/java/android/net/wifi/WifiNetworkSuggestion.java @@ -18,6 +18,7 @@ package android.net.wifi; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -40,6 +41,7 @@ import android.text.TextUtils; import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -232,6 +234,11 @@ public final class WifiNetworkSuggestion implements Parcelable { */ private boolean mIsNetworkRestricted; + /** + * Whether enable Wi-Fi 7 for this network + */ + private boolean mIsWifi7Enabled; + /** * The Subscription group UUID identifies the SIM cards for which this network configuration @@ -269,6 +276,7 @@ public final class WifiNetworkSuggestion implements Parcelable { mIsNetworkRestricted = false; mSubscriptionGroup = null; mWifiSsid = null; + mIsWifi7Enabled = true; } /** @@ -862,6 +870,17 @@ public final class WifiNetworkSuggestion implements Parcelable { } /** + * Sets whether Wi-Fi 7 is enabled for this network. + * + * @param enabled Enable Wi-Fi 7 if true, otherwise disable Wi-Fi 7 + * @return Instance of {@link Builder} to enable chaining of the builder method. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @NonNull Builder setWifi7Enabled(boolean enabled) { + mIsWifi7Enabled = enabled; + return this; + } + /** * Specifies whether the system will bring up the network (if selected) as OEM paid. An * OEM paid network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID} capability * added. @@ -1080,6 +1099,7 @@ public final class WifiNetworkSuggestion implements Parcelable { wifiConfiguration.subscriptionId = mSubscriptionId; wifiConfiguration.restricted = mIsNetworkRestricted; wifiConfiguration.setSubscriptionGroup(mSubscriptionGroup); + wifiConfiguration.setWifi7Enabled(mIsWifi7Enabled); return wifiConfiguration; } @@ -1119,6 +1139,7 @@ public final class WifiNetworkSuggestion implements Parcelable { : WifiConfiguration.RANDOMIZATION_PERSISTENT; wifiConfiguration.restricted = mIsNetworkRestricted; wifiConfiguration.setSubscriptionGroup(mSubscriptionGroup); + wifiConfiguration.setWifi7Enabled(mIsWifi7Enabled); mPasspointConfiguration.setCarrierId(mCarrierId); mPasspointConfiguration.setSubscriptionId(mSubscriptionId); mPasspointConfiguration.setSubscriptionGroup(mSubscriptionGroup); @@ -1709,4 +1730,12 @@ public final class WifiNetworkSuggestion implements Parcelable { } return wifiConfiguration.getSubscriptionGroup(); } + + /** + * See {@link Builder#setWifi7Enabled(boolean)} + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean isWifi7Enabled() { + return wifiConfiguration.isWifi7Enabled(); + } } diff --git a/framework/java/android/net/wifi/WifiScanner.java b/framework/java/android/net/wifi/WifiScanner.java index 526ca7c360..93ea0b0bad 100644 --- a/framework/java/android/net/wifi/WifiScanner.java +++ b/framework/java/android/net/wifi/WifiScanner.java @@ -16,10 +16,13 @@ package android.net.wifi; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.Manifest.permission.LOCATION_HARDWARE; import static android.Manifest.permission.NEARBY_WIFI_DEVICES; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -44,6 +47,7 @@ import androidx.annotation.RequiresApi; import com.android.internal.util.Protocol; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -54,6 +58,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.function.Consumer; /** * This class provides a way to scan the Wifi universe around the device @@ -835,7 +840,8 @@ public class WifiScanner { /** all scan results discovered in this scan, sorted by timestamp in ascending order */ private final List<ScanResult> mResults; - ScanData() { + /** {@hide} */ + public ScanData() { mResults = new ArrayList<>(); } @@ -1560,6 +1566,41 @@ public class WifiScanner { } } + /** + * Retrieve the scan data cached by the hardware. + * + * @param executor The executor on which callback will be invoked. + * @param resultsCallback An asynchronous callback that will return the cached scan data. + * + * @throws UnsupportedOperationException if the API is not supported on this SDK version. + * @throws SecurityException if the caller does not have permission. + * @throws NullPointerException if the caller provided invalid inputs. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, LOCATION_HARDWARE}) + public void getCachedScanData(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<ScanData> resultsCallback) { + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null"); + try { + mService.getCachedScanData(mContext.getPackageName(), + mContext.getAttributionTag(), + new IScanDataListener.Stub() { + @Override + public void onResult(@NonNull ScanData scanData) { + Binder.clearCallingIdentity(); + executor.execute(() -> { + resultsCallback.accept(scanData); + }); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private void startPnoScan(PnoScanListener listener, Executor executor, ScanSettings scanSettings, PnoSettings pnoSettings) { // Set the PNO scan flag. @@ -1854,6 +1895,8 @@ public class WifiScanner { /** @hide */ public static final int CMD_SCAN_RESULT = BASE + 5; /** @hide */ + public static final int CMD_CACHED_SCAN_DATA = BASE + 6; + /** @hide */ public static final int CMD_OP_SUCCEEDED = BASE + 17; /** @hide */ public static final int CMD_OP_FAILED = BASE + 18; diff --git a/framework/java/android/net/wifi/WifiTwtSession.java b/framework/java/android/net/wifi/WifiTwtSession.java new file mode 100644 index 0000000000..0967415d42 --- /dev/null +++ b/framework/java/android/net/wifi/WifiTwtSession.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import android.net.wifi.twt.TwtSession; +import android.os.Binder; +import android.os.Bundle; +import android.util.CloseGuard; +import android.util.Log; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * Implementation of the interface {@link TwtSession} + * + * @hide + */ +public class WifiTwtSession implements TwtSession { + private static final String TAG = "WifiTwtSession"; + public static final int MAX_TWT_SESSIONS = 8; + private final int mWakeDurationMicros; + private final long mWakeIntervalMicros; + private final int mMloLinkId; + private final int mOwner; + private final int mSessionId; + private final WeakReference<WifiManager> mMgr; + private final CloseGuard mCloseGuard = new CloseGuard(); + + @Override + public int getWakeDurationMicros() { + return mWakeDurationMicros; + } + + @Override + public long getWakeIntervalMicros() { + return mWakeIntervalMicros; + } + + @Override + public int getMloLinkId() { + return mMloLinkId; + } + + public int getOwner() { + return mOwner; + } + + public int getSessionId() { + return mSessionId; + } + + @Override + public void getStats(Executor executor, Consumer<Bundle> resultCallback) { + WifiManager mgr = mMgr.get(); + if (mgr == null) { + Log.e(TAG, "getStats: called post garbage collection"); + return; + } + if (Binder.getCallingUid() != mOwner) { + throw new SecurityException("TWT session is not owned by the caller"); + } + mgr.getStatsTwtSession(mSessionId, executor, resultCallback); + } + + public WifiTwtSession(WifiManager wifiManager, int wakeDurationMicros, long wakeIntervalMicros, + int mloLinkId, int owner, int sessionId) { + mMgr = new WeakReference<>(wifiManager); + mWakeDurationMicros = wakeDurationMicros; + mWakeIntervalMicros = wakeIntervalMicros; + mMloLinkId = mloLinkId; + mOwner = owner; + mSessionId = sessionId; + mCloseGuard.open("teardown"); + } + + @Override + public void teardown() { + try { + WifiManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "close: called post garbage collection"); + return; + } + mgr.teardownTwtSession(mSessionId); + mMgr.clear(); + mCloseGuard.close(); + } finally { + Reference.reachabilityFence(this); + } + } +} diff --git a/framework/java/android/net/wifi/WifiUriParser.java b/framework/java/android/net/wifi/WifiUriParser.java new file mode 100644 index 0000000000..926678a314 --- /dev/null +++ b/framework/java/android/net/wifi/WifiUriParser.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.text.TextUtils; + +import androidx.annotation.VisibleForTesting; + +import com.android.wifi.flags.Flags; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Supports to parse 2 types of Wifi Uri + * + * <p>1. Standard Wi-Fi Easy Connect (DPP) bootstrapping information or 2. ZXing reader library's + * Wi-Fi Network config format described in + * https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11 + * + * <p>ZXing reader library's Wi-Fi Network config format example: + * + * <p>WIFI:T:WPA;S:mynetwork;P:mypass;; + * + * <p>parameter Example Description T WPA Authentication type; can be WEP, WPA, SAE or 'nopass' for + * no password. Or, omit for no password. S mynetwork Network SSID. Required. Enclose in double + * quotes if it is an ASCII name, but could be interpreted as hex (i.e. "ABCD") P mypass Password, + * ignored if T is "nopass" (in which case it may be omitted). Enclose in double quotes if it is an + * ASCII name, but could be interpreted as hex (i.e. "ABCD") H true Optional. True if the network + * SSID is hidden. + * @hide + */ +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +@SystemApi +public class WifiUriParser { + static final String TAG = "WifiUriParser"; + static final String SCHEME_DPP = "DPP"; + static final String SCHEME_ZXING_WIFI_NETWORK_CONFIG = "WIFI"; + static final String PREFIX_DPP = "DPP:"; + static final String PREFIX_ZXING_WIFI_NETWORK_CONFIG = "WIFI:"; + + static final String PREFIX_DPP_PUBLIC_KEY = "K:"; + static final String PREFIX_DPP_INFORMATION = "I:"; + + static final String PREFIX_ZXING_SECURITY = "T:"; + static final String PREFIX_ZXING_SSID = "S:"; + static final String PREFIX_ZXING_PASSWORD = "P:"; + static final String PREFIX_ZXING_HIDDEN_SSID = "H:"; + + static final String DELIMITER_QR_CODE = ";"; + + // Ignores password if security is SECURITY_NO_PASSWORD or absent + static final String SECURITY_NO_PASSWORD = "nopass"; // open network or OWE + static final String SECURITY_WEP = "WEP"; + static final String SECURITY_WPA_PSK = "WPA"; + static final String SECURITY_SAE = "SAE"; + + private WifiUriParser() {} + + /** + * Returns parsed result from given uri. + * + * @param uri URI of the configuration that was obtained out of band(QR code scanning, BLE). + * @throws IllegalArgumentException when parse failed. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public static UriParserResults parseUri(@NonNull String uri) { + if (TextUtils.isEmpty(uri)) { + throw new IllegalArgumentException("Empty Wifi Uri"); + } + + if (uri.startsWith(PREFIX_DPP)) { + return parseWifiDppUri(uri); + } else if (uri.startsWith(PREFIX_ZXING_WIFI_NETWORK_CONFIG)) { + return parseZxingWifiUriParser(uri); + } else { + throw new IllegalArgumentException("Unsupport scheme (Not start with " + + PREFIX_DPP + "/" + PREFIX_ZXING_WIFI_NETWORK_CONFIG + ")"); + } + } + + /** Parses Wi-Fi Easy Connect (DPP) Wifi Uri string */ + private static UriParserResults parseWifiDppUri(String uri) throws IllegalArgumentException { + List<String> keyValueList = getKeyValueList(uri, PREFIX_DPP, DELIMITER_QR_CODE); + + String publicKey = getValueOrNull(keyValueList, PREFIX_DPP_PUBLIC_KEY); + if (TextUtils.isEmpty(publicKey)) { + throw new IllegalArgumentException("Invalid format, publicKey is empty"); + } + + String information = getValueOrNull(keyValueList, PREFIX_DPP_INFORMATION); + + return new UriParserResults(UriParserResults.URI_SCHEME_DPP, publicKey, information, null); + } + + /** Parses ZXing reader library's Wi-Fi Network config format */ + private static UriParserResults parseZxingWifiUriParser(String uri) + throws IllegalArgumentException { + List<String> keyValueList = + getKeyValueList(uri, PREFIX_ZXING_WIFI_NETWORK_CONFIG, DELIMITER_QR_CODE); + WifiConfiguration config = null; + String security = getValueOrNull(keyValueList, PREFIX_ZXING_SECURITY); + String ssid = getValueOrNull(keyValueList, PREFIX_ZXING_SSID); + String password = getValueOrNull(keyValueList, PREFIX_ZXING_PASSWORD); + String hiddenSsidString = getValueOrNull(keyValueList, PREFIX_ZXING_HIDDEN_SSID); + boolean hiddenSsid = "true".equalsIgnoreCase(hiddenSsidString); + + // "\", ";", "," and ":" are escaped with a backslash "\", should remove at first + security = removeBackSlash(security); + ssid = removeBackSlash(ssid); + password = removeBackSlash(password); + if (isValidConfig(security, ssid, password)) { + config = generatetWifiConfiguration( + security, ssid, password, hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID); + } + + if (config == null) { + throw new IllegalArgumentException("Invalid format, can't generate WifiConfiguration"); + } + return new UriParserResults(UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG, + null, null, config); + } + + /** + * Splits key/value pairs from uri + * + * @param uri the Wifi Uri raw string + * @param prefixUri the string before all key/value pairs in uri + * @param delimiter the string to split key/value pairs, can't contain a backslash + * @return a list contains string of key/value (e.g. K:key1) + */ + private static List<String> getKeyValueList(String uri, String prefixUri, String delimiter) { + String keyValueString = uri.substring(prefixUri.length()); + + // Should not treat \delimiter as a delimiter + String regex = "(?<!\\\\)" + Pattern.quote(delimiter); + + return Arrays.asList(keyValueString.split(regex)); + } + + private static String getValueOrNull(List<String> keyValueList, String prefix) { + for (String keyValue : keyValueList) { + String strippedKeyValue = keyValue.stripLeading(); + if (strippedKeyValue.startsWith(prefix)) { + return strippedKeyValue.substring(prefix.length()); + } + } + + return null; + } + + @VisibleForTesting + static String removeBackSlash(String input) { + if (input == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + boolean backSlash = false; + for (int i = 0; i < input.length(); i++) { + char ch = input.charAt(i); + if (ch != '\\') { + sb.append(ch); + backSlash = false; + } else { + if (backSlash) { + sb.append(ch); + backSlash = false; + continue; + } + + backSlash = true; + } + } + + return sb.toString(); + } + + private static String addQuotationIfNeeded(String input) { + if (TextUtils.isEmpty(input)) { + return ""; + } + + if (input.length() >= 2 && input.startsWith("\"") && input.endsWith("\"")) { + return input; + } + + StringBuilder sb = new StringBuilder(); + sb.append("\"").append(input).append("\""); + return sb.toString(); + } + + private static boolean isValidConfig(String security, String ssid, String preSharedKey) { + if (!TextUtils.isEmpty(security) && !SECURITY_NO_PASSWORD.equals(security)) { + if (TextUtils.isEmpty(preSharedKey)) { + return false; + } + } + + if (TextUtils.isEmpty(ssid)) { + return false; + } + + return true; + } + + /** + * This is a simplified method from {@code WifiConfigController.getConfig()} + * + * @return WifiConfiguration from parsing result + */ + private static WifiConfiguration generatetWifiConfiguration( + String security, String ssid, String preSharedKey, boolean hiddenSsid, int networkId) { + final WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = addQuotationIfNeeded(ssid); + wifiConfiguration.hiddenSSID = hiddenSsid; + wifiConfiguration.networkId = networkId; + + if (TextUtils.isEmpty(security) || SECURITY_NO_PASSWORD.equals(security)) { + List<SecurityParams> securityParamsList = new ArrayList<>(); + securityParamsList.add( + SecurityParams.createSecurityParamsBySecurityType( + WifiConfiguration.SECURITY_TYPE_OPEN)); + securityParamsList.add( + SecurityParams.createSecurityParamsBySecurityType( + WifiConfiguration.SECURITY_TYPE_OWE)); + wifiConfiguration.setSecurityParams(securityParamsList); + return wifiConfiguration; + } + + if (security.startsWith(SECURITY_WEP)) { + wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP); + + // WEP-40, WEP-104, and 256-bit WEP (WEP-232?) + final int length = preSharedKey.length(); + if ((length == 10 || length == 26 || length == 58) + && preSharedKey.matches("[0-9A-Fa-f]*")) { + wifiConfiguration.wepKeys[0] = preSharedKey; + } else { + wifiConfiguration.wepKeys[0] = addQuotationIfNeeded(preSharedKey); + } + } else if (security.startsWith(SECURITY_WPA_PSK)) { + wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); + + if (preSharedKey.matches("[0-9A-Fa-f]{64}")) { + wifiConfiguration.preSharedKey = preSharedKey; + } else { + wifiConfiguration.preSharedKey = addQuotationIfNeeded(preSharedKey); + } + } else if (security.startsWith(SECURITY_SAE)) { + wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); + if (preSharedKey.length() != 0) { + wifiConfiguration.preSharedKey = addQuotationIfNeeded(preSharedKey); + } + } else { + throw new IllegalArgumentException("Unsupported security"); + } + + return wifiConfiguration; + } +} diff --git a/framework/java/android/net/wifi/WifiUsabilityStatsEntry.java b/framework/java/android/net/wifi/WifiUsabilityStatsEntry.java index e147b500db..435bf4fcfe 100644 --- a/framework/java/android/net/wifi/WifiUsabilityStatsEntry.java +++ b/framework/java/android/net/wifi/WifiUsabilityStatsEntry.java @@ -29,6 +29,8 @@ import android.util.SparseArray; import androidx.annotation.Nullable; +import com.android.wifi.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; @@ -1180,7 +1182,7 @@ public final class WifiUsabilityStatsEntry implements Parcelable { * @return total time CCA is on busy status for the link in ms. * @throws NoSuchElementException if linkId is invalid. */ - @FlaggedApi("com.android.wifi.flags.add_channel_stats_per_link") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public long getTotalCcaBusyFreqTimeMillis(int linkId) { if (mLinkStats.contains(linkId)) return mLinkStats.get(linkId).mTotalCcaBusyFreqTimeMillis; throw new NoSuchElementException("linkId is invalid - " + linkId); @@ -1202,7 +1204,7 @@ public final class WifiUsabilityStatsEntry implements Parcelable { * @return The total radio on time for the link in ms. * @throws NoSuchElementException if linkId is invalid. */ - @FlaggedApi("com.android.wifi.flags.add_channel_stats_per_link") + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public long getTotalRadioOnFreqTimeMillis(int linkId) { if (mLinkStats.contains(linkId)) return mLinkStats.get(linkId).mTotalRadioOnFreqTimeMillis; throw new NoSuchElementException("linkId is invalid - " + linkId); diff --git a/framework/java/android/net/wifi/aware/ConfigRequest.java b/framework/java/android/net/wifi/aware/ConfigRequest.java index c954a86166..decdbeedef 100644 --- a/framework/java/android/net/wifi/aware/ConfigRequest.java +++ b/framework/java/android/net/wifi/aware/ConfigRequest.java @@ -16,10 +16,23 @@ package android.net.wifi.aware; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.RequiresApi; +import android.annotation.SystemApi; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; + import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; /** * Defines a request object to configure a Wi-Fi Aware network. Built using @@ -31,72 +44,98 @@ import java.util.Arrays; * * @hide */ +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +@SystemApi public final class ConfigRequest implements Parcelable { /** * Lower range of possible cluster ID. + * @hide */ public static final int CLUSTER_ID_MIN = 0; /** * Upper range of possible cluster ID. + * @hide */ public static final int CLUSTER_ID_MAX = 0xFFFF; /** * Indices for configuration variables which are specified per band. + * @hide */ public static final int NAN_BAND_24GHZ = 0; + + /** @hide */ public static final int NAN_BAND_5GHZ = 1; + + /** @hide */ public static final int NAN_BAND_6GHZ = 2; /** * Magic values for Discovery Window (DW) interval configuration + * @hide */ public static final int DW_INTERVAL_NOT_INIT = -1; + + /** @hide */ public static final int DW_DISABLE = 0; // only valid for 5GHz /** * Indicates whether 5G band support is requested. + * @hide */ public final boolean mSupport5gBand; /** * Indicates whether 6G band support is requested. + * @hide */ public final boolean mSupport6gBand; /** * Specifies the desired master preference. + * @hide */ public int mMasterPreference; /** - * Specifies the desired lower range of the cluster ID. Must be lower then + * Specifies the desired lower range of the cluster ID. Must be lower than * {@link ConfigRequest#mClusterHigh}. + * @hide */ public final int mClusterLow; /** - * Specifies the desired higher range of the cluster ID. Must be higher then + * Specifies the desired higher range of the cluster ID. Must be higher than * {@link ConfigRequest#mClusterLow}. + * @hide */ public final int mClusterHigh; /** * Specifies the discovery window interval for the device on NAN_BAND_*. + * @hide */ public final int mDiscoveryWindowInterval[]; + /** + * List of {@link OuiKeyedData} providing vendor-specific configuration data. + */ + private final List<OuiKeyedData> mVendorData; + private ConfigRequest(boolean support5gBand, boolean support6gBand, int masterPreference, - int clusterLow, int clusterHigh, int[] discoveryWindowInterval) { + int clusterLow, int clusterHigh, int[] discoveryWindowInterval, + @NonNull List<OuiKeyedData> vendorData) { mSupport5gBand = support5gBand; mSupport6gBand = support6gBand; mMasterPreference = masterPreference; mClusterLow = clusterLow; mClusterHigh = clusterHigh; mDiscoveryWindowInterval = discoveryWindowInterval; + mVendorData = vendorData; } + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public String toString() { return "ConfigRequest [mSupport5gBand=" + mSupport5gBand @@ -104,24 +143,30 @@ public final class ConfigRequest implements Parcelable { + ", mMasterPreference=" + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh=" + mClusterHigh - + ", mDiscoveryWindowInterval=" + Arrays.toString(mDiscoveryWindowInterval) + "]"; + + ", mDiscoveryWindowInterval=" + Arrays.toString(mDiscoveryWindowInterval) + + ", mVendorData=" + mVendorData + + "]"; } + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public int describeContents() { return 0; } + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSupport5gBand ? 1 : 0); dest.writeInt(mSupport6gBand ? 1 : 0); dest.writeInt(mMasterPreference); dest.writeInt(mClusterLow); dest.writeInt(mClusterHigh); dest.writeIntArray(mDiscoveryWindowInterval); + dest.writeList(mVendorData); } + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public static final @android.annotation.NonNull Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() { @Override public ConfigRequest[] newArray(int size) { @@ -136,12 +181,14 @@ public final class ConfigRequest implements Parcelable { int clusterLow = in.readInt(); int clusterHigh = in.readInt(); int discoveryWindowInterval[] = in.createIntArray(); + List<OuiKeyedData> vendorData = ParcelUtil.readOuiKeyedDataList(in); return new ConfigRequest(support5gBand, support6gBand, masterPreference, clusterLow, - clusterHigh, discoveryWindowInterval); + clusterHigh, discoveryWindowInterval, vendorData); } }; + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public boolean equals(Object o) { if (this == o) { @@ -158,9 +205,11 @@ public final class ConfigRequest implements Parcelable { && mSupport6gBand == lhs.mSupport6gBand && mMasterPreference == lhs.mMasterPreference && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh - && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval); + && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval) + && Objects.equals(mVendorData, lhs.mVendorData); } + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) @Override public int hashCode() { int result = 17; @@ -171,6 +220,7 @@ public final class ConfigRequest implements Parcelable { result = 31 * result + mClusterLow; result = 31 * result + mClusterHigh; result = 31 * result + Arrays.hashCode(mDiscoveryWindowInterval); + result = 31 * result + mVendorData.hashCode(); return result; } @@ -178,6 +228,7 @@ public final class ConfigRequest implements Parcelable { /** * Verifies that the contents of the ConfigRequest are valid. Otherwise * throws an IllegalArgumentException. + * @hide */ public void validate() throws IllegalArgumentException { if (mMasterPreference < 0) { @@ -226,11 +277,33 @@ public final class ConfigRequest implements Parcelable { throw new IllegalArgumentException( "Invalid discovery window interval for 6GHz: valid is UNSET or [0,5]"); } + if (mVendorData == null) { + throw new IllegalArgumentException("Vendor data list must be non-null"); + } + } + + /** + * Get the vendor-provided configuration data, if it exists. See {@link + * Builder#setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData != null ? mVendorData : Collections.emptyList(); } /** * Builder used to build {@link ConfigRequest} objects. */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public static final class Builder { private boolean mSupport5gBand = true; private boolean mSupport6gBand = false; @@ -239,6 +312,7 @@ public final class ConfigRequest implements Parcelable { private int mClusterHigh = CLUSTER_ID_MAX; private int[] mDiscoveryWindowInterval = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT}; + private List<OuiKeyedData> mVendorData = Collections.emptyList(); /** * Specify whether 5G band support is required in this request. Disabled by default. @@ -247,6 +321,7 @@ public final class ConfigRequest implements Parcelable { * * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. + * @hide */ public Builder setSupport5gBand(boolean support5gBand) { mSupport5gBand = support5gBand; @@ -260,6 +335,7 @@ public final class ConfigRequest implements Parcelable { * * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. + * @hide */ public Builder setSupport6gBand(boolean support6gBand) { mSupport6gBand = support6gBand; @@ -274,6 +350,7 @@ public final class ConfigRequest implements Parcelable { * * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. + * @hide */ public Builder setMasterPreference(int masterPreference) { if (masterPreference < 0) { @@ -301,6 +378,7 @@ public final class ConfigRequest implements Parcelable { * * @return The builder to facilitate chaining * {@code builder.setClusterLow(..).setClusterHigh(..)}. + * @hide */ public Builder setClusterLow(int clusterLow) { if (clusterLow < CLUSTER_ID_MIN) { @@ -326,6 +404,7 @@ public final class ConfigRequest implements Parcelable { * * @return The builder to facilitate chaining * {@code builder.setClusterLow(..).setClusterHigh(..)}. + * @hide */ public Builder setClusterHigh(int clusterHigh) { if (clusterHigh < CLUSTER_ID_MIN) { @@ -352,6 +431,7 @@ public final class ConfigRequest implements Parcelable { * * @return The builder itself to facilitate chaining operations * {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}. + * @hide */ public Builder setDiscoveryWindowInterval(int band, int interval) { if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ && band != NAN_BAND_6GHZ) { @@ -369,9 +449,35 @@ public final class ConfigRequest implements Parcelable { } /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + * @return Builder for chaining. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + return this; + } + + /** * Build {@link ConfigRequest} given the current requests made on the * builder. */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull public ConfigRequest build() { if (mClusterLow > mClusterHigh) { throw new IllegalArgumentException( @@ -379,7 +485,7 @@ public final class ConfigRequest implements Parcelable { } return new ConfigRequest(mSupport5gBand, mSupport6gBand, mMasterPreference, mClusterLow, - mClusterHigh, mDiscoveryWindowInterval); + mClusterHigh, mDiscoveryWindowInterval, mVendorData); } } } diff --git a/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl b/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl index 2ab88b3535..392ec6cc2e 100644 --- a/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl +++ b/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl @@ -17,6 +17,7 @@ package android.net.wifi.aware; import android.net.wifi.aware.AwarePairingConfig; +import android.net.wifi.OuiKeyedData; /** * Callback interface that WifiAwareManager implements @@ -36,10 +37,10 @@ oneway interface IWifiAwareDiscoverySessionCallback void onMatch(int peerId, in byte[] serviceSpecificInfo, in byte[] matchFilter, int peerCipherSuite, in byte[] scid, String pairingAlias, - in AwarePairingConfig pairingConfig); + in AwarePairingConfig pairingConfig, in OuiKeyedData[] vendorData); void onMatchWithDistance(int peerId, in byte[] serviceSpecificInfo, in byte[] matchFilter, int distanceMm, int peerCipherSuite, in byte[] scid, String pairingAlias, - in AwarePairingConfig pairingConfig); + in AwarePairingConfig pairingConfig, in OuiKeyedData[] vendorData); void onMessageSendSuccess(int messageId); void onMessageSendFail(int messageId, int reason); diff --git a/framework/java/android/net/wifi/aware/PublishConfig.java b/framework/java/android/net/wifi/aware/PublishConfig.java index 3f82aed5a2..aa43cdbb99 100644 --- a/framework/java/android/net/wifi/aware/PublishConfig.java +++ b/framework/java/android/net/wifi/aware/PublishConfig.java @@ -18,11 +18,14 @@ package android.net.wifi.aware; import static android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; import android.net.wifi.ScanResult; import android.net.wifi.WifiScanner; import android.net.wifi.util.HexEncoding; @@ -33,11 +36,13 @@ import android.os.Parcelable; import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -104,12 +109,15 @@ public final class PublishConfig implements Parcelable { private final boolean mIsSuspendable; + private final List<OuiKeyedData> mVendorData; + /** @hide */ public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, int publishType, int ttlSec, boolean enableTerminateNotification, boolean enableRanging, boolean enableInstantMode, @WifiScanner.WifiBand int band, WifiAwareDataPathSecurityConfig securityConfig, - AwarePairingConfig pairingConfig, boolean isSuspendable) { + AwarePairingConfig pairingConfig, boolean isSuspendable, + @NonNull List<OuiKeyedData> vendorData) { mServiceName = serviceName; mServiceSpecificInfo = serviceSpecificInfo; mMatchFilter = matchFilter; @@ -122,6 +130,7 @@ public final class PublishConfig implements Parcelable { mSecurityConfig = securityConfig; mPairingConfig = pairingConfig; mIsSuspendable = isSuspendable; + mVendorData = vendorData; } @Override @@ -142,7 +151,8 @@ public final class PublishConfig implements Parcelable { + ", mBand=" + mBand + ", mSecurityConfig" + mSecurityConfig + ", mPairingConfig" + mPairingConfig - + ", mIsSuspendable=" + mIsSuspendable; + + ", mIsSuspendable=" + mIsSuspendable + + ", mVendorData=" + mVendorData + "]"; } @Override @@ -164,6 +174,7 @@ public final class PublishConfig implements Parcelable { dest.writeParcelable(mSecurityConfig, flags); dest.writeParcelable(mPairingConfig, flags); dest.writeBoolean(mIsSuspendable); + dest.writeList(mVendorData); } @NonNull @@ -189,10 +200,11 @@ public final class PublishConfig implements Parcelable { AwarePairingConfig pairingConfig = in .readParcelable(AwarePairingConfig.class.getClassLoader()); boolean isSuspendable = in.readBoolean(); + List<OuiKeyedData> vendorData = ParcelUtil.readOuiKeyedDataList(in); return new PublishConfig(serviceName, ssi, matchFilter, publishType, ttlSec, enableTerminateNotification, enableRanging, enableInstantMode, - band, securityConfig, pairingConfig, isSuspendable); + band, securityConfig, pairingConfig, isSuspendable, vendorData); } }; @@ -218,7 +230,8 @@ public final class PublishConfig implements Parcelable { && mBand == lhs.mBand && mIsSuspendable == lhs.mIsSuspendable && Objects.equals(mSecurityConfig, lhs.mSecurityConfig) - && Objects.equals(mPairingConfig, lhs.mPairingConfig); + && Objects.equals(mPairingConfig, lhs.mPairingConfig) + && Objects.equals(mVendorData, lhs.mVendorData); } @Override @@ -226,7 +239,7 @@ public final class PublishConfig implements Parcelable { return Objects.hash(Arrays.hashCode(mServiceName), Arrays.hashCode(mServiceSpecificInfo), Arrays.hashCode(mMatchFilter), mPublishType, mTtlSec, mEnableTerminateNotification, mEnableRanging, mEnableInstantMode, mBand, mSecurityConfig, mPairingConfig, - mIsSuspendable); + mIsSuspendable, mVendorData); } /** @@ -353,6 +366,24 @@ public final class PublishConfig implements Parcelable { } /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * Builder#setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData != null ? mVendorData : Collections.emptyList(); + } + + /** * Builder used to build {@link PublishConfig} objects. */ public static final class Builder { @@ -368,6 +399,7 @@ public final class PublishConfig implements Parcelable { private WifiAwareDataPathSecurityConfig mSecurityConfig = null; private AwarePairingConfig mPairingConfig = null; private boolean mIsSuspendable = false; + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); /** * Specify the service name of the publish session. The actual on-air @@ -630,13 +662,36 @@ public final class PublishConfig implements Parcelable { } /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided + * configuration data. Note that multiple elements with the same OUI are allowed. + * @return Builder for chaining. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + return this; + } + + /** * Build {@link PublishConfig} given the current requests made on the * builder. */ public PublishConfig build() { return new PublishConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, mPublishType, mTtlSec, mEnableTerminateNotification, mEnableRanging, mEnableInstantMode, - mBand, mSecurityConfig, mPairingConfig, mIsSuspendable); + mBand, mSecurityConfig, mPairingConfig, mIsSuspendable, mVendorData); } } } diff --git a/framework/java/android/net/wifi/aware/ServiceDiscoveryInfo.java b/framework/java/android/net/wifi/aware/ServiceDiscoveryInfo.java index 48b9a2b0bf..6b2191c550 100644 --- a/framework/java/android/net/wifi/aware/ServiceDiscoveryInfo.java +++ b/framework/java/android/net/wifi/aware/ServiceDiscoveryInfo.java @@ -16,9 +16,19 @@ package android.net.wifi.aware; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresApi; +import android.annotation.SystemApi; +import android.net.wifi.OuiKeyedData; +import android.os.Build; +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; + +import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -34,6 +44,7 @@ public final class ServiceDiscoveryInfo { private final PeerHandle mPeerHandle; private final String mPairingAlias; private final AwarePairingConfig mPairingConfig; + private final List<OuiKeyedData> mVendorData; /** * @hide @@ -41,7 +52,7 @@ public final class ServiceDiscoveryInfo { public ServiceDiscoveryInfo(PeerHandle peerHandle, int peerCipherSuite, @Nullable byte[] serviceSpecificInfo, @NonNull List<byte[]> matchFilter, @Nullable byte[] scid, String pairingAlias, - AwarePairingConfig pairingConfig) { + AwarePairingConfig pairingConfig, @Nullable OuiKeyedData[] vendorData) { mServiceSpecificInfo = serviceSpecificInfo; mMatchFilters = matchFilter; mPeerCipherSuite = peerCipherSuite; @@ -49,6 +60,7 @@ public final class ServiceDiscoveryInfo { mPeerHandle = peerHandle; mPairingAlias = pairingAlias; mPairingConfig = pairingConfig; + mVendorData = vendorData != null ? Arrays.asList(vendorData) : Collections.emptyList(); } /** @@ -130,4 +142,21 @@ public final class ServiceDiscoveryInfo { public AwarePairingConfig getPairingConfig() { return mPairingConfig; } + + /** + * Get the vendor-provided configuration data, if it exists. + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData != null ? mVendorData : Collections.emptyList(); + } } diff --git a/framework/java/android/net/wifi/aware/SubscribeConfig.java b/framework/java/android/net/wifi/aware/SubscribeConfig.java index 1fc29521fb..ea99d819cd 100644 --- a/framework/java/android/net/wifi/aware/SubscribeConfig.java +++ b/framework/java/android/net/wifi/aware/SubscribeConfig.java @@ -18,11 +18,14 @@ package android.net.wifi.aware; import static android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; import android.net.wifi.ScanResult; import android.net.wifi.WifiScanner; import android.net.wifi.util.HexEncoding; @@ -33,11 +36,13 @@ import android.os.Parcelable; import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -108,13 +113,15 @@ public final class SubscribeConfig implements Parcelable { private final AwarePairingConfig mPairingConfig; private final boolean mIsSuspendable; + private final List<OuiKeyedData> mVendorData; /** @hide */ public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, int subscribeType, int ttlSec, boolean enableTerminateNotification, boolean minDistanceMmSet, int minDistanceMm, boolean maxDistanceMmSet, int maxDistanceMm, boolean enableInstantMode, @WifiScanner.WifiBand int band, - AwarePairingConfig pairingConfig, boolean isSuspendable) { + AwarePairingConfig pairingConfig, boolean isSuspendable, + @NonNull List<OuiKeyedData> vendorData) { mServiceName = serviceName; mServiceSpecificInfo = serviceSpecificInfo; mMatchFilter = matchFilter; @@ -129,6 +136,7 @@ public final class SubscribeConfig implements Parcelable { mBand = band; mPairingConfig = pairingConfig; mIsSuspendable = isSuspendable; + mVendorData = vendorData; } @Override @@ -151,7 +159,8 @@ public final class SubscribeConfig implements Parcelable { + ", mEnableInstantMode=" + mEnableInstantMode + ", mBand=" + mBand + ", mPairingConfig" + mPairingConfig - + ", mIsSuspendable=" + mIsSuspendable; + + ", mIsSuspendable=" + mIsSuspendable + + ", mVendorData=" + mVendorData + "]"; } @Override @@ -175,6 +184,7 @@ public final class SubscribeConfig implements Parcelable { dest.writeInt(mBand); dest.writeParcelable(mPairingConfig, flags); dest.writeBoolean(mIsSuspendable); + dest.writeList(mVendorData); } @NonNull @@ -201,10 +211,12 @@ public final class SubscribeConfig implements Parcelable { AwarePairingConfig pairingConfig = in.readParcelable( AwarePairingConfig.class.getClassLoader()); boolean isSuspendable = in.readBoolean(); + List<OuiKeyedData> vendorData = ParcelUtil.readOuiKeyedDataList(in); return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType, ttlSec, enableTerminateNotification, minDistanceMmSet, minDistanceMm, maxDistanceMmSet, - maxDistanceMm, enableInstantMode, band, pairingConfig, isSuspendable); + maxDistanceMm, enableInstantMode, band, pairingConfig, isSuspendable, + vendorData); } }; @@ -228,7 +240,8 @@ public final class SubscribeConfig implements Parcelable { && mMaxDistanceMmSet == lhs.mMaxDistanceMmSet && mEnableInstantMode == lhs.mEnableInstantMode && mBand == lhs.mBand - && mIsSuspendable == lhs.mIsSuspendable)) { + && mIsSuspendable == lhs.mIsSuspendable + && Objects.equals(mVendorData, lhs.mVendorData))) { return false; } @@ -248,7 +261,7 @@ public final class SubscribeConfig implements Parcelable { int result = Objects.hash(Arrays.hashCode(mServiceName), Arrays.hashCode(mServiceSpecificInfo), Arrays.hashCode(mMatchFilter), mSubscribeType, mTtlSec, mEnableTerminateNotification, mMinDistanceMmSet, - mMaxDistanceMmSet, mEnableInstantMode, mBand, mIsSuspendable); + mMaxDistanceMmSet, mEnableInstantMode, mBand, mIsSuspendable, mVendorData); if (mMinDistanceMmSet) { result = Objects.hash(result, mMinDistanceMm); @@ -378,6 +391,24 @@ public final class SubscribeConfig implements Parcelable { } /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * Builder#setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData != null ? mVendorData : Collections.emptyList(); + } + + /** * Builder used to build {@link SubscribeConfig} objects. */ public static final class Builder { @@ -395,6 +426,7 @@ public final class SubscribeConfig implements Parcelable { private int mBand = WifiScanner.WIFI_BAND_24_GHZ; private AwarePairingConfig mPairingConfig; private boolean mIsSuspendable = false; + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); /** * Specify the service name of the subscribe session. The actual on-air @@ -669,6 +701,29 @@ public final class SubscribeConfig implements Parcelable { } /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided + * configuration data. Note that multiple elements with the same OUI are allowed. + * @return Builder for chaining. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + return this; + } + + /** * Build {@link SubscribeConfig} given the current requests made on the * builder. */ @@ -676,7 +731,7 @@ public final class SubscribeConfig implements Parcelable { return new SubscribeConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, mSubscribeType, mTtlSec, mEnableTerminateNotification, mMinDistanceMmSet, mMinDistanceMm, mMaxDistanceMmSet, mMaxDistanceMm, - mEnableInstantMode, mBand, mPairingConfig, mIsSuspendable); + mEnableInstantMode, mBand, mPairingConfig, mIsSuspendable, mVendorData); } } } diff --git a/framework/java/android/net/wifi/aware/WifiAwareManager.java b/framework/java/android/net/wifi/aware/WifiAwareManager.java index 74551f0d32..2edf792b16 100644 --- a/framework/java/android/net/wifi/aware/WifiAwareManager.java +++ b/framework/java/android/net/wifi/aware/WifiAwareManager.java @@ -19,12 +19,14 @@ package android.net.wifi.aware; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.ACCESS_WIFI_STATE; import static android.Manifest.permission.CHANGE_WIFI_STATE; +import static android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION; import static android.Manifest.permission.NEARBY_WIFI_DEVICES; import static android.Manifest.permission.OVERRIDE_WIFI_CONFIG; import static android.net.wifi.ScanResult.WIFI_BAND_24_GHZ; import static android.net.wifi.ScanResult.WIFI_BAND_5_GHZ; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -41,6 +43,7 @@ import android.net.NetworkSpecifier; import android.net.wifi.IBooleanListener; import android.net.wifi.IIntegerListener; import android.net.wifi.IListListener; +import android.net.wifi.OuiKeyedData; import android.net.wifi.WifiManager; import android.net.wifi.util.HexEncoding; import android.os.Binder; @@ -55,6 +58,7 @@ import androidx.annotation.RequiresApi; import com.android.modules.utils.HandlerExecutor; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -518,6 +522,40 @@ public class WifiAwareManager { attach(handler, null, attachCallback, identityChangedListener, false, null); } + /** + * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or + * create connections to peers. See {@link #attach(AttachCallback, IdentityChangedListener, + * Handler)} for more information. + * + * This version allows callers to provide an instance of {@link ConfigRequest}. + * + * @param configRequest Parameters for this request. + * @param executor The executor to execute the listener of the {@code attachCallback} object. + * @param attachCallback A callback for attach events, extended from {@link AttachCallback}. + * @param identityChangedListener A callback for changed identity or cluster ID, extended from + * {@link IdentityChangedListener}. + * @hide + */ + @RequiresPermission(allOf = { + ACCESS_WIFI_STATE, + CHANGE_WIFI_STATE, + ACCESS_FINE_LOCATION, + NEARBY_WIFI_DEVICES, + MANAGE_WIFI_NETWORK_SELECTION}, conditional = true) + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void attach(@NonNull ConfigRequest configRequest, + @NonNull @CallbackExecutor Executor executor, @NonNull AttachCallback attachCallback, + @NonNull IdentityChangedListener identityChangedListener) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + Objects.requireNonNull(configRequest); + Objects.requireNonNull(executor); + attach(null, configRequest, attachCallback, identityChangedListener, false, executor); + } + /** @hide */ public void attach(Handler handler, ConfigRequest configRequest, AttachCallback attachCallback, @@ -1068,7 +1106,7 @@ public class WifiAwareManager { @Override public void onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, int peerCipherSuite, byte[] scid, String pairingAlias, - AwarePairingConfig pairingConfig) { + AwarePairingConfig pairingConfig, @Nullable OuiKeyedData[] vendorData) { if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); mHandler.post(() -> { @@ -1078,7 +1116,7 @@ public class WifiAwareManager { mOriginalCallback.onServiceDiscovered( new ServiceDiscoveryInfo(new PeerHandle(peerId), peerCipherSuite, serviceSpecificInfo, matchFilterList, scid, pairingAlias, - pairingConfig)); + pairingConfig, vendorData)); }); } @@ -1098,7 +1136,7 @@ public class WifiAwareManager { @Override public void onMatchWithDistance(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, int distanceMm, int peerCipherSuite, byte[] scid, String pairingAlias, - AwarePairingConfig pairingConfig) { + AwarePairingConfig pairingConfig, @Nullable OuiKeyedData[] vendorData) { if (VDBG) { Log.v(TAG, "onMatchWithDistance: peerId=" + peerId + ", distanceMm=" + distanceMm); } @@ -1116,7 +1154,8 @@ public class WifiAwareManager { matchFilterList, scid, pairingAlias, - pairingConfig), + pairingConfig, + vendorData), distanceMm); }); } diff --git a/framework/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java b/framework/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java index 7ad74d09c5..d98afbfa30 100644 --- a/framework/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java +++ b/framework/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java @@ -424,7 +424,7 @@ public final class PpsMoParser { try { config = parsePpsNode(child); } catch (ParsingException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); return null; } break; diff --git a/framework/java/android/net/wifi/p2p/IWifiP2pListener.aidl b/framework/java/android/net/wifi/p2p/IWifiP2pListener.aidl new file mode 100644 index 0000000000..084050be42 --- /dev/null +++ b/framework/java/android/net/wifi/p2p/IWifiP2pListener.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 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 android.net.wifi.p2p; + +import android.net.wifi.p2p.WifiP2pDevice; +import android.net.wifi.p2p.WifiP2pDeviceList; +import android.net.wifi.p2p.WifiP2pInfo; +import android.net.wifi.p2p.WifiP2pGroup; +import android.net.wifi.p2p.WifiP2pGroupList; + +/** + * Interface for Wi-Fi p2p listener. + * @hide + */ +oneway interface IWifiP2pListener +{ + void onP2pStateChanged(int state); + void onDiscoveryStateChanged(int state); + void onListenStateChanged(int state); + void onDeviceConfigurationChanged(in WifiP2pDevice p2pDevice); + void onPeerListChanged(in WifiP2pDeviceList p2pDeviceList); + void onPersistentGroupsChanged(in WifiP2pGroupList p2pGroupList); + void onGroupCreating(); + void onGroupNegotiationRejectedByUser(); + void onGroupCreationFailed(int reason); + void onGroupCreated(in WifiP2pInfo p2pInfo, in WifiP2pGroup p2pGroup); + void onPeerClientJoined(in WifiP2pInfo p2pInfo, in WifiP2pGroup p2pGroup); + void onPeerClientDisconnected(in WifiP2pInfo p2pInfo, in WifiP2pGroup p2pGroup); + void onFrequencyChanged(in WifiP2pInfo p2pInfo, in WifiP2pGroup p2pGroup); + void onGroupRemoved(); +} diff --git a/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl index f29a9b3c3a..088ead4927 100644 --- a/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -16,6 +16,8 @@ package android.net.wifi.p2p; +import android.net.wifi.p2p.IWifiP2pListener; + import android.os.Bundle; import android.os.Messenger; @@ -32,5 +34,7 @@ interface IWifiP2pManager void setMiracastMode(int mode); void checkConfigureWifiDisplayPermission(); long getSupportedFeatures(); + void registerWifiP2pListener(in IWifiP2pListener listener, in String packageName, in Bundle extras); + void unregisterWifiP2pListener(in IWifiP2pListener listener); } diff --git a/framework/java/android/net/wifi/p2p/WifiP2pConfig.java b/framework/java/android/net/wifi/p2p/WifiP2pConfig.java index 895773223c..d2775fee1b 100644 --- a/framework/java/android/net/wifi/p2p/WifiP2pConfig.java +++ b/framework/java/android/net/wifi/p2p/WifiP2pConfig.java @@ -16,6 +16,7 @@ package android.net.wifi.p2p; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -23,6 +24,8 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; import android.net.wifi.WpsInfo; import android.os.Build; import android.os.Parcel; @@ -32,10 +35,14 @@ import android.text.TextUtils; import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.regex.PatternSyntaxException; /** @@ -194,6 +201,48 @@ public class WifiP2pConfig implements Parcelable { return netId; } + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); + + /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = new ArrayList<>(vendorData); + } + + /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * #setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + public WifiP2pConfig() { //set defaults wps = new WpsInfo(); @@ -269,6 +318,7 @@ public class WifiP2pConfig implements Parcelable { sbuf.append("\n groupOwnerBand: ").append(groupOwnerBand); sbuf.append("\n groupClientIpProvisioningMode: ").append(mGroupClientIpProvisioningMode); sbuf.append("\n joinExistingGroup: ").append(mJoinExistingGroup); + sbuf.append("\n vendorData: ").append(mVendorData); return sbuf.toString(); } @@ -289,6 +339,7 @@ public class WifiP2pConfig implements Parcelable { groupOwnerBand = source.groupOwnerBand; mGroupClientIpProvisioningMode = source.mGroupClientIpProvisioningMode; mJoinExistingGroup = source.mJoinExistingGroup; + mVendorData = new ArrayList<>(source.mVendorData); } } @@ -303,6 +354,7 @@ public class WifiP2pConfig implements Parcelable { dest.writeInt(groupOwnerBand); dest.writeInt(mGroupClientIpProvisioningMode); dest.writeBoolean(mJoinExistingGroup); + dest.writeList(mVendorData); } /** Implement the Parcelable interface */ @@ -320,6 +372,7 @@ public class WifiP2pConfig implements Parcelable { config.groupOwnerBand = in.readInt(); config.mGroupClientIpProvisioningMode = in.readInt(); config.mJoinExistingGroup = in.readBoolean(); + config.mVendorData = ParcelUtil.readOuiKeyedDataList(in); return config; } diff --git a/framework/java/android/net/wifi/p2p/WifiP2pDevice.java b/framework/java/android/net/wifi/p2p/WifiP2pDevice.java index 214eb35a0d..75ae83d286 100644 --- a/framework/java/android/net/wifi/p2p/WifiP2pDevice.java +++ b/framework/java/android/net/wifi/p2p/WifiP2pDevice.java @@ -16,17 +16,27 @@ package android.net.wifi.p2p; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; import android.net.wifi.ScanResult; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import androidx.annotation.RequiresApi; + import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -53,6 +63,15 @@ public class WifiP2pDevice implements Parcelable { * The device MAC address uniquely identifies a Wi-Fi p2p device */ public String deviceAddress = ""; + /** + * The device interface MAC address. This field is valid when the device is a part of the group + */ + @Nullable private MacAddress mInterfaceMacAddress; + + /** + * The IP address of the device. This field is valid when the device is a part of the group. + */ + @Nullable private InetAddress mIpAddress; /** * Primary device type identifies the type of device. For example, an application @@ -175,6 +194,26 @@ public class WifiP2pDevice implements Parcelable { "(?:[0-9a-f]{2}:){5}[0-9a-f]{2} p2p_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})" ); + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); + + /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * #setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } public WifiP2pDevice() { } @@ -325,6 +364,7 @@ public class WifiP2pDevice implements Parcelable { if (!deviceAddress.equals(device.deviceAddress)) { throw new IllegalArgumentException("deviceAddress does not match"); } + mInterfaceMacAddress = device.mInterfaceMacAddress; deviceName = device.deviceName; primaryDeviceType = device.primaryDeviceType; secondaryDeviceType = device.secondaryDeviceType; @@ -348,6 +388,27 @@ public class WifiP2pDevice implements Parcelable { } /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + } + + /** * Get the vendor-specific information elements received as part of the discovery * of the peer device. * @@ -360,6 +421,52 @@ public class WifiP2pDevice implements Parcelable { return new ArrayList<>(mVendorElements); } + /** + * Get the device interface MAC address if the device is a part of the group; otherwise null. + * + * @return the interface MAC address if the device is a part of the group; otherwise null. + * @hide + */ + @Nullable public MacAddress getInterfaceMacAddress() { + return mInterfaceMacAddress; + } + + /** + * Set the device interface MAC address. + * @hide + */ + public void setInterfaceMacAddress(@Nullable MacAddress interfaceAddress) { + mInterfaceMacAddress = interfaceAddress; + } + + /** + * Get the IP address of the connected client device. + * The application should listen to {@link WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION} + * broadcast to obtain the IP address of the connected client. When system assigns the IP + * address, the connected P2P device information ({@link WifiP2pGroup#getClientList()}) in the + * group is updated with the IP address and broadcast the group information using + * {@link WifiP2pManager#EXTRA_WIFI_P2P_GROUP} extra of the + * {@link WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION} broadcast intent. + * + * Alternatively, the application can request for the group details with + * {@link WifiP2pManager#requestGroupInfo} and use ({@link WifiP2pGroup#getClientList()}) to + * obtain the connected client details. + * + * @return the IP address if the device is a part of the group; otherwise null. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Nullable public InetAddress getIpAddress() { + return mIpAddress; + } + + /** + * Set the IP address of the device. + * @hide + */ + public void setIpAddress(InetAddress ipAddress) { + mIpAddress = ipAddress; + } + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -382,6 +489,10 @@ public class WifiP2pDevice implements Parcelable { StringBuffer sbuf = new StringBuffer(); sbuf.append("Device: ").append(deviceName); sbuf.append("\n deviceAddress: ").append(deviceAddress); + sbuf.append("\n interfaceMacAddress: ") + .append(mInterfaceMacAddress == null ? "none" : mInterfaceMacAddress.toString()); + sbuf.append("\n ipAddress: ") + .append(mIpAddress == null ? "none" : mIpAddress.getHostAddress()); sbuf.append("\n primary type: ").append(primaryDeviceType); sbuf.append("\n secondary type: ").append(secondaryDeviceType); sbuf.append("\n wps: ").append(wpsConfigMethodsSupported); @@ -390,6 +501,7 @@ public class WifiP2pDevice implements Parcelable { sbuf.append("\n status: ").append(status); sbuf.append("\n wfdInfo: ").append(wfdInfo); sbuf.append("\n vendorElements: ").append(mVendorElements); + sbuf.append("\n vendorData: ").append(mVendorData); return sbuf.toString(); } @@ -404,6 +516,8 @@ public class WifiP2pDevice implements Parcelable { if (source != null) { deviceName = source.deviceName; deviceAddress = source.deviceAddress; + mInterfaceMacAddress = source.mInterfaceMacAddress; + mIpAddress = source.mIpAddress; primaryDeviceType = source.primaryDeviceType; secondaryDeviceType = source.secondaryDeviceType; wpsConfigMethodsSupported = source.wpsConfigMethodsSupported; @@ -416,6 +530,7 @@ public class WifiP2pDevice implements Parcelable { if (null != source.mVendorElements) { mVendorElements = new ArrayList<>(source.mVendorElements); } + mVendorData = new ArrayList<>(source.mVendorData); } } @@ -424,6 +539,13 @@ public class WifiP2pDevice implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(deviceName); dest.writeString(deviceAddress); + dest.writeParcelable(mInterfaceMacAddress, flags); + if (mIpAddress != null) { + dest.writeByte((byte) 1); + dest.writeByteArray(mIpAddress.getAddress()); + } else { + dest.writeByte((byte) 0); + } dest.writeString(primaryDeviceType); dest.writeString(secondaryDeviceType); dest.writeInt(wpsConfigMethodsSupported); @@ -437,6 +559,7 @@ public class WifiP2pDevice implements Parcelable { dest.writeInt(0); } dest.writeTypedList(mVendorElements); + dest.writeList(mVendorData); } /** Implement the Parcelable interface */ @@ -447,6 +570,15 @@ public class WifiP2pDevice implements Parcelable { WifiP2pDevice device = new WifiP2pDevice(); device.deviceName = in.readString(); device.deviceAddress = in.readString(); + device.mInterfaceMacAddress = in.readParcelable(MacAddress.class.getClassLoader()); + if (in.readByte() == 1) { + try { + device.mIpAddress = InetAddress.getByAddress(in.createByteArray()); + } catch (UnknownHostException e) { + e.printStackTrace(); + return new WifiP2pDevice(); + } + } device.primaryDeviceType = in.readString(); device.secondaryDeviceType = in.readString(); device.wpsConfigMethodsSupported = in.readInt(); @@ -458,6 +590,7 @@ public class WifiP2pDevice implements Parcelable { } device.mVendorElements = in.createTypedArrayList( ScanResult.InformationElement.CREATOR); + device.mVendorData = ParcelUtil.readOuiKeyedDataList(in); return device; } diff --git a/framework/java/android/net/wifi/p2p/WifiP2pDiscoveryConfig.java b/framework/java/android/net/wifi/p2p/WifiP2pDiscoveryConfig.java new file mode 100644 index 0000000000..bb84006c72 --- /dev/null +++ b/framework/java/android/net/wifi/p2p/WifiP2pDiscoveryConfig.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2023 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 android.net.wifi.p2p; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.RequiresApi; +import android.annotation.SystemApi; +import android.net.wifi.OuiKeyedData; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; + +import java.util.ArrayList; +import java.util.List; + +/** + * A class representing a Wi-Fi P2P scan configuration for setting up discovery. + */ +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +public final class WifiP2pDiscoveryConfig implements Parcelable { + /** Type of this P2P scan. */ + private final @WifiP2pManager.WifiP2pScanType int mScanType; + + /** Frequency to scan in MHz. */ + private final int mFrequencyMhz; + + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private final @NonNull List<OuiKeyedData> mVendorData; + + private WifiP2pDiscoveryConfig(@WifiP2pManager.WifiP2pScanType int scanType, int frequencyMhz, + @NonNull List<OuiKeyedData> vendorData) { + mScanType = scanType; + mFrequencyMhz = frequencyMhz; + mVendorData = new ArrayList<>(vendorData); + } + + /** + * Get the type of this scan. See {@link Builder#Builder(int)}} + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public @WifiP2pManager.WifiP2pScanType int getScanType() { + return mScanType; + } + + /** + * Get the frequency to scan in MHz. See {@link Builder#setFrequencyMhz(int)} + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int getFrequencyMhz() { + return mFrequencyMhz; + } + + /** + * Get the vendor-provided configuration data, if it exists. See {@link + * Builder#setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + public String toString() { + StringBuffer sbuf = new StringBuffer(); + sbuf.append("\n scanType: ").append(mScanType); + sbuf.append("\n frequencyMhz: ").append(mFrequencyMhz); + sbuf.append("\n vendorData: ").append(mVendorData); + return sbuf.toString(); + } + + /** Implement the Parcelable interface */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int describeContents() { + return 0; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mScanType); + dest.writeInt(mFrequencyMhz); + dest.writeList(mVendorData); + } + + /* Read List<OuiKeyedData> from Parcel */ + @NonNull + private static List<OuiKeyedData> readOuiKeyedDataList(@NonNull Parcel in) { + List<OuiKeyedData> dataList = new ArrayList<>(); + if (SdkLevel.isAtLeastT()) { + in.readList(dataList, OuiKeyedData.class.getClassLoader(), OuiKeyedData.class); + } else { + in.readList(dataList, OuiKeyedData.class.getClassLoader()); + } + return dataList; + } + + /** @hide */ + WifiP2pDiscoveryConfig(@NonNull Parcel in) { + this.mScanType = in.readInt(); + this.mFrequencyMhz = in.readInt(); + this.mVendorData = readOuiKeyedDataList(in); + } + + /** Implement the Parcelable interface */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public static final Creator<WifiP2pDiscoveryConfig> CREATOR = + new Creator<WifiP2pDiscoveryConfig>() { + public WifiP2pDiscoveryConfig createFromParcel(Parcel in) { + return new WifiP2pDiscoveryConfig(in); + } + + public WifiP2pDiscoveryConfig[] newArray(int size) { + return new WifiP2pDiscoveryConfig[size]; + } + }; + + /** + * Builder for {@link WifiP2pDiscoveryConfig}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final class Builder { + + private final int mScanType; + private int mFrequencyMhz = 0; + private @NonNull List<OuiKeyedData> mVendorData = new ArrayList<>(); + + /** + * Constructor for {@link Builder}. + * + * @param scanType Type of this P2P scan. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public Builder(@WifiP2pManager.WifiP2pScanType int scanType) { + mScanType = scanType; + } + + /** + * Set the frequency to scan. Only applicable if the scan type is + * {@link WifiP2pManager#WIFI_P2P_SCAN_SINGLE_FREQ}. + * + * @param frequencyMhz Frequency to scan in MHz. + * @return Builder for chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setFrequencyMhz(@IntRange(from = 0) int frequencyMhz) { + if (frequencyMhz <= 0) { + throw new IllegalArgumentException("Frequency must be greater than 0"); + } + mFrequencyMhz = frequencyMhz; + return this; + } + + /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + * @return Builder for chaining. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + return this; + } + + /** + * Build {@link WifiP2pDiscoveryConfig} given the current requests made on the builder. + * @return {@link WifiP2pDiscoveryConfig} constructed based on builder method calls. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public WifiP2pDiscoveryConfig build() { + if (mScanType < WifiP2pManager.WIFI_P2P_SCAN_FULL + || mScanType > WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ) { + throw new IllegalArgumentException("Invalid scan type " + mScanType); + } + if (mScanType == WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ && mFrequencyMhz == 0) { + throw new IllegalArgumentException( + "Scan type is single frequency, but no frequency was provided"); + } + return new WifiP2pDiscoveryConfig(mScanType, mFrequencyMhz, mVendorData); + } + } +} diff --git a/framework/java/android/net/wifi/p2p/WifiP2pExtListenParams.java b/framework/java/android/net/wifi/p2p/WifiP2pExtListenParams.java new file mode 100644 index 0000000000..720d674dbd --- /dev/null +++ b/framework/java/android/net/wifi/p2p/WifiP2pExtListenParams.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2024 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 android.net.wifi.p2p; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.RequiresApi; +import android.annotation.SystemApi; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class representing Wi-Fi P2P extended listen parameters. + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +public final class WifiP2pExtListenParams implements Parcelable { + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private @NonNull List<OuiKeyedData> mVendorData; + + private WifiP2pExtListenParams(@NonNull List<OuiKeyedData> vendorData) { + mVendorData = new ArrayList<>(vendorData); + } + + /** + * Get the vendor-provided configuration data, if it exists. See {@link + * Builder#setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + public String toString() { + StringBuffer sbuf = new StringBuffer(); + sbuf.append("\n vendorData: ").append(mVendorData); + return sbuf.toString(); + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + public int describeContents() { + return 0; + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeList(mVendorData); + } + + /** @hide */ + WifiP2pExtListenParams(@NonNull Parcel in) { + this.mVendorData = ParcelUtil.readOuiKeyedDataList(in); + } + + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public static final Creator<WifiP2pExtListenParams> CREATOR = + new Creator<WifiP2pExtListenParams>() { + public WifiP2pExtListenParams createFromParcel(Parcel in) { + return new WifiP2pExtListenParams(in); + } + + public WifiP2pExtListenParams[] newArray(int size) { + return new WifiP2pExtListenParams[size]; + } + }; + + /** + * Builder for {@link WifiP2pExtListenParams}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final class Builder { + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); + + /** + * Constructor for {@link Builder}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public Builder() { + } + + /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + * @return Builder for chaining. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + return this; + } + + /** + * Construct a WifiP2pExtListenParams object with the specified parameters. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public WifiP2pExtListenParams build() { + return new WifiP2pExtListenParams(mVendorData); + } + } +} diff --git a/framework/java/android/net/wifi/p2p/WifiP2pGroup.java b/framework/java/android/net/wifi/p2p/WifiP2pGroup.java index bdd6519002..fe9ad03e08 100644 --- a/framework/java/android/net/wifi/p2p/WifiP2pGroup.java +++ b/framework/java/android/net/wifi/p2p/WifiP2pGroup.java @@ -16,12 +16,26 @@ package android.net.wifi.p2p; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.net.Inet4Address; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -90,6 +104,9 @@ public class WifiP2pGroup implements Parcelable { /** The frequency (in MHz) used by this group */ private int mFrequency; + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); + /** * P2P Client IPV4 address allocated via EAPOL-Key exchange. * @hide @@ -261,7 +278,33 @@ public class WifiP2pGroup implements Parcelable { for (WifiP2pDevice client : mClients) { if (client.equals(device)) return; } - mClients.add(device); + mClients.add(new WifiP2pDevice(device)); + } + + /** @hide */ + public void setClientInterfaceMacAddress(@NonNull String deviceAddress, + @NonNull final MacAddress interfaceMacAddress) { + for (WifiP2pDevice client : mClients) { + if (client.deviceAddress.equals(deviceAddress)) { + Log.i("setClientInterfaceMacAddress", " device: " + deviceAddress + + " interfaceAddress: " + interfaceMacAddress.toString()); + client.setInterfaceMacAddress(interfaceMacAddress); + break; + } + } + } + /** @hide */ + public void setClientIpAddress(@NonNull final MacAddress interfaceMacAddress, + @NonNull final InetAddress ipAddress) { + for (WifiP2pDevice client : mClients) { + if (client.getInterfaceMacAddress().equals(interfaceMacAddress)) { + Log.i("setClientIpAddress", "Update the IP address" + + " device: " + client.deviceAddress + " interfaceAddress: " + + interfaceMacAddress.toString() + " IP: " + ipAddress.getHostAddress()); + client.setIpAddress(ipAddress); + break; + } + } } /** @hide */ @@ -340,6 +383,44 @@ public class WifiP2pGroup implements Parcelable { this.mFrequency = freq; } + /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * #setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + + /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided + * configuration data. Note that multiple elements with the same OUI are allowed. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + public void setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = new ArrayList<>(vendorData); + } + public String toString() { StringBuffer sbuf = new StringBuffer(); sbuf.append("network: ").append(mNetworkName); @@ -351,6 +432,7 @@ public class WifiP2pGroup implements Parcelable { sbuf.append("\n interface: ").append(mInterface); sbuf.append("\n networkId: ").append(mNetId); sbuf.append("\n frequency: ").append(mFrequency); + sbuf.append("\n vendorData: ").append(mVendorData); return sbuf.toString(); } @@ -370,6 +452,9 @@ public class WifiP2pGroup implements Parcelable { mInterface = source.getInterface(); mNetId = source.getNetworkId(); mFrequency = source.getFrequency(); + if (SdkLevel.isAtLeastV()) { + mVendorData = new ArrayList<>(source.getVendorData()); + } } } @@ -386,6 +471,9 @@ public class WifiP2pGroup implements Parcelable { dest.writeString(mInterface); dest.writeInt(mNetId); dest.writeInt(mFrequency); + if (SdkLevel.isAtLeastV()) { + dest.writeList(mVendorData); + } } /** Implement the Parcelable interface */ @@ -404,6 +492,9 @@ public class WifiP2pGroup implements Parcelable { group.setInterface(in.readString()); group.setNetworkId(in.readInt()); group.setFrequency(in.readInt()); + if (SdkLevel.isAtLeastV()) { + group.setVendorData(ParcelUtil.readOuiKeyedDataList(in)); + } return group; } diff --git a/framework/java/android/net/wifi/p2p/WifiP2pInfo.java b/framework/java/android/net/wifi/p2p/WifiP2pInfo.java index 33bc37e155..a287da52c8 100644 --- a/framework/java/android/net/wifi/p2p/WifiP2pInfo.java +++ b/framework/java/android/net/wifi/p2p/WifiP2pInfo.java @@ -16,8 +16,8 @@ package android.net.wifi.p2p; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; import java.net.InetAddress; import java.net.UnknownHostException; @@ -45,7 +45,8 @@ public class WifiP2pInfo implements Parcelable { StringBuffer sbuf = new StringBuffer(); sbuf.append("groupFormed: ").append(groupFormed) .append(" isGroupOwner: ").append(isGroupOwner) - .append(" groupOwnerAddress: ").append(groupOwnerAddress); + .append(" groupOwnerIpAddress: ") + .append(groupOwnerAddress == null ? "none" : groupOwnerAddress.getHostAddress()); return sbuf.toString(); } diff --git a/framework/java/android/net/wifi/p2p/WifiP2pManager.java b/framework/java/android/net/wifi/p2p/WifiP2pManager.java index d552fd8dbc..7213bbe5c6 100644 --- a/framework/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/framework/java/android/net/wifi/p2p/WifiP2pManager.java @@ -17,6 +17,7 @@ package android.net.wifi.p2p; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -50,6 +51,7 @@ import android.os.RemoteException; import android.text.TextUtils; import android.util.CloseGuard; import android.util.Log; +import android.util.SparseArray; import android.view.Display; import androidx.annotation.RequiresApi; @@ -57,6 +59,7 @@ import androidx.annotation.RequiresApi; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -226,6 +229,20 @@ public class WifiP2pManager { "android.net.wifi.p2p.EXTRA_PARAM_KEY_INFORMATION_ELEMENT_LIST"; /** + * Extra for transporting discovery config with vendor-specific data + * @hide + */ + public static final String EXTRA_PARAM_KEY_DISCOVERY_CONFIG = + "android.net.wifi.p2p.EXTRA_PARAM_KEY_DISCOVERY_CONFIG"; + + /** + * Extra for transporting extended listening parameters + * @hide + */ + public static final String EXTRA_PARAM_KEY_EXT_LISTEN_PARAMS = + "android.net.wifi.p2p.EXTRA_PARAM_KEY_EXT_LISTEN_PARAMS"; + + /** * Key for transporting a bundle of extra information. * @hide */ @@ -522,22 +539,28 @@ public class WifiP2pManager { /** * Run P2P scan on all channels. - * @hide */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public static final int WIFI_P2P_SCAN_FULL = 0; /** * Run P2P scan only on social channels. - * @hide */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public static final int WIFI_P2P_SCAN_SOCIAL = 1; /** * Run P2P scan only on a specific channel. - * @hide */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) public static final int WIFI_P2P_SCAN_SINGLE_FREQ = 2; + /** + * Run P2P scan with config Params. + * @hide + */ + public static final int WIFI_P2P_SCAN_WITH_CONFIG_PARAMS = 3; + /** @hide */ @IntDef(prefix = {"WIFI_P2P_SCAN_"}, value = { WIFI_P2P_SCAN_FULL, @@ -548,6 +571,12 @@ public class WifiP2pManager { } /** + * Enter the P2P listen state with additional parameters. + * @hide + */ + public static final int WIFI_P2P_EXT_LISTEN_WITH_PARAMS = 1; + + /** * No channel specified for discover Peers APIs. Let lower layer decide the frequencies to scan * based on the WifiP2pScanType. * @hide @@ -560,6 +589,8 @@ public class WifiP2pManager { */ private static final int WIFI_P2P_VENDOR_ELEMENTS_MAXIMUM_LENGTH = 512; + private Context mContext; + IWifiP2pManager mService; private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER; @@ -833,6 +864,7 @@ public class WifiP2pManager { /** @hide */ public static final int RESPONSE_GET_LISTEN_STATE = BASE + 118; + private static final SparseArray<IWifiP2pListener> sWifiP2pListenerMap = new SparseArray<>(); /** * Create a new WifiP2pManager instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -1219,6 +1251,376 @@ public class WifiP2pManager { void onPinGenerated(@NonNull MacAddress deviceAddress, @NonNull String pin); } + /** + * Interface used to listen to Wi-Fi p2p various changes such as device state change, + * discovery started/stopped, connection change, etc. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public interface WifiP2pListener { + /** + * Called when Wi-Fi p2p has been enabled or disabled. + * @see #WIFI_P2P_STATE_CHANGED_ACTION + * @see #requestP2pState(Channel, P2pStateListener) + * + * @param state indicates whether Wi-Fi p2p is enabled or disabled. + * @see #WIFI_P2P_STATE_ENABLED + * @see #WIFI_P2P_STATE_DISABLED + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onP2pStateChanged(@WifiP2pState int state) { + } + + /** + * Called when peer discovery has either started or stopped. + * @see #WIFI_P2P_DISCOVERY_CHANGED_ACTION + * @see #requestDiscoveryState(Channel, DiscoveryStateListener) + * + * @param state indicates whether discovery has started or stopped. + * @see #WIFI_P2P_DISCOVERY_STARTED + * @see #WIFI_P2P_DISCOVERY_STOPPED + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onDiscoveryStateChanged(@WifiP2pDiscoveryState int state) { + } + + /** + * Called when peer listen has either started or stopped. + * @see #ACTION_WIFI_P2P_LISTEN_STATE_CHANGED + * @see #getListenState(Channel, Executor, Consumer) + * + * @param state indicates whether listen has started or stopped. + * @see #WIFI_P2P_LISTEN_STARTED + * @see #WIFI_P2P_LISTEN_STOPPED + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onListenStateChanged(@WifiP2pListenState int state) { + } + + /** + * Called when this device details have changed. + * @see #WIFI_P2P_THIS_DEVICE_CHANGED_ACTION + * @see #requestDeviceInfo(Channel, DeviceInfoListener) + * + * @param p2pDevice provides this device details. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onDeviceConfigurationChanged(@Nullable WifiP2pDevice p2pDevice) { + } + + /** + * Called when the available peer list has changed. This can be sent as a result of peers + * being found, lost or updated. + * @see #WIFI_P2P_PEERS_CHANGED_ACTION + * @see #requestPeers(Channel, PeerListListener) + * + * @param p2pDeviceList provides the full list of current peers. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onPeerListChanged(@NonNull WifiP2pDeviceList p2pDeviceList) { + } + + /** + * Called when remembered persistent groups have changed. + * @see #ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED + * @see #requestPersistentGroupInfo(Channel, PersistentGroupInfoListener) + * + * @param p2pGroupList provides the full list of p2p group. + * + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onPersistentGroupsChanged(@NonNull WifiP2pGroupList p2pGroupList) { + } + + /** + * Called when either group owner or group client is creating p2p group. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onGroupCreating() { + } + + /** + * Called when group negotiation has been rejected by user. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onGroupNegotiationRejectedByUser() { + } + + /** + * Called when group creation has failed. + * + * @param reason provides the group creation failure reason. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onGroupCreationFailed(@GroupCreationFailureReason int reason) { + } + + /** + * Called when either group owner or group client has created p2p group successfully. + * + * @param p2pInfo provides the p2p connection info. + * @param p2pGroup provides the details of the group. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onGroupCreated(@NonNull WifiP2pInfo p2pInfo, + @NonNull WifiP2pGroup p2pGroup) { + } + + /** + * Called to indicate group owner that a group client has joined p2p group successfully. + * + * @param p2pInfo provides the p2p connection info. + * @param p2pGroup provides the details of the group. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onPeerClientJoined(@NonNull WifiP2pInfo p2pInfo, + @NonNull WifiP2pGroup p2pGroup) { + } + + /** + * Called to indicate group owner that a group client has disconnected. + * + * @param p2pInfo provides the p2p connection info. + * @param p2pGroup provides the details of the group. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onPeerClientDisconnected(@NonNull WifiP2pInfo p2pInfo, + @NonNull WifiP2pGroup p2pGroup) { + } + + /** + * Called when the frequency of a formed group has been changed. + * + * @param p2pInfo provides the p2p connection info. + * @param p2pGroup provides the details of the group. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onFrequencyChanged(@NonNull WifiP2pInfo p2pInfo, + @NonNull WifiP2pGroup p2pGroup) { + } + + /** + * Called when p2p group has been removed. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + default void onGroupRemoved() { + } + } + + /** + * P2p group creation failed because the connection has been cancelled. + * Used in {@link WifiP2pListener#onGroupCreationFailed(int reason)}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int GROUP_CREATION_FAILURE_REASON_CONNECTION_CANCELLED = 0; + /** + * P2p group creation failed because it has timed out. + * Used in {@link WifiP2pListener#onGroupCreationFailed(int reason)}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int GROUP_CREATION_FAILURE_REASON_TIMED_OUT = 1; + /** + * P2p group creation failed because user has rejected. + * Used in {@link WifiP2pListener#onGroupCreationFailed(int reason)}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int GROUP_CREATION_FAILURE_REASON_USER_REJECTED = 2; + /** + * P2p group creation failed because provision discovery has failed. + * Used in {@link WifiP2pListener#onGroupCreationFailed(int reason)}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED = 3; + /** + * P2p group creation failed because the group has been removed. + * Used in {@link WifiP2pListener#onGroupCreationFailed(int reason)}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int GROUP_CREATION_FAILURE_REASON_GROUP_REMOVED = 4; + /** + * P2p group creation failed because invitation has failed. + * Used in {@link WifiP2pListener#onGroupCreationFailed(int reason)}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final int GROUP_CREATION_FAILURE_REASON_INVITATION_FAILED = 5; + + /** + * @hide + */ + @IntDef(prefix = {"GROUP_CREATION_FAILURE_REASON_"}, value = { + GROUP_CREATION_FAILURE_REASON_CONNECTION_CANCELLED, + GROUP_CREATION_FAILURE_REASON_TIMED_OUT, + GROUP_CREATION_FAILURE_REASON_USER_REJECTED, + GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED, + GROUP_CREATION_FAILURE_REASON_GROUP_REMOVED, + GROUP_CREATION_FAILURE_REASON_INVITATION_FAILED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface GroupCreationFailureReason { + } + + /** + * Helper class to support wifi p2p listener. + */ + private static class OnWifiP2pListenerProxy extends IWifiP2pListener.Stub { + @NonNull + private Executor mExecutor; + @NonNull + private WifiP2pListener mListener; + + OnWifiP2pListenerProxy(@NonNull Executor executor, + @NonNull WifiP2pListener listener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(listener); + mExecutor = executor; + mListener = listener; + } + + @Override + public void onP2pStateChanged(@WifiP2pState int state) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onP2pStateChanged(state)); + } + + @Override + public void onDiscoveryStateChanged(@WifiP2pDiscoveryState int state) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onDiscoveryStateChanged(state)); + } + + @Override + public void onListenStateChanged(@WifiP2pListenState int state) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onListenStateChanged(state)); + } + + @Override + public void onDeviceConfigurationChanged(WifiP2pDevice p2pDevice) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onDeviceConfigurationChanged(p2pDevice)); + } + + @Override + public void onPeerListChanged(WifiP2pDeviceList p2pDeviceList) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onPeerListChanged(p2pDeviceList)); + } + + @Override + public void onPersistentGroupsChanged(WifiP2pGroupList p2pGroupList) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onPersistentGroupsChanged(p2pGroupList)); + } + + @Override + public void onGroupCreating() { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onGroupCreating()); + } + + @Override + public void onGroupNegotiationRejectedByUser() { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onGroupNegotiationRejectedByUser()); + } + + @Override + public void onGroupCreationFailed(@GroupCreationFailureReason int reason) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onGroupCreationFailed(reason)); + } + + @Override + public void onGroupCreated(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onGroupCreated(p2pInfo, p2pGroup)); + } + + @Override + public void onPeerClientJoined(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onPeerClientJoined(p2pInfo, p2pGroup)); + } + + @Override + public void onPeerClientDisconnected(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onPeerClientDisconnected(p2pInfo, p2pGroup)); + } + + @Override + public void onFrequencyChanged(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onFrequencyChanged(p2pInfo, p2pGroup)); + } + + @Override + public void onGroupRemoved() { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> mListener.onGroupRemoved()); + } + } + + /** + * Add a listener to listen to Wi-Fi p2p various changes. + * + * @param executor the Executor on which to execute the callbacks. + * @param listener listener for the Wi-Fi p2p connection changes. + * @throws SecurityException if the caller is missing required permissions. + * @throws IllegalArgumentException if incorrect input arguments are provided. + */ + @RequiresPermission(allOf = { + android.Manifest.permission.NEARBY_WIFI_DEVICES, + android.Manifest.permission.ACCESS_WIFI_STATE + }, conditional = true) + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void registerWifiP2pListener(@NonNull @CallbackExecutor Executor executor, + @NonNull WifiP2pListener listener) { + Log.d(TAG, "registerWifiP2pListener: listener=" + listener + ", executor=" + executor); + final int listenerIdentifier = System.identityHashCode(listener); + synchronized (sWifiP2pListenerMap) { + try { + IWifiP2pListener.Stub listenerProxy = new OnWifiP2pListenerProxy(executor, + listener); + sWifiP2pListenerMap.put(listenerIdentifier, listenerProxy); + Bundle extras = prepareExtrasBundleWithAttributionSource(mContext); + mService.registerWifiP2pListener(listenerProxy, mContext.getOpPackageName(), + extras); + } catch (RemoteException e) { + sWifiP2pListenerMap.remove(listenerIdentifier); + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Remove a listener added using + * {@link #registerWifiP2pListener(Executor, WifiP2pListener)} + * + * @param listener the listener to be removed. + * @throws IllegalArgumentException if incorrect input arguments are provided. + */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void unregisterWifiP2pListener(@NonNull WifiP2pListener listener) { + Log.d(TAG, "unregisterWifiP2pListener: listener=" + listener); + final int listenerIdentifier = System.identityHashCode(listener); + synchronized (sWifiP2pListenerMap) { + try { + if (!sWifiP2pListenerMap.contains(listenerIdentifier)) { + Log.w(TAG, "Unknown external listener " + listenerIdentifier); + return; + } + mService.unregisterWifiP2pListener(sWifiP2pListenerMap.get(listenerIdentifier)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } finally { + sWifiP2pListenerMap.remove(listenerIdentifier); + } + } + } /** * A channel that connects the application to the Wifi p2p framework. @@ -1618,6 +2020,7 @@ public class WifiP2pManager { extras.putInt(EXTRA_PARAM_KEY_DISPLAY_ID, displayId); Channel channel = initializeChannel(srcContext, srcLooper, listener, getMessenger(binder, srcContext.getOpPackageName(), extras), binder); + mContext = srcContext; return channel; } @@ -1822,6 +2225,45 @@ public class WifiP2pManager { } /** + * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers + * for the purpose of establishing a connection. See {@link #discoverPeers( + * Channel, ActionListener)} for more details. + * + * This method accepts a {@link WifiP2pDiscoveryConfig} object specifying the desired + * parameters for the peer discovery. The configuration object allows the specification of the + * scan type (ex. FULL, SOCIAL) and the inclusion of vendor-specific configuration data. + * + * The application must have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with + * android:usesPermissionFlags="neverForLocation". If the application does not declare + * android:usesPermissionFlags="neverForLocation", then it must also have + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. + * + * @param channel is the channel created at {@link #initialize} + * @param config is the configuration for this peer discovery + * @param listener for callbacks on success or failure. + */ + @RequiresPermission(allOf = { + android.Manifest.permission.NEARBY_WIFI_DEVICES, + android.Manifest.permission.ACCESS_FINE_LOCATION + }, conditional = true) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void startPeerDiscovery( + @NonNull Channel channel, + @NonNull WifiP2pDiscoveryConfig config, + @Nullable ActionListener listener) { + if (!isChannelConstrainedDiscoverySupported()) { + throw new UnsupportedOperationException(); + } + checkChannel(channel); + Objects.requireNonNull(config); + Bundle extras = prepareExtrasBundle(channel); + extras.putParcelable(EXTRA_PARAM_KEY_DISCOVERY_CONFIG, config); + channel.mAsyncChannel.sendMessage(prepareMessage(DISCOVER_PEERS, + WIFI_P2P_SCAN_WITH_CONFIG_PARAMS, + channel.putListener(listener), extras, channel.mContext)); + } + + /** * Stop an ongoing peer discovery * * <p> The function call immediately returns after sending a stop request @@ -2043,6 +2485,38 @@ public class WifiP2pManager { } /** + * Force P2P to enter the listen state. See {@link #startListening(Channel, ActionListener)} + * for more details. + * + * This method accepts a {@link WifiP2pExtListenParams} object containing additional + * parameters. + * + * @param channel is the channel created at @link #initialize(Context, Looper, ChannelListener)} + * @param params are the parameters for this listen request. + * @param listener for callbacks on success or failure. + * @hide + */ + @SystemApi + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(allOf = { + android.Manifest.permission.NEARBY_WIFI_DEVICES, + android.Manifest.permission.ACCESS_FINE_LOCATION + }, conditional = true) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public void startListening( + @NonNull Channel channel, + @NonNull WifiP2pExtListenParams params, + @Nullable ActionListener listener) { + checkChannel(channel); + Bundle extras = prepareExtrasBundle(channel); + Objects.requireNonNull(params); + extras.putParcelable(EXTRA_PARAM_KEY_EXT_LISTEN_PARAMS, params); + channel.mAsyncChannel.sendMessage(prepareMessage(START_LISTEN, + WIFI_P2P_EXT_LISTEN_WITH_PARAMS, channel.putListener(listener), extras, + channel.mContext)); + } + + /** * Force p2p to exit listen state. * * When this API is called, this device will stop entering LISTENING state periodically diff --git a/framework/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java b/framework/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java index d0fe92d524..481075b9ac 100644 --- a/framework/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java +++ b/framework/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java @@ -16,7 +16,17 @@ package android.net.wifi.p2p; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; +import android.net.wifi.OuiKeyedData; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import com.android.modules.utils.build.SdkLevel; + +import java.util.Collections; +import java.util.List; /** * A class representing a Wi-Fi p2p provisional discovery request/response @@ -44,12 +54,49 @@ public class WifiP2pProvDiscEvent { @UnsupportedAppUsage public String pin; + /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */ + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); + + /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * #setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + @UnsupportedAppUsage public WifiP2pProvDiscEvent() { device = new WifiP2pDevice(); } /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @NonNull + public void setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + } + + /** * @param string formats supported include * * P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 @@ -87,6 +134,7 @@ public class WifiP2pProvDiscEvent { sbuf.append(device); sbuf.append("\n event: ").append(event); sbuf.append("\n pin: ").append(pin); + sbuf.append("\n vendorData: ").append(mVendorData); return sbuf.toString(); } } diff --git a/framework/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/framework/java/android/net/wifi/p2p/WifiP2pWfdInfo.java index b7411e82d4..3411d6a198 100644 --- a/framework/java/android/net/wifi/p2p/WifiP2pWfdInfo.java +++ b/framework/java/android/net/wifi/p2p/WifiP2pWfdInfo.java @@ -446,7 +446,7 @@ public final class WifiP2pWfdInfo implements Parcelable { public String toString() { StringBuffer sbuf = new StringBuffer(); sbuf.append("WFD enabled: ").append(mEnabled); - sbuf.append("WFD DeviceInfo: ").append(mDeviceInfo); + sbuf.append("\n WFD DeviceInfo: ").append(mDeviceInfo); sbuf.append("\n WFD CtrlPort: ").append(mCtrlPort); sbuf.append("\n WFD MaxThroughput: ").append(mMaxThroughput); sbuf.append("\n WFD R2 DeviceInfo: ").append(mR2DeviceInfo); diff --git a/framework/java/android/net/wifi/rtt/RangingRequest.java b/framework/java/android/net/wifi/rtt/RangingRequest.java index aebe0d338e..8360dc466a 100644 --- a/framework/java/android/net/wifi/rtt/RangingRequest.java +++ b/framework/java/android/net/wifi/rtt/RangingRequest.java @@ -16,21 +16,31 @@ package android.net.wifi.rtt; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; import android.net.wifi.ScanResult; import android.net.wifi.aware.AttachCallback; import android.net.wifi.aware.DiscoverySessionCallback; import android.net.wifi.aware.IdentityChangedListener; import android.net.wifi.aware.PeerHandle; import android.net.wifi.aware.WifiAwareManager; +import android.os.Build; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.RequiresApi; + +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; + import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.StringJoiner; @@ -96,10 +106,17 @@ public final class RangingRequest implements Parcelable { /** @hide */ public final int mRttBurstSize; + /** + * List of {@link OuiKeyedData} providing vendor-specific configuration data. + */ + private @NonNull List<OuiKeyedData> mVendorData; + /** @hide */ - private RangingRequest(List<ResponderConfig> rttPeers, int rttBurstSize) { + private RangingRequest(List<ResponderConfig> rttPeers, int rttBurstSize, + @NonNull List<OuiKeyedData> vendorData) { mRttPeers = rttPeers; mRttBurstSize = rttBurstSize; + mVendorData = new ArrayList<>(vendorData); } /** @@ -124,6 +141,24 @@ public final class RangingRequest implements Parcelable { return mRttBurstSize; } + /** + * Return the vendor-provided configuration data, if it exists. See also {@link + * Builder#setVendorData(List)} + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + @Override public int describeContents() { return 0; @@ -133,6 +168,7 @@ public final class RangingRequest implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeList(mRttPeers); dest.writeInt(mRttBurstSize); + dest.writeList(mVendorData); } public static final @android.annotation.NonNull Creator<RangingRequest> CREATOR = new Creator<RangingRequest>() { @@ -143,7 +179,8 @@ public final class RangingRequest implements Parcelable { @Override public RangingRequest createFromParcel(Parcel in) { - return new RangingRequest(in.readArrayList(null), in.readInt()); + return new RangingRequest(in.readArrayList(null), in.readInt(), + ParcelUtil.readOuiKeyedDataList(in)); } }; @@ -155,6 +192,7 @@ public final class RangingRequest implements Parcelable { sj.add(rc.toString()); } sj.add("mRttBurstSize=" + mRttBurstSize); + sj.add("mVendorData=" + mVendorData); return sj.toString(); } @@ -172,6 +210,9 @@ public final class RangingRequest implements Parcelable { if (mRttBurstSize < getMinRttBurstSize() || mRttBurstSize > getMaxRttBurstSize()) { throw new IllegalArgumentException("RTT burst size is out of range"); } + if (mVendorData == null) { + throw new IllegalArgumentException("Vendor data must be non-null"); + } } /** @@ -180,6 +221,7 @@ public final class RangingRequest implements Parcelable { public static final class Builder { private List<ResponderConfig> mRttPeers = new ArrayList<>(); private int mRttBurstSize = DEFAULT_RTT_BURST_SIZE; + private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList(); /** * Set the RTT Burst size for the ranging request. @@ -190,6 +232,14 @@ public final class RangingRequest implements Parcelable { * {@link #getMaxRttBurstSize()} inclusively, or a * {@link java.lang.IllegalArgumentException} will be thrown. * + * Note: RTT burst size is applicable to IEEE 802.11mc, and for one special case it is + * also applicable to IEEE 802.11az to generate multiple NTB ranging requests per + * measurement. It is applicable for IEEE 802.11az based ranging requests when MIMO is + * not available, with the transmit and receive spatial streams between the initiator and + * responder station is equal to 1. See + * {@link RangingResult#get80211azNumberOfRxSpatialStreams()} and + * {@link RangingResult#get80211azNumberOfTxSpatialStreams()}. + * * @param rttBurstSize The number of FTM packets used to estimate a range. * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. @@ -208,10 +258,15 @@ public final class RangingRequest implements Parcelable { * which to measure range. The total number of peers added to a request cannot exceed the * limit specified by {@link #getMaxPeers()}. * <p> - * Two-sided Ranging will be supported if the Access Point supports IEEE 802.11mc, also - * known as two-sided RTT, and this is determined by the method - * {@link ScanResult#is80211mcResponder()}. If not supported, one-sided RTT will be - * performed with no correction for the AP packet turnaround time. + * Two-sided Ranging will be performed if the local device and the AP support IEEE 802.11az + * (non-trigger based ranging) or IEEE 802.11mc. AP capability is determined by the method + * {@link ScanResult#is80211azNtbResponder()} or {@link ScanResult#is80211mcResponder()}. + * + * If both 11az and 11mc are supported by the local device and the AP, 11az non-trigger + * based ranging will be performed. + * + * If two-sided ranging is not supported, one-sided RTT will be performed with no + * correction for the AP packet turnaround time. * * @param apInfo Information about an Access Point (AP) obtained in a Scan Result. * @return The builder to facilitate chaining @@ -230,10 +285,15 @@ public final class RangingRequest implements Parcelable { * which to measure range. The total number of peers added to a request cannot exceed the * limit specified by {@link #getMaxPeers()}. * <p> - * Two-sided Ranging will be supported if the Access Point supports IEEE 802.11mc, also - * known as two-sided RTT, and this is determined by the method - * {@link ScanResult#is80211mcResponder()}. If not supported, one-sided RTT will be - * performed with no correction for the AP packet turnaround time. + * Two-sided Ranging will be performed if the local device and the AP support IEEE 802.11az + * (non-trigger based ranging) or IEEE 802.11mc. AP capability is determined by the method + * {@link ScanResult#is80211azNtbResponder()} or {@link ScanResult#is80211mcResponder()}. + * + * If both 11az and 11mc are supported by the local device and the AP, 11az non-trigger + * based ranging will be performed. + * + * If two-sided ranging is not supported, one-sided RTT will be performed with no + * correction for the AP packet turnaround time. * * @param apInfos Information about Access Points (APs) obtained in a Scan Result. * @return The builder to facilitate chaining @@ -255,10 +315,15 @@ public final class RangingRequest implements Parcelable { * with which to measure range. The total number of peers added to the request cannot exceed * the limit specified by {@link #getMaxPeers()}. * <p> - * Two-sided Ranging will be supported if an Access Point supports IEEE 802.11mc, also - * known as two-sided RTT, and this is specified in the {@link ResponderConfig} builder. - * If not supported, one-sided RTT will be performed with no correction for - * the AP packet turnaround time. + * Two-sided Ranging will be performed if the local device and the AP support IEEE 802.11az + * (non-trigger based ranging) or IEEE 802.11mc. AP capability is determined by the method + * {@link ScanResult#is80211azNtbResponder()} or {@link ScanResult#is80211mcResponder()}. + * + * If both 11az and 11mc are supported by the local device and the AP, 11az non-trigger + * based ranging will be performed. + * + * If two-sided ranging is not supported, one-sided RTT will be performed with no + * correction for the AP packet turnaround time. * * @param responder Information on the RTT Responder. * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}. @@ -278,10 +343,15 @@ public final class RangingRequest implements Parcelable { * which to measure range. The total number of peers added to a request cannot exceed the * limit specified by {@link #getMaxPeers()}. * <p> - * Two-sided Ranging will be supported if an Access Point supports IEEE 802.11mc, also - * known as two-sided RTT, and this is specified in the {@link ResponderConfig} builder. - * If not supported, one-sided RTT will be performed with no correction for the AP packet - * turnaround time. + * Two-sided Ranging will be performed if the local device and the AP support IEEE 802.11az + * (non-trigger based ranging) or IEEE 802.11mc. AP capability is determined by the method + * {@link ScanResult#is80211azNtbResponder()} or {@link ScanResult#is80211mcResponder()}. + * + * If both 11az and 11mc are supported by the local device and the AP, 11az non-trigger + * based ranging will be performed. + * + * If two-sided ranging is not supported, one-sided RTT will be performed with no + * correction for the AP packet turnaround time. * * @param responders Information representing the set of access points to be ranged * @return The builder to facilitate chaining @@ -299,17 +369,18 @@ public final class RangingRequest implements Parcelable { } /** - * Add the non-802.11mc capable device specified by the {@link ScanResult} to the list of - * devices with which to measure range. The total number of peers added to a request cannot - * exceed the limit specified by {@link #getMaxPeers()}. + * Add the non-802.11mc and non-802.11az capable device specified by the {@link ScanResult} + * to the list of devices with which to measure range. The total number of peers added to a + * request cannot exceed the limit specified by {@link #getMaxPeers()}. * <p> - * Accurate ranging cannot be supported if the Access Point does not support IEEE 802.11mc, - * and instead an alternate protocol called one-sided RTT will be used with lower - * accuracy. Use {@link ScanResult#is80211mcResponder()} to verify the Access Point)s) are - * not 802.11mc capable. + * Accurate ranging cannot be supported if the Access Point does not support IEEE 802.11mc + * and IEEE 802.11az, and instead an alternate protocol called one-sided RTT will be used + * with lower accuracy. Use {@link ScanResult#is80211mcResponder()} to verify the Access + * Point(s) are not 802.11mc capable. Use {@link ScanResult#is80211azNtbResponder()} ()} to + * verify the Access Point)s) are not 802.11az capable. * <p> * One-sided RTT does not subtract the RTT turnaround time at the Access Point, which can - * add hundreds of meters to the estimate. With experimentation it is possible to use this + * add hundreds of meters to the estimate. With experimentation, it is possible to use this * information to make a statistical estimate of the range by taking multiple measurements * to several Access Points and normalizing the result. For some applications this can be * used to improve range estimates based on Receive Signal Strength Indication (RSSI), but @@ -327,24 +398,26 @@ public final class RangingRequest implements Parcelable { if (apInfo == null) { throw new IllegalArgumentException("Null ScanResult!"); } - if (apInfo.is80211mcResponder()) { - throw new IllegalArgumentException("AP supports the 802.11mc protocol."); + if (apInfo.is80211mcResponder() || apInfo.is80211azNtbResponder()) { + throw new IllegalArgumentException( + "AP supports the 802.11mc or 8022.11az protocol."); } return addResponder(ResponderConfig.fromScanResult(apInfo)); } /** - * Add the non-802.11mc capable devices specified by the {@link ScanResult} to the list of - * devices with which to measure range. The total number of peers added to a request cannot - * exceed the limit specified by {@link #getMaxPeers()}. + * Add the non-802.11mc and non-802.11az capable devices specified by the {@link ScanResult} + * to the list of devices with which to measure range. The total number of peers added to a + * request cannot exceed the limit specified by {@link #getMaxPeers()}. * <p> - * Accurate ranging cannot be supported if the Access Point does not support IEEE 802.11mc, - * and instead an alternate protocol called one-sided RTT will be used with lower - * accuracy. Use {@link ScanResult#is80211mcResponder()} to verify the Access Point)s) are - * not 802.11mc capable. + * Accurate ranging cannot be supported if the Access Point does not support IEEE 802.11mc + * and IEEE 802.11az, and instead an alternate protocol called one-sided RTT will be used + * with lower accuracy. Use {@link ScanResult#is80211mcResponder()} to verify the Access + * Point(s) are not 802.11mc capable. Use {@link ScanResult#is80211azNtbResponder()} ()} to + * verify the Access Point(s) are not 802.11az capable. * <p> * One-sided RTT does not subtract the RTT turnaround time at the Access Point, which can - * add hundreds of meters to the estimate. With experimentation it is possible to use this + * add hundreds of meters to the estimate. With experimentation, it is possible to use this * information to make a statistical estimate of the range by taking multiple measurements * to several Access Points and normalizing the result. For some applications this can be * used to improve range estimates based on Receive Signal Strength Indication (RSSI), but @@ -363,9 +436,9 @@ public final class RangingRequest implements Parcelable { throw new IllegalArgumentException("Null list of ScanResults!"); } for (ScanResult scanResult : apInfos) { - if (scanResult.is80211mcResponder()) { + if (scanResult.is80211mcResponder() || scanResult.is80211azNtbResponder()) { throw new IllegalArgumentException( - "At least one AP supports the 802.11mc protocol."); + "At least one AP supports the 802.11mc or 802.11az protocol."); } addAccessPoint(scanResult); } @@ -427,13 +500,35 @@ public final class RangingRequest implements Parcelable { return addResponder(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle)); } + /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided + * configuration data. Note that multiple elements with the same OUI are allowed. + * @return Builder for chaining. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + @SystemApi + public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + return this; + } /** * Build {@link RangingRequest} given the current configurations made on the * builder. */ public RangingRequest build() { - return new RangingRequest(mRttPeers, mRttBurstSize); + return new RangingRequest(mRttPeers, mRttBurstSize, mVendorData); } } @@ -451,11 +546,12 @@ public final class RangingRequest implements Parcelable { return mRttPeers.size() == lhs.mRttPeers.size() && mRttPeers.containsAll(lhs.mRttPeers) - && mRttBurstSize == lhs.mRttBurstSize; + && mRttBurstSize == lhs.mRttBurstSize + && Objects.equals(mVendorData, lhs.mVendorData); } @Override public int hashCode() { - return Objects.hash(mRttPeers, mRttBurstSize); + return Objects.hash(mRttPeers, mRttBurstSize, mVendorData); } } diff --git a/framework/java/android/net/wifi/rtt/RangingResult.java b/framework/java/android/net/wifi/rtt/RangingResult.java index 32a83cfe8c..87b1ed9af3 100644 --- a/framework/java/android/net/wifi/rtt/RangingResult.java +++ b/framework/java/android/net/wifi/rtt/RangingResult.java @@ -16,20 +16,32 @@ package android.net.wifi.rtt; +import android.annotation.ElapsedRealtimeLong; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.ParcelUtil; import android.net.wifi.ScanResult; import android.net.wifi.WifiAnnotations.ChannelWidth; import android.net.wifi.aware.PeerHandle; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.RequiresApi; + +import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -79,126 +91,454 @@ public final class RangingResult implements Parcelable { */ public static final int UNSPECIFIED = -1; - /** @hide */ - public final int mStatus; + private final @RangeResultStatus int mStatus; + private final MacAddress mMac; + private final PeerHandle mPeerHandle; + private final int mDistanceMm; + private final int mDistanceStdDevMm; + private final int mRssi; + private final int mNumAttemptedMeasurements; + private final int mNumSuccessfulMeasurements; + private final byte[] mLci; + private final byte[] mLcr; + private final ResponderLocation mResponderLocation; + private final long mTimestamp; + private final boolean mIs80211mcMeasurement; + private final int mFrequencyMHz; + private final int mPacketBw; + private final boolean mIs80211azNtbMeasurement; + private final long mNtbMinMeasurementTime; + private final long mNtbMaxMeasurementTime; + private final int mI2rTxLtfRepetitions; + private final int mR2iTxLtfRepetitions; + private final int mNumTxSpatialStreams; + private final int mNumRxSpatialStreams; + private List<OuiKeyedData> mVendorData; - /** @hide */ - public final MacAddress mMac; + /** + * Builder class used to construct {@link RangingResult} objects. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final class Builder { + private @RangeResultStatus int mStatus = STATUS_FAIL; + private MacAddress mMac = null; + private PeerHandle mPeerHandle = null; + private int mDistanceMm = 0; + private int mDistanceStdDevMm = 0; + private int mRssi = -127; + private int mNumAttemptedMeasurements = 0; + private int mNumSuccessfulMeasurements = 0; + private byte[] mLci = null; + private byte[] mLcr = null; + private ResponderLocation mResponderLocation = null; + private long mTimestamp = 0; + private boolean mIs80211mcMeasurement = false; + private int mFrequencyMHz = UNSPECIFIED; + private int mPacketBw = UNSPECIFIED; + private boolean mIs80211azNtbMeasurement = false; + private long mNtbMinMeasurementTime = UNSPECIFIED; + private long mNtbMaxMeasurementTime = UNSPECIFIED; + private int mI2rTxLtfRepetitions = UNSPECIFIED; + private int mR2iTxLtfRepetitions = UNSPECIFIED; + private int mNumTxSpatialStreams = UNSPECIFIED; + private int mNumRxSpatialStreams = UNSPECIFIED; + private List<OuiKeyedData> mVendorData = Collections.emptyList(); - /** @hide */ - public final PeerHandle mPeerHandle; + /** + * Sets the Range result status. + * + * @param status Ranging result status, if not set defaults to + * {@link #STATUS_FAIL}. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setStatus(@RangeResultStatus int status) { + mStatus = status; + return this; + } - /** @hide */ - public final int mDistanceMm; + /** + * Sets the MAC address of the ranging result. + * + * @param macAddress Mac address, if not defaults to null. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setMacAddress(@Nullable MacAddress macAddress) { + mMac = macAddress; + return this; + } - /** @hide */ - public final int mDistanceStdDevMm; - /** @hide */ - public final int mRssi; + /** + * Sets the peer handle. Applicable only for NAN Ranging. + * + * @param peerHandle Opaque object used to represent a Wi-Fi Aware peer. If not set, + * defaults to null. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setPeerHandle(@Nullable PeerHandle peerHandle) { + mPeerHandle = peerHandle; + return this; + } - /** @hide */ - public final int mNumAttemptedMeasurements; + /** + * Sets the distance in millimeter. + * + * @param distanceMm distance. If not set, defaults to 0. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setDistanceMm(int distanceMm) { + mDistanceMm = distanceMm; + return this; + } - /** @hide */ - public final int mNumSuccessfulMeasurements; + /** + * Sets the standard deviation of the distance in millimeter. + * + * @param distanceStdDevMm Standard deviation of the distance measurement. If not set + * defaults to 0. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setDistanceStdDevMm(int distanceStdDevMm) { + mDistanceStdDevMm = distanceStdDevMm; + return this; + } - /** @hide */ - public final byte[] mLci; + /** + * Sets the average RSSI. + * + * @param rssi Average RSSI. If not set, defaults to -127. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setRssi(int rssi) { + mRssi = rssi; + return this; + } - /** @hide */ - public final byte[] mLcr; + /** + * Sets the total number of RTT measurements attempted. + * + * @param numAttemptedMeasurements Number of attempted measurements. If not set, default + * to 0. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setNumAttemptedMeasurements(int numAttemptedMeasurements) { + mNumAttemptedMeasurements = numAttemptedMeasurements; + return this; + } - /** @hide */ - public final ResponderLocation mResponderLocation; + /** + * Sets the total number of successful RTT measurements. + * + * @param numSuccessfulMeasurements Number of successful measurements. If not set, default + * to 0. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setNumSuccessfulMeasurements(int numSuccessfulMeasurements) { + mNumSuccessfulMeasurements = numSuccessfulMeasurements; + return this; + } - /** @hide */ - public final long mTimestamp; + /** + * Sets the Location Configuration Information (LCI). + * + * LCI provides data about the access point's (AP) physical location, such as its + * latitude, longitude, and altitude. The format is specified in the IEEE 802.11-2016 + * specifications, section 9.4.2.22.10. + * + * @param lci Location configuration information. If not set, defaults to null. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setLci(@Nullable byte[] lci) { + mLci = lci; + return this; + } - /** @hide */ - public final boolean mIs80211mcMeasurement; + /** + * Sets the Location Civic Report (LCR). + * + * LCR provides additional details about the AP's location in a human-readable format, + * such as the street address, building name, or floor number. This can be helpful for + * users to understand the context of their location within a building or complex. + * + * The format is + * specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.13. + * + * @param lcr Location civic report. If not set, defaults to null. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setLcr(@Nullable byte[] lcr) { + mLcr = lcr; + return this; + } - /** @hide */ - public final int mFrequencyMHz; + /** + * Sets Responder Location. + * + * ResponderLocation is both a Location Configuration Information (LCI) decoder and a + * Location Civic Report (LCR) decoder for information received from a Wi-Fi Access Point + * (AP) during Wi-Fi RTT ranging process. + * + * @param responderLocation Responder location. If not set, defaults to null. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setUnverifiedResponderLocation( + @Nullable ResponderLocation responderLocation) { + mResponderLocation = responderLocation; + return this; + } - /** @hide */ - public final int mPacketBw; + /** + * Sets the time stamp at which the ranging operation was performed. + * + * The timestamp is in milliseconds since boot, including time spent in sleep, + * corresponding to values provided by {@link android.os.SystemClock#elapsedRealtime()}. + * + * @param timestamp time stamp in milliseconds. If not set, default to 0. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setRangingTimestampMillis(@ElapsedRealtimeLong long timestamp) { + mTimestamp = timestamp; + return this; + } - /** @hide */ - public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm, - int distanceStdDevMm, int rssi, int numAttemptedMeasurements, - int numSuccessfulMeasurements, byte[] lci, byte[] lcr, - ResponderLocation responderLocation, long timestamp, boolean is80211McMeasurement, - int frequencyMHz, int packetBw) { - mStatus = status; - mMac = mac; - mPeerHandle = null; - mDistanceMm = distanceMm; - mDistanceStdDevMm = distanceStdDevMm; - mRssi = rssi; - mNumAttemptedMeasurements = numAttemptedMeasurements; - mNumSuccessfulMeasurements = numSuccessfulMeasurements; - mLci = lci == null ? EMPTY_BYTE_ARRAY : lci; - mLcr = lcr == null ? EMPTY_BYTE_ARRAY : lcr; - mResponderLocation = responderLocation; - mTimestamp = timestamp; - mIs80211mcMeasurement = is80211McMeasurement; - mFrequencyMHz = frequencyMHz; - mPacketBw = packetBw; - } - /** @hide */ - public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm, - int distanceStdDevMm, int rssi, int numAttemptedMeasurements, - int numSuccessfulMeasurements, byte[] lci, byte[] lcr, - ResponderLocation responderLocation, long timestamp, boolean is80211McMeasurement) { - mStatus = status; - mMac = mac; - mPeerHandle = null; - mDistanceMm = distanceMm; - mDistanceStdDevMm = distanceStdDevMm; - mRssi = rssi; - mNumAttemptedMeasurements = numAttemptedMeasurements; - mNumSuccessfulMeasurements = numSuccessfulMeasurements; - mLci = lci == null ? EMPTY_BYTE_ARRAY : lci; - mLcr = lcr == null ? EMPTY_BYTE_ARRAY : lcr; - mResponderLocation = responderLocation; - mTimestamp = timestamp; - mIs80211mcMeasurement = is80211McMeasurement; - mFrequencyMHz = UNSPECIFIED; - mPacketBw = UNSPECIFIED; + /** + * Sets whether the ranging measurement was performed using IEEE 802.11mc ranging method. + * If {@link #set80211mcMeasurement(boolean)} is set as false and + * {@link #set80211azNtbMeasurement(boolean)} is also set as false, ranging measurement was + * performed using one-side RTT. If not set, default to false. + * + * @param is80211mcMeasurement true for IEEE 802.11mc measure, otherwise false. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder set80211mcMeasurement(boolean is80211mcMeasurement) { + mIs80211mcMeasurement = is80211mcMeasurement; + return this; + } + + /** + * Sets the center frequency of the primary 20 MHz frequency (in MHz) of the channel over + * which the measurement frames are sent. If not set, default to + * {@link RangingResult#UNSPECIFIED} + * + * @param frequencyMHz Frequency. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setMeasurementChannelFrequencyMHz(int frequencyMHz) { + mFrequencyMHz = frequencyMHz; + return this; + } + + /** + * Sets the bandwidth used to transmit the RTT measurement frame. If not set, default to + * {@link RangingResult#UNSPECIFIED}. + * + * @param measurementBandwidth Measurement bandwidth. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setMeasurementBandwidth(@ChannelWidth int measurementBandwidth) { + mPacketBw = measurementBandwidth; + return this; + } + + /** + * Sets whether the ranging measurement was performed using IEEE 802.11az non-trigger + * ranging method. If {@link #set80211azNtbMeasurement(boolean)} is set as false and + * {@link #set80211mcMeasurement(boolean)} is also set as false, ranging measurement was + * performed using one-side RTT. If not set defaults to false. + * + * @param is80211azNtbMeasurement true for IEEE 802.11az non-trigger based measurement, + * otherwise false. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder set80211azNtbMeasurement(boolean is80211azNtbMeasurement) { + mIs80211azNtbMeasurement = is80211azNtbMeasurement; + return this; + } + + /** + * Sets minimum time between measurements in microseconds for IEEE 802.11az non-trigger + * based ranging. If not set, defaults to {@link RangingResult#UNSPECIFIED}. + * + * @param ntbMinMeasurementTime non-trigger based ranging minimum measurement time. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setMinTimeBetweenNtbMeasurementsMicros(long ntbMinMeasurementTime) { + mNtbMinMeasurementTime = ntbMinMeasurementTime; + return this; + } + + /** + * Sets maximum time between measurements in microseconds for IEEE 802.11az non-trigger + * based ranging. If not set, defaults to {@link RangingResult#UNSPECIFIED}. + * + * @param ntbMaxMeasurementTime non-trigger based ranging maximum measurement time. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder setMaxTimeBetweenNtbMeasurementsMicros(long ntbMaxMeasurementTime) { + mNtbMaxMeasurementTime = ntbMaxMeasurementTime; + return this; + } + + /** + * Sets LTF repetitions that the initiator station used in the preamble. If not set, + * defaults to {@link RangingResult#UNSPECIFIED}. + * + * @param i2rTxLtfRepetitions LFT repetition count. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder set80211azInitiatorTxLtfRepetitionsCount(int i2rTxLtfRepetitions) { + mI2rTxLtfRepetitions = i2rTxLtfRepetitions; + return this; + } + + /** + * Sets LTF repetitions that the responder station used in the preamble. If not set, + * defaults to {@link RangingResult#UNSPECIFIED}. + * + * @param r2iTxLtfRepetitions LFT repetition count. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder set80211azResponderTxLtfRepetitionsCount(int r2iTxLtfRepetitions) { + mR2iTxLtfRepetitions = r2iTxLtfRepetitions; + return this; + } + + /** + * Sets number of transmit spatial streams that the initiator station used for the + * ranging result. If not set, defaults to {@link RangingResult#UNSPECIFIED}. + * + * @param numTxSpatialStreams Number of transmit spatial streams. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder set80211azNumberOfTxSpatialStreams(int numTxSpatialStreams) { + mNumTxSpatialStreams = numTxSpatialStreams; + return this; + } + + /** + * Sets number of receive spatial streams that the initiator station used for the ranging + * result. If not set, defaults to {@link RangingResult#UNSPECIFIED}. + * + * @param numRxSpatialStreams Number of receive spatial streams. + * @return The builder to facilitate chaining. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder set80211azNumberOfRxSpatialStreams(int numRxSpatialStreams) { + mNumRxSpatialStreams = numRxSpatialStreams; + return this; + } + + /** + * Set additional vendor-provided configuration data. + * + * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the + * vendor-provided configuration data. Note that multiple elements with + * the same OUI are allowed. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + if (vendorData == null) { + throw new IllegalArgumentException("setVendorData received a null value"); + } + mVendorData = vendorData; + return this; + } + + /** + * Build {@link RangingResult} + * @return an instance of {@link RangingResult} + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public RangingResult build() { + if (mMac == null && mPeerHandle == null) { + throw new IllegalArgumentException("Either MAC address or Peer handle is needed"); + } + if (mIs80211azNtbMeasurement && mIs80211mcMeasurement) { + throw new IllegalArgumentException( + "A ranging result cannot use both IEEE 802.11mc and IEEE 802.11az " + + "measurements simultaneously"); + } + return new RangingResult(this); + } } /** @hide */ - public RangingResult( - @RangeResultStatus int status, - PeerHandle peerHandle, - int distanceMm, - int distanceStdDevMm, - int rssi, - int numAttemptedMeasurements, - int numSuccessfulMeasurements, - byte[] lci, - byte[] lcr, - ResponderLocation responderLocation, - long timestamp, - int frequencyMHz, - int packetBw) { - mStatus = status; - mMac = null; - mPeerHandle = peerHandle; - mDistanceMm = distanceMm; - mDistanceStdDevMm = distanceStdDevMm; - mRssi = rssi; - mNumAttemptedMeasurements = numAttemptedMeasurements; - mNumSuccessfulMeasurements = numSuccessfulMeasurements; - mLci = lci == null ? EMPTY_BYTE_ARRAY : lci; - mLcr = lcr == null ? EMPTY_BYTE_ARRAY : lcr; - mResponderLocation = responderLocation; - mTimestamp = timestamp; - mIs80211mcMeasurement = true; - mFrequencyMHz = frequencyMHz; - mPacketBw = packetBw; + private RangingResult(Builder builder) { + mStatus = builder.mStatus; + mMac = builder.mMac; + mPeerHandle = builder.mPeerHandle; + mDistanceMm = builder.mDistanceMm; + mDistanceStdDevMm = builder.mDistanceStdDevMm; + mRssi = builder.mRssi; + mNumAttemptedMeasurements = builder.mNumAttemptedMeasurements; + mNumSuccessfulMeasurements = builder.mNumSuccessfulMeasurements; + mLci = (builder.mLci == null) ? EMPTY_BYTE_ARRAY : builder.mLci; + mLcr = (builder.mLcr == null) ? EMPTY_BYTE_ARRAY : builder.mLcr; + mResponderLocation = builder.mResponderLocation; + mTimestamp = builder.mTimestamp; + mIs80211mcMeasurement = builder.mIs80211mcMeasurement; + mFrequencyMHz = builder.mFrequencyMHz; + mPacketBw = builder.mPacketBw; + mIs80211azNtbMeasurement = builder.mIs80211azNtbMeasurement; + mNtbMinMeasurementTime = builder.mNtbMinMeasurementTime; + mNtbMaxMeasurementTime = builder.mNtbMaxMeasurementTime; + mI2rTxLtfRepetitions = builder.mI2rTxLtfRepetitions; + mR2iTxLtfRepetitions = builder.mR2iTxLtfRepetitions; + mNumRxSpatialStreams = builder.mNumRxSpatialStreams; + mNumTxSpatialStreams = builder.mNumTxSpatialStreams; + mVendorData = builder.mVendorData; } /** @@ -351,10 +691,8 @@ public final class RangingResult implements Parcelable { * <p> * Note: the information is NOT validated - use with caution. Consider validating it with * other sources of information before using it. - * - * @hide */ - @SystemApi + @SuppressLint("UnflaggedApi") // Flagging API promotion from @SystemApi to public not supported @NonNull public byte[] getLci() { if (mStatus != STATUS_SUCCESS) { @@ -370,10 +708,8 @@ public final class RangingResult implements Parcelable { * <p> * Note: the information is NOT validated - use with caution. Consider validating it with * other sources of information before using it. - * - * @hide */ - @SystemApi + @SuppressLint("UnflaggedApi") // Flagging API promotion from @SystemApi to public not supported @NonNull public byte[] getLcr() { if (mStatus != STATUS_SUCCESS) { @@ -402,9 +738,9 @@ public final class RangingResult implements Parcelable { } /** - * @return The result is true if the IEEE 802.11mc protocol was used (also known as - * two-sided RTT). If the result is false, a one-side RTT result is provided which does not - * subtract the turnaround time at the responder. + * @return The result is true if the IEEE 802.11mc protocol was used. If the result is false, + * and {@link #is80211azNtbMeasurement()} is also false a one-side RTT result is provided + * which does not subtract the turnaround time at the responder. * <p> * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an * exception. @@ -419,6 +755,101 @@ public final class RangingResult implements Parcelable { } /** + * @return The result is true if the IEEE 802.11az non-trigger based protocol was used. If the + * result is false, and {@link #is80211mcMeasurement()} is also false a one-side RTT result + * is provided which does not subtract the turnaround time at the responder. + * <p>. + * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an + * exception. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean is80211azNtbMeasurement() { + if (mStatus != STATUS_SUCCESS) { + throw new IllegalStateException( + "is80211azNtbMeasurement(): invoked on an invalid result: getStatus()=" + + mStatus); + } + return mIs80211azNtbMeasurement; + } + + /** + * Gets minimum time between measurements in microseconds for IEEE 802.11az non-trigger based + * ranging. + * + * The next 11az ranging measurement request must be invoked after the minimum time from the + * last measurement time {@link #getRangingTimestampMillis()} for the peer. Otherwise, cached + * ranging result will be returned for the peer. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public long getMinTimeBetweenNtbMeasurementsMicros() { + return mNtbMinMeasurementTime; + } + + /** + * Gets maximum time between measurements in microseconds for IEEE 802.11az non-trigger based + * ranging. + * + * The next 11az ranging request needs to be invoked before the maximum time from the last + * measurement time {@link #getRangingTimestampMillis()}. Otherwise, the non-trigger based + * ranging session will be terminated and a new ranging negotiation will happen with + * the responding station. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public long getMaxTimeBetweenNtbMeasurementsMicros() { + return mNtbMaxMeasurementTime; + } + + /** + * Gets LTF repetitions that the responder station (RSTA) used in the preamble of the + * responder to initiator (I2R) null data PPDU (NDP) for this result. + * + * LTF repetitions is the multiple transmissions of HE-LTF symbols in an HE ranging NDP. An + * HE-LTF repetition value of 1 indicates no repetitions. + * + * @return LTF repetitions count + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int get80211azResponderTxLtfRepetitionsCount() { + return mR2iTxLtfRepetitions; + } + + /** + * Gets LTF repetitions that the initiator station (ISTA) used in the preamble of the + * initiator to responder (I2R) null data PPDU (NDP) for this result. + * + * LTF repetitions is the multiple transmissions of HE-LTF symbols in an HE ranging NDP. An + * HE-LTF repetition value of 1 indicates no repetitions. + * + * @return LTF repetitions count + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int get80211azInitiatorTxLtfRepetitionsCount() { + return mI2rTxLtfRepetitions; + } + + /** + * Gets number of transmit spatial streams that the initiator station (ISTA) used for the + * initiator to responder (I2R) null data PPDU (NDP) for this result. + * + * @return Number of spatial streams + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int get80211azNumberOfTxSpatialStreams() { + return mNumTxSpatialStreams; + } + + /** + * Gets number of receive spatial streams that the initiator station (ISTA) used for the + * initiator to responder (I2R) null data PPDU (NDP) for this result. + * + * @return Number of spatial streams + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int get80211azNumberOfRxSpatialStreams() { + return mNumRxSpatialStreams; + } + + /** * The center frequency of the primary 20 MHz frequency (in MHz) of the channel over * which the measurement frames are sent. * @return center frequency in Mhz of the channel if available, otherwise {@link #UNSPECIFIED} @@ -456,6 +887,23 @@ public final class RangingResult implements Parcelable { return mPacketBw; } + /** + * Get the vendor-provided configuration data, if it exists. + * + * @return Vendor configuration data, or empty list if it does not exist. + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @SystemApi + @NonNull + public List<OuiKeyedData> getVendorData() { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException(); + } + return mVendorData; + } + @Override public int describeContents() { return 0; @@ -488,6 +936,16 @@ public final class RangingResult implements Parcelable { dest.writeBoolean(mIs80211mcMeasurement); dest.writeInt(mFrequencyMHz); dest.writeInt(mPacketBw); + dest.writeBoolean(mIs80211azNtbMeasurement); + dest.writeLong(mNtbMinMeasurementTime); + dest.writeLong(mNtbMaxMeasurementTime); + dest.writeInt(mI2rTxLtfRepetitions); + dest.writeInt(mR2iTxLtfRepetitions); + dest.writeInt(mNumTxSpatialStreams); + dest.writeInt(mNumRxSpatialStreams); + if (SdkLevel.isAtLeastV()) { + dest.writeList(mVendorData); + } } public static final @android.annotation.NonNull Creator<RangingResult> CREATOR = @@ -499,62 +957,36 @@ public final class RangingResult implements Parcelable { @Override public RangingResult createFromParcel(Parcel in) { - int status = in.readInt(); - boolean macAddressPresent = in.readBoolean(); - MacAddress mac = null; - if (macAddressPresent) { - mac = MacAddress.CREATOR.createFromParcel(in); - } - boolean peerHandlePresent = in.readBoolean(); - PeerHandle peerHandle = null; - if (peerHandlePresent) { - peerHandle = new PeerHandle(in.readInt()); - } - int distanceMm = in.readInt(); - int distanceStdDevMm = in.readInt(); - int rssi = in.readInt(); - int numAttemptedMeasurements = in.readInt(); - int numSuccessfulMeasurements = in.readInt(); - byte[] lci = in.createByteArray(); - byte[] lcr = in.createByteArray(); - ResponderLocation responderLocation = - in.readParcelable(this.getClass().getClassLoader()); - long timestamp = in.readLong(); - boolean isllmcMeasurement = in.readBoolean(); - int frequencyMHz = in.readInt(); - int packetBw = in.readInt(); - if (peerHandlePresent) { - return new RangingResult( - status, - peerHandle, - distanceMm, - distanceStdDevMm, - rssi, - numAttemptedMeasurements, - numSuccessfulMeasurements, - lci, - lcr, - responderLocation, - timestamp, - frequencyMHz, - packetBw); - } else { - return new RangingResult( - status, - mac, - distanceMm, - distanceStdDevMm, - rssi, - numAttemptedMeasurements, - numSuccessfulMeasurements, - lci, - lcr, - responderLocation, - timestamp, - isllmcMeasurement, - frequencyMHz, - packetBw); + RangingResult.Builder builder = new Builder() + .setStatus(in.readInt()) + .setMacAddress( + in.readBoolean() ? MacAddress.CREATOR.createFromParcel(in) + : null) + .setPeerHandle(in.readBoolean() ? new PeerHandle(in.readInt()) : null) + .setDistanceMm(in.readInt()) + .setDistanceStdDevMm(in.readInt()) + .setRssi(in.readInt()) + .setNumAttemptedMeasurements(in.readInt()) + .setNumSuccessfulMeasurements(in.readInt()) + .setLci(in.createByteArray()) + .setLcr(in.createByteArray()) + .setUnverifiedResponderLocation( + in.readParcelable(this.getClass().getClassLoader())) + .setRangingTimestampMillis(in.readLong()) + .set80211mcMeasurement(in.readBoolean()) + .setMeasurementChannelFrequencyMHz(in.readInt()) + .setMeasurementBandwidth(in.readInt()) + .set80211azNtbMeasurement(in.readBoolean()) + .setMinTimeBetweenNtbMeasurementsMicros(in.readLong()) + .setMaxTimeBetweenNtbMeasurementsMicros(in.readLong()) + .set80211azInitiatorTxLtfRepetitionsCount(in.readInt()) + .set80211azResponderTxLtfRepetitionsCount(in.readInt()) + .set80211azNumberOfTxSpatialStreams(in.readInt()) + .set80211azNumberOfRxSpatialStreams(in.readInt()); + if (SdkLevel.isAtLeastV()) { + builder.setVendorData(ParcelUtil.readOuiKeyedDataList(in)); } + return builder.build(); } }; @@ -577,6 +1009,14 @@ public final class RangingResult implements Parcelable { .append(mIs80211mcMeasurement) .append(", frequencyMHz=").append(mFrequencyMHz) .append(", packetBw=").append(mPacketBw) + .append("is80211azNtbMeasurement").append(mIs80211azNtbMeasurement) + .append("ntbMinMeasurementTime").append(mNtbMinMeasurementTime) + .append("ntbMaxMeasurementTime").append(mNtbMaxMeasurementTime) + .append("i2rTxLtfRepetitions").append(mI2rTxLtfRepetitions) + .append("r2iTxLtfRepetitions").append(mR2iTxLtfRepetitions) + .append("txSpatialStreams").append(mNumTxSpatialStreams) + .append("rxSpatialStreams").append(mNumRxSpatialStreams) + .append(", vendorData=").append(mVendorData) .append("]").toString(); } @@ -602,7 +1042,15 @@ public final class RangingResult implements Parcelable { && mIs80211mcMeasurement == lhs.mIs80211mcMeasurement && Objects.equals(mResponderLocation, lhs.mResponderLocation) && mFrequencyMHz == lhs.mFrequencyMHz - && mPacketBw == lhs.mPacketBw; + && mPacketBw == lhs.mPacketBw + && mIs80211azNtbMeasurement == lhs.mIs80211azNtbMeasurement + && mNtbMinMeasurementTime == lhs.mNtbMinMeasurementTime + && mNtbMaxMeasurementTime == lhs.mNtbMaxMeasurementTime + && mI2rTxLtfRepetitions == lhs.mI2rTxLtfRepetitions + && mR2iTxLtfRepetitions == lhs.mR2iTxLtfRepetitions + && mNumTxSpatialStreams == lhs.mNumTxSpatialStreams + && mNumRxSpatialStreams == lhs.mNumRxSpatialStreams + && Objects.equals(mVendorData, lhs.mVendorData); } @Override @@ -610,6 +1058,8 @@ public final class RangingResult implements Parcelable { return Objects.hash(mStatus, mMac, mPeerHandle, mDistanceMm, mDistanceStdDevMm, mRssi, mNumAttemptedMeasurements, mNumSuccessfulMeasurements, Arrays.hashCode(mLci), Arrays.hashCode(mLcr), mResponderLocation, mTimestamp, mIs80211mcMeasurement, - mFrequencyMHz, mPacketBw); + mFrequencyMHz, mPacketBw, mIs80211azNtbMeasurement, mNtbMinMeasurementTime, + mNtbMaxMeasurementTime, mI2rTxLtfRepetitions, mR2iTxLtfRepetitions, + mNumTxSpatialStreams, mR2iTxLtfRepetitions, mVendorData); } } diff --git a/framework/java/android/net/wifi/rtt/ResponderConfig.java b/framework/java/android/net/wifi/rtt/ResponderConfig.java index c42c47c81f..5db9290b32 100644 --- a/framework/java/android/net/wifi/rtt/ResponderConfig.java +++ b/framework/java/android/net/wifi/rtt/ResponderConfig.java @@ -22,6 +22,7 @@ import static android.net.wifi.ScanResult.InformationElement.EID_EXT_HE_CAPABILI import static android.net.wifi.ScanResult.InformationElement.EID_HT_CAPABILITIES; import static android.net.wifi.ScanResult.InformationElement.EID_VHT_CAPABILITIES; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -35,6 +36,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import com.android.wifi.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -139,7 +142,6 @@ public final class ResponderConfig implements Parcelable { @SystemApi public static final int CHANNEL_WIDTH_320MHZ = 5; - /** @hide */ @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT, PREAMBLE_HE, PREAMBLE_EHT}) @Retention(RetentionPolicy.SOURCE) @@ -181,6 +183,9 @@ public final class ResponderConfig implements Parcelable { @SystemApi public static final int PREAMBLE_EHT = 4; + private static final long DEFAULT_NTB_MIN_TIME_BETWEEN_MEASUREMENTS_MICROS = 250000; + private static final long DEFAULT_NTB_MAX_TIME_BETWEEN_MEASUREMENTS_MICROS = 15000000; + /** * The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the * peerHandle field) ise used to identify the Responder. @@ -212,6 +217,14 @@ public final class ResponderConfig implements Parcelable { public final boolean supports80211mc; /** + * Indicates whether the Responder device supports IEEE 802.11az non-trigger based ranging. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public final boolean supports80211azNtb; + + /** * Responder channel bandwidth, specified using {@link ChannelWidth}. * @hide */ @@ -249,6 +262,33 @@ public final class ResponderConfig implements Parcelable { @SystemApi public final int preamble; + private long mNtbMinMeasurementTime = DEFAULT_NTB_MIN_TIME_BETWEEN_MEASUREMENTS_MICROS; + private long mNtbMaxMeasurementTime = DEFAULT_NTB_MAX_TIME_BETWEEN_MEASUREMENTS_MICROS; + + /** + * Constructs Responder configuration from the builder + * @param builder See {@link Builder} + * @hide + */ + public ResponderConfig(Builder builder) { + if (builder.mMacAddress == null && builder.mPeerHandle == null) { + throw new IllegalArgumentException( + "Invalid ResponderConfig - must specify a MAC address or Peer handle"); + } + this.macAddress = builder.mMacAddress; + this.peerHandle = builder.mPeerHandle; + this.responderType = builder.mResponderType; + this.supports80211mc = builder.mSupports80211Mc; + this.supports80211azNtb = builder.mSupports80211azNtb; + this.channelWidth = builder.mChannelWidth; + this.frequency = builder.mFrequency; + this.centerFreq0 = builder.mCenterFreq0; + this.centerFreq1 = builder.mCenterFreq1; + this.preamble = builder.mPreamble; + this.mNtbMinMeasurementTime = builder.mNtbMinMeasurementTime; + this.mNtbMaxMeasurementTime = builder.mNtbMaxMeasurementTime; + } + /** * Constructs Responder configuration, using a MAC address to identify the Responder. * @@ -289,6 +329,9 @@ public final class ResponderConfig implements Parcelable { this.centerFreq0 = centerFreq0; this.centerFreq1 = centerFreq1; this.preamble = preamble; + this.supports80211azNtb = false; + this.mNtbMinMeasurementTime = DEFAULT_NTB_MIN_TIME_BETWEEN_MEASUREMENTS_MICROS; + this.mNtbMaxMeasurementTime = DEFAULT_NTB_MAX_TIME_BETWEEN_MEASUREMENTS_MICROS; } /** @@ -326,6 +369,9 @@ public final class ResponderConfig implements Parcelable { this.centerFreq0 = centerFreq0; this.centerFreq1 = centerFreq1; this.preamble = preamble; + this.supports80211azNtb = false; + this.mNtbMinMeasurementTime = DEFAULT_NTB_MIN_TIME_BETWEEN_MEASUREMENTS_MICROS; + this.mNtbMaxMeasurementTime = DEFAULT_NTB_MAX_TIME_BETWEEN_MEASUREMENTS_MICROS; } /** @@ -367,6 +413,9 @@ public final class ResponderConfig implements Parcelable { this.centerFreq0 = centerFreq0; this.centerFreq1 = centerFreq1; this.preamble = preamble; + this.supports80211azNtb = false; + this.mNtbMinMeasurementTime = DEFAULT_NTB_MIN_TIME_BETWEEN_MEASUREMENTS_MICROS; + this.mNtbMaxMeasurementTime = DEFAULT_NTB_MAX_TIME_BETWEEN_MEASUREMENTS_MICROS; } /** @@ -378,7 +427,8 @@ public final class ResponderConfig implements Parcelable { MacAddress macAddress = MacAddress.fromString(scanResult.BSSID); int responderType = RESPONDER_AP; boolean supports80211mc = scanResult.is80211mcResponder(); - int channelWidth = translateFromScanResultToLocalChannelWidth(scanResult.channelWidth); + boolean supports80211azNtbRanging = scanResult.is80211azNtbResponder(); + int channelWidth = scanResult.channelWidth; int frequency = scanResult.frequency; int centerFreq0 = scanResult.centerFreq0; int centerFreq1 = scanResult.centerFreq1; @@ -403,30 +453,39 @@ public final class ResponderConfig implements Parcelable { } if (ehtCapabilitiesPresent && ScanResult.is6GHz(frequency)) { - preamble = PREAMBLE_EHT; + preamble = ScanResult.PREAMBLE_EHT; } else if (heCapabilitiesPresent && ScanResult.is6GHz(frequency)) { - preamble = PREAMBLE_HE; + preamble = ScanResult.PREAMBLE_HE; } else if (vhtCapabilitiesPresent) { - preamble = PREAMBLE_VHT; + preamble = ScanResult.PREAMBLE_VHT; } else if (htCapabilitiesPresent) { - preamble = PREAMBLE_HT; + preamble = ScanResult.PREAMBLE_HT; } else { - preamble = PREAMBLE_LEGACY; + preamble = ScanResult.PREAMBLE_LEGACY; } } else { Log.e(TAG, "Scan Results do not contain IEs - using backup method to select preamble"); - if (channelWidth == CHANNEL_WIDTH_320MHZ) { - preamble = PREAMBLE_EHT; - } else if (channelWidth == CHANNEL_WIDTH_80MHZ - || channelWidth == CHANNEL_WIDTH_160MHZ) { - preamble = PREAMBLE_VHT; + if (channelWidth == ScanResult.CHANNEL_WIDTH_320MHZ) { + preamble = ScanResult.PREAMBLE_EHT; + } else if (channelWidth == ScanResult.CHANNEL_WIDTH_80MHZ + || channelWidth == ScanResult.CHANNEL_WIDTH_160MHZ) { + preamble = ScanResult.PREAMBLE_VHT; } else { - preamble = PREAMBLE_HT; + preamble = ScanResult.PREAMBLE_HT; } } - return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, - frequency, centerFreq0, centerFreq1, preamble); + return new ResponderConfig.Builder() + .setMacAddress(macAddress) + .setResponderType(responderType) + .set80211mcSupported(supports80211mc) + .set80211azNtbSupported(supports80211azNtbRanging) + .setChannelWidth(channelWidth) + .setFrequencyMhz(frequency) + .setCenterFreq0Mhz(centerFreq0) + .setCenterFreq1Mhz(centerFreq1) + .setPreamble(preamble) + .build(); } /** @@ -443,8 +502,10 @@ public final class ResponderConfig implements Parcelable { * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware * Unsolicited Publisher with Ranging enabled. */ - return new ResponderConfig(macAddress, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, - AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); + return new ResponderConfig.Builder() + .setMacAddress(macAddress) + .setResponderType(RESPONDER_AWARE) + .build(); } /** @@ -461,8 +522,24 @@ public final class ResponderConfig implements Parcelable { * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware * Unsolicited Publisher with Ranging enabled. */ - return new ResponderConfig(peerHandle, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, - AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); + return new ResponderConfig.Builder() + .setPeerHandle(peerHandle) + .setResponderType(RESPONDER_AWARE) + .build(); + } + + private static boolean isResponderTypeSupported(@ResponderType int responderType) { + switch (responderType) { + case RESPONDER_AP: + case RESPONDER_STA: + case RESPONDER_AWARE: + break; + case RESPONDER_P2P_GO: + case RESPONDER_P2P_CLIENT: + default: + return false; + } + return true; } /** @@ -473,6 +550,7 @@ public final class ResponderConfig implements Parcelable { * @hide */ public boolean isValid(boolean awareSupported) { + if (!isResponderTypeSupported(responderType)) return false; if (macAddress == null && peerHandle == null || macAddress != null && peerHandle != null) { return false; } @@ -491,6 +569,16 @@ public final class ResponderConfig implements Parcelable { } /** + * @return the peer handle of the responder + * + * @hide + */ + @Nullable + public PeerHandle getPeerHandle() { + return peerHandle; + } + + /** * @return true if the Responder supports the 802.11mc protocol, false otherwise. */ public boolean is80211mcSupported() { @@ -498,6 +586,15 @@ public final class ResponderConfig implements Parcelable { } /** + * @return true if the Responder supports the 802.11az non-trigger based ranging protocol, + * false otherwise. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public boolean is80211azNtbSupported() { + return supports80211azNtb; + } + + /** * AP Channel bandwidth; one of {@link ScanResult#CHANNEL_WIDTH_20MHZ}, * {@link ScanResult#CHANNEL_WIDTH_40MHZ}, * {@link ScanResult#CHANNEL_WIDTH_80MHZ}, {@link ScanResult#CHANNEL_WIDTH_160MHZ}, @@ -559,17 +656,55 @@ public final class ResponderConfig implements Parcelable { } /** + * Gets the minimum time between IEEE 802.11az non-trigger based ranging measurements in + * microseconds for the responder. + * + * @hide + */ + public long getNtbMinTimeBetweenMeasurementsMicros() { + return mNtbMinMeasurementTime; + } + + /** + * Gets the maximum time between IEEE 802.11az non-trigger based ranging measurements in + * microseconds for the responder. + * + * @hide + */ + public long getNtbMaxTimeBetweenMeasurementsMicros() { + return mNtbMaxMeasurementTime; + } + + /** + * @hide + */ + public void setNtbMinTimeBetweenMeasurementsMicros(long ntbMinMeasurementTime) { + this.mNtbMinMeasurementTime = ntbMinMeasurementTime; + } + + /** + * @hide + */ + public void setNtbMaxTimeBetweenMeasurementsMicros(long ntbMaxMeasurementTime) { + this.mNtbMaxMeasurementTime = ntbMaxMeasurementTime; + } + + /** * Builder class used to construct {@link ResponderConfig} objects. */ public static final class Builder { private MacAddress mMacAddress; + private PeerHandle mPeerHandle; private @ResponderType int mResponderType = RESPONDER_AP; private boolean mSupports80211Mc = true; + private boolean mSupports80211azNtb = false; private @ChannelWidth int mChannelWidth = CHANNEL_WIDTH_20MHZ; private int mFrequency = 0; private int mCenterFreq0 = 0; private int mCenterFreq1 = 0; private @PreambleType int mPreamble = PREAMBLE_LEGACY; + private long mNtbMinMeasurementTime = DEFAULT_NTB_MIN_TIME_BETWEEN_MEASUREMENTS_MICROS; + private long mNtbMaxMeasurementTime = DEFAULT_NTB_MAX_TIME_BETWEEN_MEASUREMENTS_MICROS; /** * Sets the Responder MAC Address. @@ -585,6 +720,20 @@ public final class ResponderConfig implements Parcelable { } /** + * Sets the Responder Peer handle. + * + * @param peerHandle Peer handle of the resposnde + * @return the builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + * @hide + */ + @NonNull + public Builder setPeerHandle(@NonNull PeerHandle peerHandle) { + this.mPeerHandle = peerHandle; + return this; + } + + /** * Sets an indication the access point can to respond to the two-sided Wi-Fi RTT protocol, * but, if false, indicates only one-sided Wi-Fi RTT is possible. * @@ -599,6 +748,23 @@ public final class ResponderConfig implements Parcelable { } /** + * Sets an indication the access point can to respond to the IEEE 802.11az non-trigger + * based ranging protocol, but, if false, indicates only IEEE 802.11mc or one-sided Wi-Fi + * RTT is possible. + * + * @param supports80211azNtb the ability to support the IEEE 802.11az non-trigger based + * ranging protocol + * @return the builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public Builder set80211azNtbSupported(boolean supports80211azNtb) { + this.mSupports80211azNtb = supports80211azNtb; + return this; + } + + /** * Sets the channel bandwidth in MHz. * * @param channelWidth the bandwidth of the channel in MHz @@ -679,7 +845,8 @@ public final class ResponderConfig implements Parcelable { } /** - * Sets the responder type, can be {@link #RESPONDER_AP} or {@link #RESPONDER_STA} + * Sets the responder type, can be {@link #RESPONDER_AP} or {@link #RESPONDER_STA} or + * {@link #RESPONDER_AWARE} * * @param responderType the type of the responder, if not set defaults to * {@link #RESPONDER_AP} @@ -687,25 +854,80 @@ public final class ResponderConfig implements Parcelable { */ @NonNull public Builder setResponderType(@ResponderType int responderType) { - if (responderType != RESPONDER_STA && responderType != RESPONDER_AP) { - throw new IllegalArgumentException("invalid responder type"); + if (!isResponderTypeSupported(responderType)) { + throw new IllegalArgumentException("invalid responder type " + responderType); } mResponderType = responderType; return this; } /** + * Sets the minimum time between IEEE 802.11az non-trigger based ranging measurements in + * microseconds for the responder. + * + * Note: This should be a multiple of 100 microseconds as per IEEE 802.11 az standard. + * + * @param ntbMinMeasurementTime Minimum time between non-trigger based IEEE 802.11az + * ranging measurements in units of 100 microseconds. Range of + * values (0, 419430400). + * @hide + */ + public Builder setNtbMinTimeBetweenMeasurementsMicros(long ntbMinMeasurementTime) { + if (mNtbMinMeasurementTime == 0 || mNtbMinMeasurementTime >= 419430400) { + throw new IllegalArgumentException( + "Should be a non-zero number less than 419430400 microseconds"); + } + if (mNtbMinMeasurementTime % 100 != 0) { + throw new IllegalArgumentException("Should be a multiple of 100 microseconds"); + } + mNtbMinMeasurementTime = ntbMinMeasurementTime; + return this; + } + + /** + * Sets the maximum time between IEEE 802.11az non-trigger based ranging measurements in + * microseconds for the responder. + * + * Note: This should be a multiple of 10000 microseconds (10 milliseconds) as per + * IEEE 802.11 az standard. + * + * @param ntbMaxMeasurementTime Maximum time between non-trigger based IEEE 802.11az + * ranging measurements in units of 10000 microseconds. Range + * of values (0, 5242880000). + * @hide + */ + public Builder setNtbMaxTimeBetweenMeasurementsMicros(long ntbMaxMeasurementTime) { + if (mNtbMaxMeasurementTime % 10000 != 0) { + throw new IllegalArgumentException("Should be a multiple of 10000 microseconds"); + } + if (mNtbMaxMeasurementTime == 0 || mNtbMaxMeasurementTime >= 5242880000L) { + throw new IllegalArgumentException( + "Should be a non-zero number less than 5242880000 microseconds"); + } + mNtbMaxMeasurementTime = ntbMaxMeasurementTime; + return this; + } + + /** * Build {@link ResponderConfig} given the current configurations made on the builder. * @return an instance of {@link ResponderConfig} */ @NonNull public ResponderConfig build() { - if (mMacAddress == null) { + if ((mMacAddress == null && mPeerHandle == null) + || (mMacAddress != null && mPeerHandle != null)) { throw new IllegalArgumentException( - "Invalid ResponderConfig - must specify a MAC address"); + "Invalid ResponderConfig - must specify a MAC address or peer handle but " + + "not both"); + } + // For Aware, use supported default values + if (mResponderType == RESPONDER_AWARE) { + mSupports80211Mc = true; + mFrequency = AWARE_BAND_2_DISCOVERY_CHANNEL; + mChannelWidth = CHANNEL_WIDTH_20MHZ; + mPreamble = PREAMBLE_HT; } - return new ResponderConfig(mMacAddress, mResponderType, mSupports80211Mc, mChannelWidth, - mFrequency, mCenterFreq0, mCenterFreq1, mPreamble); + return new ResponderConfig(this); } } @@ -729,12 +951,15 @@ public final class ResponderConfig implements Parcelable { dest.writeInt(peerHandle.peerId); } dest.writeInt(responderType); - dest.writeInt(supports80211mc ? 1 : 0); + dest.writeBoolean(supports80211mc); + dest.writeBoolean(supports80211azNtb); dest.writeInt(channelWidth); dest.writeInt(frequency); dest.writeInt(centerFreq0); dest.writeInt(centerFreq1); dest.writeInt(preamble); + dest.writeLong(mNtbMinMeasurementTime); + dest.writeLong(mNtbMaxMeasurementTime); } public static final @android.annotation.NonNull Creator<ResponderConfig> CREATOR = new Creator<ResponderConfig>() { @@ -755,21 +980,21 @@ public final class ResponderConfig implements Parcelable { if (peerHandlePresent) { peerHandle = new PeerHandle(in.readInt()); } - int responderType = in.readInt(); - boolean supports80211mc = in.readInt() == 1; - int channelWidth = in.readInt(); - int frequency = in.readInt(); - int centerFreq0 = in.readInt(); - int centerFreq1 = in.readInt(); - int preamble = in.readInt(); - - if (peerHandle == null) { - return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, - frequency, centerFreq0, centerFreq1, preamble); - } else { - return new ResponderConfig(peerHandle, responderType, supports80211mc, channelWidth, - frequency, centerFreq0, centerFreq1, preamble); - } + + return new ResponderConfig.Builder() + .setMacAddress(macAddress) + .setPeerHandle(peerHandle) + .setResponderType(in.readInt()) + .set80211mcSupported(in.readBoolean()) + .set80211azNtbSupported(in.readBoolean()) + .setChannelWidth(in.readInt()) + .setFrequencyMhz(in.readInt()) + .setCenterFreq0Mhz(in.readInt()) + .setCenterFreq1Mhz(in.readInt()) + .setPreamble(in.readInt()) + .setNtbMinTimeBetweenMeasurementsMicros(in.readLong()) + .setNtbMaxTimeBetweenMeasurementsMicros(in.readLong()) + .build(); } }; @@ -789,24 +1014,34 @@ public final class ResponderConfig implements Parcelable { lhs.peerHandle) && responderType == lhs.responderType && supports80211mc == lhs.supports80211mc && channelWidth == lhs.channelWidth && frequency == lhs.frequency && centerFreq0 == lhs.centerFreq0 - && centerFreq1 == lhs.centerFreq1 && preamble == lhs.preamble; + && centerFreq1 == lhs.centerFreq1 && preamble == lhs.preamble + && supports80211azNtb == lhs.supports80211azNtb + && mNtbMinMeasurementTime == lhs.mNtbMinMeasurementTime + && mNtbMaxMeasurementTime == lhs.mNtbMaxMeasurementTime; } @Override public int hashCode() { return Objects.hash(macAddress, peerHandle, responderType, supports80211mc, channelWidth, - frequency, centerFreq0, centerFreq1, preamble); + frequency, centerFreq0, centerFreq1, preamble, supports80211azNtb, + mNtbMinMeasurementTime, mNtbMaxMeasurementTime); } @Override public String toString() { - return new StringBuffer("ResponderConfig: macAddress=").append(macAddress).append( - ", peerHandle=").append(peerHandle == null ? "<null>" : peerHandle.peerId).append( - ", responderType=").append(responderType).append(", supports80211mc=").append( - supports80211mc).append(", channelWidth=").append(channelWidth).append( - ", frequency=").append(frequency).append(", centerFreq0=").append( - centerFreq0).append(", centerFreq1=").append(centerFreq1).append( - ", preamble=").append(preamble).toString(); + return new StringBuffer("ResponderConfig: macAddress=").append(macAddress) + .append(", peerHandle=").append(peerHandle == null ? "<null>" : peerHandle.peerId) + .append(", responderType=").append(responderType) + .append(", supports80211mc=").append(supports80211mc) + .append(", channelWidth=").append(channelWidth) + .append(", frequency=").append(frequency) + .append(", centerFreq0=").append(centerFreq0) + .append(", centerFreq1=").append(centerFreq1) + .append(", preamble=").append(preamble) + .append(", supports80211azNtb=").append(supports80211azNtb) + .append(", mNtbMinMeasurementTime ").append(mNtbMinMeasurementTime) + .append(", mNtbMaxMeasurementTime ").append(mNtbMaxMeasurementTime) + .toString(); } /** diff --git a/framework/java/android/net/wifi/rtt/WifiRttManager.java b/framework/java/android/net/wifi/rtt/WifiRttManager.java index 69bf608f9b..f86eaa4382 100644 --- a/framework/java/android/net/wifi/rtt/WifiRttManager.java +++ b/framework/java/android/net/wifi/rtt/WifiRttManager.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.LOCATION_HARDWARE; import static android.Manifest.permission.NEARBY_WIFI_DEVICES; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -40,6 +41,7 @@ import android.os.WorkSource; import android.util.Log; import com.android.modules.utils.build.SdkLevel; +import com.android.wifi.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -108,12 +110,19 @@ public class WifiRttManager { */ public static final String CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER = "key_sta_responder"; + /** + * Bundle key to access if device supports to be a IEEE 802.11az non-trigger based initiator + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final String CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR = "key_ntb_initiator"; + /** @hide */ @StringDef(prefix = { "CHARACTERISTICS_KEY_"}, value = { CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT, CHARACTERISTICS_KEY_BOOLEAN_LCI, CHARACTERISTICS_KEY_BOOLEAN_LCR, CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER, + CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR, }) @Retention(RetentionPolicy.SOURCE) public @interface RttCharacteristicsKey {} diff --git a/framework/java/android/net/wifi/twt/TwtRequest.java b/framework/java/android/net/wifi/twt/TwtRequest.java new file mode 100644 index 0000000000..6bad0168d6 --- /dev/null +++ b/framework/java/android/net/wifi/twt/TwtRequest.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2024 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 android.net.wifi.twt; + +import static android.net.wifi.MloLink.INVALID_MLO_LINK_ID; +import static android.net.wifi.MloLink.MAX_MLO_LINK_ID; +import static android.net.wifi.MloLink.MIN_MLO_LINK_ID; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.net.wifi.MloLink; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.wifi.flags.Flags; + +/** + * Defines target wake time (TWT) request class. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +public final class TwtRequest implements Parcelable { + private final int mMinWakeDurationMicros; + private final int mMaxWakeDurationMicros; + private final long mMinWakeIntervalMicros; + private final long mMaxWakeIntervalMicros; + private final int mLinkId; + + private TwtRequest(TwtRequest.Builder builder) { + mMinWakeDurationMicros = builder.mMinWakeDurationMicros; + mMaxWakeDurationMicros = builder.mMaxWakeDurationMicros; + mMinWakeIntervalMicros = builder.mMinWakeIntervalMicros; + mMaxWakeIntervalMicros = builder.mMaxWakeIntervalMicros; + mLinkId = builder.mLinkId; + } + + /** + * Get minimum TWT wake duration in microseconds. + * + * @return Minimum wake duration in microseconds + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int getMinWakeDurationMicros() { + return mMinWakeDurationMicros; + } + + /** + * Get maximum TWT wake duration in microseconds. + * + * @return Maximum wake duration in microseconds + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int getMaxWakeDurationMicros() { + return mMaxWakeDurationMicros; + } + + /** + * Get minimum TWT wake interval in microseconds. + * + * @return Minimum wake interval in microseconds + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public long getMinWakeIntervalMicros() { + return mMinWakeIntervalMicros; + } + + /** + * Get maximum TWT wake interval in microseconds. + * + * @return Maximum wake interval in microseconds + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public long getMaxWakeIntervalMicros() { + return mMaxWakeIntervalMicros; + } + + + /** + * Get link id (valid only in case of Multi-link operation). + * + * @return MLO link id in the range {@link MloLink#MIN_MLO_LINK_ID} to + * {@link MloLink#MAX_MLO_LINK_ID}. Returns {@link MloLink#INVALID_MLO_LINK_ID} if not set. + */ + @IntRange(from = INVALID_MLO_LINK_ID, to = MAX_MLO_LINK_ID) + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public int getLinkId() { + return mLinkId; + } + + @NonNull + public static final Creator<TwtRequest> CREATOR = new Creator<TwtRequest>() { + @Override + public TwtRequest createFromParcel(Parcel in) { + Builder builder = new TwtRequest.Builder(in.readInt(), in.readInt(), in.readLong(), + in.readLong()); + int mloLinkId = in.readInt(); + if (mloLinkId >= MIN_MLO_LINK_ID && mloLinkId <= MAX_MLO_LINK_ID) { + builder.setLinkId(mloLinkId); + } + return builder.build(); + } + + @Override + public TwtRequest[] newArray(int size) { + return new TwtRequest[size]; + } + }; + + + /** + * Describe the kinds of special objects contained in this Parcelable + * instance's marshaled representation. + * + * @return a bitmask indicating the set of special object types marshaled + * by this Parcelable object instance. + */ + @Override + public int describeContents() { + return 0; + } + + /** + * Flatten this object in to a Parcel. + * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mMinWakeDurationMicros); + dest.writeInt(mMaxWakeDurationMicros); + dest.writeLong(mMinWakeIntervalMicros); + dest.writeLong(mMinWakeIntervalMicros); + dest.writeInt(mLinkId); + } + + /** + * Builder class used to construct {@link TwtRequest} objects. + * + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public static final class Builder { + private final int mMinWakeDurationMicros; + private final int mMaxWakeDurationMicros; + private final long mMinWakeIntervalMicros; + private final long mMaxWakeIntervalMicros; + private int mLinkId = INVALID_MLO_LINK_ID; + + /** + * Set link id (valid only in case of Multi-link operation). + * + * @param linkId Link id, which should be in the range {@link MloLink#MIN_MLO_LINK_ID} to + * {@link MloLink#MAX_MLO_LINK_ID} + * @return The builder to facilitate chaining + * @throws IllegalArgumentException if argument is invalid + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public TwtRequest.Builder setLinkId( + @IntRange(from = MIN_MLO_LINK_ID, to = MAX_MLO_LINK_ID) int linkId) { + if (linkId < MIN_MLO_LINK_ID || linkId > MAX_MLO_LINK_ID) { + throw new IllegalArgumentException("linkId is out of range"); + } + mLinkId = linkId; + return this; + } + + /** + * Constructor for {@link TwtRequest.Builder}. + * + * @param minWakeDurationMicros Minimum TWT wake duration in microseconds. + * @param maxWakeDurationMicros Maximum TWT wake duration in microseconds + * @param minWakeIntervalMicros Minimum TWT wake interval in microseconds + * @param maxWakeIntervalMicros Maximum TWT wake interval in microseconds + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + public Builder(int minWakeDurationMicros, int maxWakeDurationMicros, + long minWakeIntervalMicros, long maxWakeIntervalMicros) { + mMinWakeDurationMicros = minWakeDurationMicros; + mMaxWakeDurationMicros = maxWakeDurationMicros; + mMinWakeIntervalMicros = minWakeIntervalMicros; + mMaxWakeIntervalMicros = maxWakeIntervalMicros; + } + + /** + * Build {@link TwtRequest} given the current configurations made on the builder. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + @NonNull + public TwtRequest build() { + return new TwtRequest(this); + } + } +} diff --git a/framework/java/android/net/wifi/twt/TwtSession.java b/framework/java/android/net/wifi/twt/TwtSession.java new file mode 100644 index 0000000000..7c7f2a3127 --- /dev/null +++ b/framework/java/android/net/wifi/twt/TwtSession.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2024 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 android.net.wifi.twt; + +import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.StringDef; +import android.annotation.SystemApi; +import android.os.Bundle; + +import com.android.wifi.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * Defines a target wake time (TWT) session. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +public interface TwtSession { + /** + * Bundle key to get average number of received packets in each wake duration + */ + String TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT = "key_avg_rx_pkt_count"; + /** + * Bundle key to get average number of transmitted packets in each wake duration + */ + String TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT = "key_avg_tx_pkt_count"; + /** + * Bundle key to get average bytes per received packets in each wake duration + */ + String TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE = "key_avg_rx_pkt_size"; + /** + * Bundle key to get average bytes per transmitted packets in each wake duration + */ + String TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE = "key_avg_tx_pkt_size"; + /** + * Bundle key to get average end of service period in microseconds + */ + String TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS = "key_avg_eosp_dur"; + /** + * Bundle key to get count of early termination. Value will be -1 if not available. + */ + String TWT_STATS_KEY_INT_EOSP_COUNT = "key_eosp_count"; + + /** @hide */ + @StringDef(prefix = { "TWT_STATS_KEY_"}, value = { + TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT, + TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT, + TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE, + TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE, + TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS, + TWT_STATS_KEY_INT_EOSP_COUNT + }) + @Retention(RetentionPolicy.SOURCE) + @interface TwtStats {} + /** + * Get TWT session wake duration in microseconds. + * + * @return wake duration in microseconds. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + int getWakeDurationMicros(); + + /** + * Get TWT session wake interval in microseconds. + * + * @return wake interval in microseconds. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + long getWakeIntervalMicros(); + + /** + * Get MLO link id if the station connection is Wi-Fi 7, otherwise returns + * {@link android.net.wifi.MloLink#INVALID_MLO_LINK_ID}. + * + * @return MLO link id + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + int getMloLinkId(); + + /** + * Get stats of the session. + * + * Note: If the command fails or not available, -1 will be returned for all stats values. + * + * @param executor The executor on which callback will be invoked. + * @param resultCallback An asynchronous callback that will return a bundle for target wake time + * stats. See {@link TwtStats} for the string keys for the bundle. + * @throws SecurityException if the caller does not have permission. + * @throws NullPointerException if the caller provided null inputs. + * @throws UnsupportedOperationException if the API is not supported. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + void getStats(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Bundle> resultCallback); + + /** + * Teardown the session. See {@link TwtSessionCallback#onTeardown(int)}. Also closes this + * session, relinquishing any underlying resources. + * + * @throws SecurityException if the caller does not have permission. + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + void teardown(); +} diff --git a/framework/java/android/net/wifi/twt/TwtSessionCallback.java b/framework/java/android/net/wifi/twt/TwtSessionCallback.java new file mode 100644 index 0000000000..6efedd6cd2 --- /dev/null +++ b/framework/java/android/net/wifi/twt/TwtSessionCallback.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2024 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 android.net.wifi.twt; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import com.android.wifi.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * API interface for target wake time (TWT) session Callback. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) +public interface TwtSessionCallback { + /** + * Generic error + */ + int TWT_ERROR_CODE_FAIL = 0; + /** + * AP does not support TWT + */ + int TWT_ERROR_CODE_AP_NOT_SUPPORTED = 1; + /** + * AP is blocklisted due to interoperability issue reported with TWT + */ + int TWT_ERROR_CODE_AP_OUI_BLOCKLISTED = 2; + /** + * AP rejects TWT request + */ + int TWT_ERROR_CODE_AP_REJECTED = 3; + /** + * Invalid parameters + */ + int TWT_ERROR_CODE_INVALID_PARAMS = 4; + /** + * Maximum TWT sessions reached + */ + int TWT_ERROR_CODE_MAX_SESSIONS_REACHED = 5; + /** + * TWT is not available now + */ + int TWT_ERROR_CODE_NOT_AVAILABLE = 6; + /** + * TWT is not supported by the local device + */ + int TWT_ERROR_CODE_NOT_SUPPORTED = 7; + /** + * TWT operation Timed out + */ + int TWT_ERROR_CODE_TIMEOUT = 8; + + /** + * @hide + */ + @IntDef(prefix = {"TWT_ERROR_CODE_"}, value = {TWT_ERROR_CODE_FAIL, + TWT_ERROR_CODE_AP_NOT_SUPPORTED, TWT_ERROR_CODE_AP_OUI_BLOCKLISTED, + TWT_ERROR_CODE_AP_REJECTED, TWT_ERROR_CODE_INVALID_PARAMS, + TWT_ERROR_CODE_MAX_SESSIONS_REACHED, TWT_ERROR_CODE_NOT_AVAILABLE, + TWT_ERROR_CODE_NOT_SUPPORTED, TWT_ERROR_CODE_TIMEOUT}) + @Retention(RetentionPolicy.SOURCE) + @interface TwtErrorCode { + } + + /** + * Unknown reason code + */ + int TWT_REASON_CODE_UNKNOWN = 0; + /** + * Locally requested + */ + int TWT_REASON_CODE_LOCALLY_REQUESTED = 1; + /** + * Internally initiated by the driver or firmware + */ + int TWT_REASON_CODE_INTERNALLY_INITIATED = 2; + /** + * Peer initiated + */ + int TWT_REASON_CODE_PEER_INITIATED = 3; + + /** + * @hide + */ + @IntDef(prefix = {"TWT_REASON_CODE_"}, value = {TWT_REASON_CODE_UNKNOWN, + TWT_REASON_CODE_LOCALLY_REQUESTED, TWT_REASON_CODE_INTERNALLY_INITIATED, + TWT_REASON_CODE_PEER_INITIATED}) + @Retention(RetentionPolicy.SOURCE) + @interface TwtReasonCode { + } + + /** + * Called when a TWT operation fails. + * + * @param errorCode error code + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + void onFailure(@TwtSessionCallback.TwtErrorCode int errorCode); + + /** + * Called when a TWT session is torn down or closed. Check the + * {@link TwtReasonCode} for more details. + * + * @param reasonCode reason for TWT session teardown + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + void onTeardown(@TwtSessionCallback.TwtReasonCode int reasonCode); + + /** + * Called when the TWT session is created. + * + * @param twtSession TWT session + */ + @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API) + void onCreate(@NonNull TwtSession twtSession); +} diff --git a/framework/tests/src/android/net/wifi/MscsParamsTest.java b/framework/tests/src/android/net/wifi/MscsParamsTest.java new file mode 100644 index 0000000000..701511abde --- /dev/null +++ b/framework/tests/src/android/net/wifi/MscsParamsTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 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 android.net.wifi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.os.Parcel; + +import com.android.modules.utils.build.SdkLevel; + +import org.junit.Before; +import org.junit.Test; + +public class MscsParamsTest { + private static final int TEST_FRAME_CLASSIFIER_FIELDS = + MscsParams.FRAME_CLASSIFIER_IP_VERSION | MscsParams.FRAME_CLASSIFIER_SRC_PORT; + private static final int TEST_USER_PRIORITY_BITMAP = 1 << 7; + private static final int TEST_USER_PRIORITY_LIMIT = 5; + private static final int TEST_STREAM_TIMEOUT_US = 5550; + + @Before + public void setUp() { + assumeTrue(SdkLevel.isAtLeastV()); + } + + /** Create an MscsParams object with all fields set to the test values. */ + private MscsParams createTestMscsParams() { + return new MscsParams.Builder() + .setFrameClassifierFields(TEST_FRAME_CLASSIFIER_FIELDS) + .setUserPriorityBitmap(TEST_USER_PRIORITY_BITMAP) + .setUserPriorityLimit(TEST_USER_PRIORITY_LIMIT) + .setStreamTimeoutUs(TEST_STREAM_TIMEOUT_US) + .build(); + } + + /** Test that an exception is thrown when invalid values are provided to the builder. */ + @Test + public void testBuilderInvalid() { + MscsParams.Builder builder = new MscsParams.Builder(); + + // Bitmap arguments can only use bits 0 - 7. + assertThrows(IllegalArgumentException.class, + () -> builder.setFrameClassifierFields(1 << 8)); + assertThrows(IllegalArgumentException.class, + () -> builder.setUserPriorityBitmap(1 << 8)); + + // User priority limit must be between 0 - 7 (inclusive) + assertThrows(IllegalArgumentException.class, + () -> builder.setUserPriorityLimit(-1)); + assertThrows(IllegalArgumentException.class, + () -> builder.setUserPriorityLimit(8)); + + // Stream timeout value must be between 0 - 60 seconds. + assertThrows(IllegalArgumentException.class, + () -> builder.setStreamTimeoutUs(-1)); + assertThrows(IllegalArgumentException.class, + () -> builder.setStreamTimeoutUs(MscsParams.MAX_STREAM_TIMEOUT_US + 1)); + } + + /** + * Tests that the builder works as expected when provided valid values. + * Fields that are unset should be assigned their default value. + */ + @Test + public void testBuilderValid() { + MscsParams params = new MscsParams.Builder() + .setFrameClassifierFields(TEST_FRAME_CLASSIFIER_FIELDS) + .setUserPriorityLimit(TEST_USER_PRIORITY_LIMIT) + .build(); + assertEquals(TEST_FRAME_CLASSIFIER_FIELDS, params.getFrameClassifierFields()); + assertEquals(TEST_USER_PRIORITY_LIMIT, params.getUserPriorityLimit()); + + // Fields that were not explicitly assigned should be given a default value. + assertEquals(MscsParams.DEFAULT_USER_PRIORITY_BITMAP, params.getUserPriorityBitmap()); + assertEquals(MscsParams.MAX_STREAM_TIMEOUT_US, params.getStreamTimeoutUs()); + } + + /** + * Tests that all fields are assigned a default value if they are not explicitly + * assigned in the builder. + */ + @Test + public void testBuilderDefaultValues() { + MscsParams params = new MscsParams.Builder().build(); + assertEquals(MscsParams.DEFAULT_FRAME_CLASSIFIER_FIELDS, params.getFrameClassifierFields()); + assertEquals(MscsParams.DEFAULT_USER_PRIORITY_BITMAP, params.getUserPriorityBitmap()); + assertEquals(MscsParams.DEFAULT_USER_PRIORITY_LIMIT, params.getUserPriorityLimit()); + assertEquals(MscsParams.MAX_STREAM_TIMEOUT_US, params.getStreamTimeoutUs()); + } + + /** Tests that this class can be properly parceled and unparceled. */ + @Test + public void testParcelReadWrite() { + MscsParams params = createTestMscsParams(); + Parcel parcel = Parcel.obtain(); + params.writeToParcel(parcel, 0); + parcel.setDataPosition(0); // Rewind data position back to the beginning for read. + MscsParams unparceledParams = MscsParams.CREATOR.createFromParcel(parcel); + assertTrue(unparceledParams.equals(params)); + } + + /** Tests the equality and hashcode operations on equivalent instances. */ + @Test + public void testSameObjectComparison() { + MscsParams params1 = createTestMscsParams(); + MscsParams params2 = createTestMscsParams(); + assertTrue(params1.equals(params2)); + assertEquals(params1.hashCode(), params2.hashCode()); + } + + /** Tests the equality and hashcode operations on different instances. */ + @Test + public void testDifferentObjectComparison() { + MscsParams testParams = createTestMscsParams(); + MscsParams defaultParams = new MscsParams.Builder().build(); + assertFalse(testParams.equals(defaultParams)); + assertNotEquals(testParams.hashCode(), defaultParams.hashCode()); + } +} diff --git a/framework/tests/src/android/net/wifi/OuiKeyedDataUtil.java b/framework/tests/src/android/net/wifi/OuiKeyedDataUtil.java new file mode 100644 index 0000000000..1fe0d32f86 --- /dev/null +++ b/framework/tests/src/android/net/wifi/OuiKeyedDataUtil.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 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 android.net.wifi; + +import android.os.PersistableBundle; + +import java.util.ArrayList; +import java.util.List; + +/** Test utils for {@link OuiKeyedData} */ +public class OuiKeyedDataUtil { + private static final String STRING_FIELD_KEY = "stringField"; + private static final String ARRAY_FIELD_KEY = "arrayField"; + + private static final String STRING_FIELD_VALUE = "someString"; + private static final int[] ARRAY_FIELD_VALUE = new int[] {1, 2, 3}; + + /** + * Generate a single OuiKeyedData object containing several test fields. + */ + public static OuiKeyedData createTestOuiKeyedData(int oui) { + PersistableBundle bundle = new PersistableBundle(); + bundle.putString(STRING_FIELD_KEY, STRING_FIELD_VALUE); + bundle.putIntArray(ARRAY_FIELD_KEY, ARRAY_FIELD_VALUE); + return new OuiKeyedData.Builder(oui, bundle).build(); + } + + /** + * Generate a list of OuiKeyedData objects, each containing several test fields. + */ + public static List<OuiKeyedData> createTestOuiKeyedDataList(int size) { + List<OuiKeyedData> ouiKeyedDataList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + ouiKeyedDataList.add(createTestOuiKeyedData(i + 1)); + } + return ouiKeyedDataList; + } +} diff --git a/framework/tests/src/android/net/wifi/QosCharacteristicsTest.java b/framework/tests/src/android/net/wifi/QosCharacteristicsTest.java new file mode 100644 index 0000000000..4876fc18c6 --- /dev/null +++ b/framework/tests/src/android/net/wifi/QosCharacteristicsTest.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import static android.net.wifi.QosCharacteristics.DELIVERY_RATIO_95; +import static android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_9999; + +import static junit.framework.Assert.assertFalse; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.os.Parcel; + +import com.android.modules.utils.build.SdkLevel; + +import org.junit.Before; +import org.junit.Test; + +public class QosCharacteristicsTest { + private static final int TEST_MIN_SERVICE_INTERVAL_MICROS = 2000; + private static final int TEST_MAX_SERVICE_INTERVAL_MICROS = 5000; + private static final int TEST_MIN_DATA_RATE_KBPS = 500; + private static final int TEST_BURST_SIZE_OCTETS = 2; + private static final int TEST_DELAY_BOUND_MICROS = 200; + private static final int TEST_MAX_MSDU_SIZE_OCTETS = 4; + private static final int TEST_SERVICE_START_TIME_MICROS = 250; + private static final int TEST_SERVICE_START_TIME_LINK_ID = 0x5; + private static final int TEST_MEAN_DATA_RATE_KBPS = 1500; + private static final int TEST_MSDU_LIFETIME_MILLIS = 400; + private static final int TEST_DELIVERY_RATIO = QosCharacteristics.DELIVERY_RATIO_99; + private static final int TEST_COUNT_EXPONENT = 5; + + @Before + public void setUp() { + assumeTrue(SdkLevel.isAtLeastV()); + } + + /** + * Get a Builder with the mandatory fields set to the default test values. + */ + private static QosCharacteristics.Builder getDefaultBuilder() { + return new QosCharacteristics.Builder( + TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, + TEST_MIN_DATA_RATE_KBPS, TEST_DELAY_BOUND_MICROS); + } + + /** + * Get a QosCharacteristics with all fields set to the default test values. + */ + private static QosCharacteristics getDefaultQosCharacteristics() { + return getDefaultBuilder() + .setMaxMsduSizeOctets(TEST_MAX_MSDU_SIZE_OCTETS) + .setServiceStartTimeInfo( + TEST_SERVICE_START_TIME_MICROS, TEST_SERVICE_START_TIME_LINK_ID) + .setMeanDataRateKbps(TEST_MEAN_DATA_RATE_KBPS) + .setBurstSizeOctets(TEST_BURST_SIZE_OCTETS) + .setMsduLifetimeMillis(TEST_MSDU_LIFETIME_MILLIS) + .setMsduDeliveryInfo(TEST_DELIVERY_RATIO, TEST_COUNT_EXPONENT) + .build(); + } + + /** + * Verify that all fields in the QosCharacteristics object contain the default test values. + */ + private static void validateDefaultFields(QosCharacteristics qosCharacteristics) { + assertEquals(TEST_MIN_SERVICE_INTERVAL_MICROS, + qosCharacteristics.getMinServiceIntervalMicros()); + assertEquals(TEST_MAX_SERVICE_INTERVAL_MICROS, + qosCharacteristics.getMaxServiceIntervalMicros()); + assertEquals(TEST_MIN_DATA_RATE_KBPS, qosCharacteristics.getMinDataRateKbps()); + assertEquals(TEST_DELAY_BOUND_MICROS, qosCharacteristics.getDelayBoundMicros()); + + assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MAX_MSDU_SIZE)); + assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.SERVICE_START_TIME)); + assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MEAN_DATA_RATE)); + assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.BURST_SIZE)); + assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MSDU_LIFETIME)); + assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MSDU_DELIVERY_INFO)); + + assertEquals(TEST_MAX_MSDU_SIZE_OCTETS, qosCharacteristics.getMaxMsduSizeOctets()); + assertEquals(TEST_SERVICE_START_TIME_MICROS, + qosCharacteristics.getServiceStartTimeMicros()); + assertEquals(TEST_SERVICE_START_TIME_LINK_ID, + qosCharacteristics.getServiceStartTimeLinkId()); + assertEquals(TEST_MEAN_DATA_RATE_KBPS, qosCharacteristics.getMeanDataRateKbps()); + assertEquals(TEST_BURST_SIZE_OCTETS, qosCharacteristics.getBurstSizeOctets()); + assertEquals(TEST_MSDU_LIFETIME_MILLIS, qosCharacteristics.getMsduLifetimeMillis()); + assertEquals(TEST_DELIVERY_RATIO, qosCharacteristics.getDeliveryRatio()); + assertEquals(TEST_COUNT_EXPONENT, qosCharacteristics.getCountExponent()); + } + + /** + * Test that the builder works correctly when provided valid values. + */ + @Test + public void testBuilderValid() { + QosCharacteristics qosCharacteristics = getDefaultQosCharacteristics(); + validateDefaultFields(qosCharacteristics); + } + + /** + * Test that an exception is thrown if any of the mandatory fields are assigned an + * invalid value. + */ + @Test + public void testMandatoryFieldsInvalid() { + // All mandatory fields must be positive. + assertThrows(IllegalArgumentException.class, () -> + new QosCharacteristics.Builder( + 0, TEST_MAX_SERVICE_INTERVAL_MICROS, + TEST_MIN_DATA_RATE_KBPS, TEST_DELAY_BOUND_MICROS).build()); + assertThrows(IllegalArgumentException.class, () -> + new QosCharacteristics.Builder( + TEST_MIN_SERVICE_INTERVAL_MICROS, 0, + TEST_MIN_DATA_RATE_KBPS, TEST_DELAY_BOUND_MICROS).build()); + assertThrows(IllegalArgumentException.class, () -> + new QosCharacteristics.Builder( + TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, + 0, TEST_DELAY_BOUND_MICROS).build()); + assertThrows(IllegalArgumentException.class, () -> + new QosCharacteristics.Builder( + TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, + TEST_MIN_DATA_RATE_KBPS, 0).build()); + + // Min service interval must be less than or equal to the max service interval. + assertThrows(IllegalArgumentException.class, () -> + new QosCharacteristics.Builder( + 5000 /* minServiceInterval */, 3000 /* maxServiceInterval */, + TEST_MIN_DATA_RATE_KBPS, 0).build()); + } + + /** + * Test that an exception is thrown if any optional values that expect a positive value + * are assigned a zero value. + */ + @Test + public void testOptionalFieldsInvalid_zeroValue() { + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder().setMaxMsduSizeOctets(0).build()); + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder().setMeanDataRateKbps(0).build()); + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder().setBurstSizeOctets(0).build()); + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder().setMsduLifetimeMillis(0).build()); + } + + /** + * Test that an exception is thrown if any optional values that expect a <32-bit value are + * assigned a value that exceeds the expected bit size. + */ + @Test + public void testOptionalFieldsInvalid_exceedUpperBound() { + // Expects 16-bit value + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder().setMaxMsduSizeOctets(0x1FFFF).build()); + + // Expects 16-bit value + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder().setMsduLifetimeMillis(0x1FFFF).build()); + + // Expects 4-bit link ID + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder() + .setServiceStartTimeInfo(TEST_SERVICE_START_TIME_MICROS, 0x1F).build()); + } + + /** + * Test that an exception is thrown if any additional constraints on the optional fields + * are broken. + */ + @Test + public void testOptionalFieldsInvalid_additionalConstraints() { + // MSDU lifetime should be >= the delay bound + int delayBoundUs = 30_000; // 30 ms + int msduLifetimeMs = 20; + assertThrows(IllegalArgumentException.class, () -> + new QosCharacteristics.Builder( + TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, + TEST_MIN_DATA_RATE_KBPS, delayBoundUs) + .setMsduLifetimeMillis(msduLifetimeMs) + .build()); + + // MSDU delivery ratio should be a valid enum + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder() + .setMsduDeliveryInfo(DELIVERY_RATIO_95 - 1, TEST_COUNT_EXPONENT) + .build()); + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder() + .setMsduDeliveryInfo(DELIVERY_RATIO_99_9999 + 1, TEST_COUNT_EXPONENT) + .build()); + + // MSDU count exponent should be between 0 and 15 (inclusive) + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder() + .setMsduDeliveryInfo(TEST_DELIVERY_RATIO, -1) + .build()); + assertThrows(IllegalArgumentException.class, () -> + getDefaultBuilder() + .setMsduDeliveryInfo(TEST_DELIVERY_RATIO, 16) + .build()); + } + + /** + * Test that an exception is thrown if the caller attempts to get an optional field + * that was not assigned a value. + */ + @Test + public void testOptionalFields_unsetException() { + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getMaxMsduSizeOctets()); + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getServiceStartTimeMicros()); + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getServiceStartTimeLinkId()); + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getMeanDataRateKbps()); + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getBurstSizeOctets()); + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getMsduLifetimeMillis()); + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getDeliveryRatio()); + assertThrows(IllegalStateException.class, () -> + getDefaultBuilder().build().getCountExponent()); + } + + /** + * Tests that the parceling logic can properly read and write from a Parcel. + */ + @Test + public void testParcelReadWrite() { + QosCharacteristics qosCharacteristics = getDefaultQosCharacteristics(); + Parcel parcel = Parcel.obtain(); + qosCharacteristics.writeToParcel(parcel, 0); + parcel.setDataPosition(0); // Rewind data position back to the beginning for read. + QosCharacteristics unparceledQosCharacteristics = + QosCharacteristics.CREATOR.createFromParcel(parcel); + validateDefaultFields(unparceledQosCharacteristics); + } + + /** + * Tests that the overridden equality and hashCode operators properly compare the same object. + */ + @Test + public void testSameObjectComparison() { + QosCharacteristics qosCharacteristics1 = getDefaultQosCharacteristics(); + QosCharacteristics qosCharacteristics2 = getDefaultQosCharacteristics(); + assertTrue(qosCharacteristics1.equals(qosCharacteristics2)); + assertEquals(qosCharacteristics1.hashCode(), qosCharacteristics2.hashCode()); + } + + /** + * Tests that the overridden equality and hashCode operators properly compare different objects. + */ + @Test + public void testDifferentObjectComparison() { + QosCharacteristics qosCharacteristics1 = getDefaultQosCharacteristics(); + QosCharacteristics qosCharacteristics2 = getDefaultBuilder().build(); + assertFalse(qosCharacteristics1.equals(qosCharacteristics2)); + assertNotEquals(qosCharacteristics1.hashCode(), qosCharacteristics2.hashCode()); + } +} diff --git a/framework/tests/src/android/net/wifi/QosPolicyParamsTest.java b/framework/tests/src/android/net/wifi/QosPolicyParamsTest.java index cb50bac307..fe40e2158c 100644 --- a/framework/tests/src/android/net/wifi/QosPolicyParamsTest.java +++ b/framework/tests/src/android/net/wifi/QosPolicyParamsTest.java @@ -62,19 +62,36 @@ public class QosPolicyParamsTest { } /** - * Creates a QosPolicyParams object will all fields assigned to a default test value. + * Creates a QosCharacteristics object with all fields assigned to a default value. + */ + private static QosCharacteristics createTestQosCharacteristics() { + int minServiceIntervalMicros = 2000; + int maxServiceIntervalMicros = 5000; + int minDataRateKbps = 500; + int delayBoundMicros = 200; + return new QosCharacteristics.Builder( + minServiceIntervalMicros, maxServiceIntervalMicros, + minDataRateKbps, delayBoundMicros).build(); + } + + /** + * Creates a QosPolicyParams object with all fields assigned to a default test value. */ private QosPolicyParams createTestQosPolicyParams() { - return new QosPolicyParams.Builder(TEST_POLICY_ID, TEST_DIRECTION) - .setUserPriority(TEST_USER_PRIORITY) - .setIpVersion(TEST_IP_VERSION) - .setDscp(TEST_DSCP) - .setSourcePort(TEST_SOURCE_PORT) - .setProtocol(TEST_PROTOCOL) - .setDestinationPort(TEST_DESTINATION_PORT) - .setSourceAddress(getInetAddress(TEST_SOURCE_ADDRESS)) - .setDestinationAddress(getInetAddress(TEST_DESTINATION_ADDRESS)) - .build(); + QosPolicyParams.Builder builder = + new QosPolicyParams.Builder(TEST_POLICY_ID, TEST_DIRECTION) + .setUserPriority(TEST_USER_PRIORITY) + .setIpVersion(TEST_IP_VERSION) + .setDscp(TEST_DSCP) + .setSourcePort(TEST_SOURCE_PORT) + .setProtocol(TEST_PROTOCOL) + .setDestinationPort(TEST_DESTINATION_PORT) + .setSourceAddress(getInetAddress(TEST_SOURCE_ADDRESS)) + .setDestinationAddress(getInetAddress(TEST_DESTINATION_ADDRESS)); + if (SdkLevel.isAtLeastV()) { + builder.setQosCharacteristics(createTestQosCharacteristics()); + } + return builder.build(); } /** @@ -91,6 +108,10 @@ public class QosPolicyParamsTest { assertEquals(TEST_DESTINATION_PORT, params.getDestinationPort()); assertTrue(getInetAddress(TEST_SOURCE_ADDRESS).equals(params.getSourceAddress())); assertTrue(getInetAddress(TEST_DESTINATION_ADDRESS).equals(params.getDestinationAddress())); + if (SdkLevel.isAtLeastV()) { + QosCharacteristics testQosCharacteristics = createTestQosCharacteristics(); + assertEquals(testQosCharacteristics, params.getQosCharacteristics()); + } } /** @@ -139,6 +160,10 @@ public class QosPolicyParamsTest { // Policies for downlink are required to have a User Priority and IP Version. new QosPolicyParams.Builder(TEST_POLICY_ID, QosPolicyParams.DIRECTION_DOWNLINK) .build()); + assertThrows(IllegalArgumentException.class, () -> + // Policies for uplink are required to have QoS characteristics. + new QosPolicyParams.Builder(TEST_POLICY_ID, QosPolicyParams.DIRECTION_UPLINK) + .build()); } /** diff --git a/framework/tests/src/android/net/wifi/ScanResultTest.java b/framework/tests/src/android/net/wifi/ScanResultTest.java index 14a9aef830..32265c3279 100644 --- a/framework/tests/src/android/net/wifi/ScanResultTest.java +++ b/framework/tests/src/android/net/wifi/ScanResultTest.java @@ -262,6 +262,8 @@ public class ScanResultTest { + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " + "standard: 11ac, " + "80211mcResponder: is not supported, " + + "80211azNtbResponder: is not supported, " + + "TWT Responder: no, " + "Radio Chain Infos: null, interface name: test_ifname", scanResult.toString()); } @@ -284,6 +286,8 @@ public class ScanResultTest { + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " + "standard: 11ac, " + "80211mcResponder: is not supported, " + + "80211azNtbResponder: is not supported, " + + "TWT Responder: no, " + "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, " + "RadioChainInfo: id=1, level=-54], interface name: test_ifname", scanResult.toString()); @@ -302,6 +306,8 @@ public class ScanResultTest { + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " + "standard: 11ac, " + "80211mcResponder: is not supported, " + + "80211azNtbResponder: is not supported, " + + "TWT Responder: no, " + "Radio Chain Infos: null, interface name: test_ifname", scanResult.toString()); } diff --git a/framework/tests/src/android/net/wifi/SoftApInfoTest.java b/framework/tests/src/android/net/wifi/SoftApInfoTest.java index f415447b6a..b2f9e35844 100644 --- a/framework/tests/src/android/net/wifi/SoftApInfoTest.java +++ b/framework/tests/src/android/net/wifi/SoftApInfoTest.java @@ -17,6 +17,8 @@ package android.net.wifi; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import android.net.MacAddress; import android.os.Parcel; @@ -27,6 +29,8 @@ import com.android.modules.utils.build.SdkLevel; import org.junit.Test; +import java.util.List; + /** * Unit tests for {@link android.net.wifi.SoftApInfo}. */ @@ -38,6 +42,9 @@ public class SoftApInfoTest { private static final int TEST_WIFI_STANDARD = ScanResult.WIFI_STANDARD_LEGACY; private static final MacAddress TEST_AP_MAC = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); private static final long TEST_SHUTDOWN_TIMEOUT_MILLIS = 100_000; + private static final List<OuiKeyedData> TEST_VENDOR_DATA = + OuiKeyedDataUtil.createTestOuiKeyedDataList(5); + /** * Verifies copy constructor. */ @@ -49,7 +56,9 @@ public class SoftApInfoTest { info.setBssid(TEST_AP_MAC); info.setWifiStandard(TEST_WIFI_STANDARD); info.setApInstanceIdentifier(TEST_AP_INSTANCE); - + if (SdkLevel.isAtLeastV()) { + info.setVendorData(TEST_VENDOR_DATA); + } SoftApInfo copiedInfo = new SoftApInfo(info); @@ -68,6 +77,9 @@ public class SoftApInfoTest { info.setBssid(TEST_AP_MAC); info.setWifiStandard(TEST_WIFI_STANDARD); info.setApInstanceIdentifier(TEST_AP_INSTANCE); + if (SdkLevel.isAtLeastV()) { + info.setVendorData(TEST_VENDOR_DATA); + } Parcel parcelW = Parcel.obtain(); info.writeToParcel(parcelW, 0); @@ -97,6 +109,9 @@ public class SoftApInfoTest { assertEquals(info.getWifiStandard(), ScanResult.WIFI_STANDARD_UNKNOWN); assertEquals(info.getApInstanceIdentifier(), null); } + if (SdkLevel.isAtLeastV()) { + assertNotNull(info.getVendorData()); + } } /** @@ -119,6 +134,10 @@ public class SoftApInfoTest { assertEquals(info.getApInstanceIdentifier(), TEST_AP_INSTANCE); } assertEquals(info.getAutoShutdownTimeoutMillis(), TEST_SHUTDOWN_TIMEOUT_MILLIS); + if (SdkLevel.isAtLeastV()) { + info.setVendorData(TEST_VENDOR_DATA); + assertTrue(TEST_VENDOR_DATA.equals(info.getVendorData())); + } } } diff --git a/framework/tests/src/android/net/wifi/UriParserResultsTest.java b/framework/tests/src/android/net/wifi/UriParserResultsTest.java new file mode 100644 index 0000000000..a5f4b2238c --- /dev/null +++ b/framework/tests/src/android/net/wifi/UriParserResultsTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import com.android.net.module.util.MacAddressUtils; + +import org.junit.Test; + +/** Unit tests for {@link android.net.wifi.UriParserResults}. */ +@SmallTest +public class UriParserResultsTest { + private static final String TEST_PUBLIC_KEY = "testPublicKey"; + private static final String TEST_INFORMATION = "testInformation"; + + WifiConfiguration generateTestWifiConfig() { + WifiConfiguration config = new WifiConfiguration(); + final String mSsid = "\"TestAP\""; + final String bSsid = MacAddressUtils.createRandomUnicastAddress().toString(); + config.SSID = mSsid; + config.BSSID = bSsid; + return config; + } + + private void testParcelOperation(UriParserResults testResult) throws Exception { + Parcel parcelW = Parcel.obtain(); + testResult.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + UriParserResults fromParcel = UriParserResults.CREATOR.createFromParcel(parcelR); + + assertEquals(testResult, fromParcel); + assertEquals(testResult.hashCode(), fromParcel.hashCode()); + } + + /** Verifies parcel serialization/deserialization. */ + @Test + public void testParcelOperation() throws Exception { + final WifiConfiguration testWifiConfig = generateTestWifiConfig(); + testParcelOperation( + new UriParserResults( + UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG, + null, + null, + testWifiConfig)); + testParcelOperation( + new UriParserResults( + UriParserResults.URI_SCHEME_DPP, + TEST_PUBLIC_KEY, + TEST_INFORMATION, + null)); + } + + @Test + public void testGetXXXMethods() throws Exception { + final WifiConfiguration testWifiConfig = generateTestWifiConfig(); + UriParserResults testResultZxing = + new UriParserResults( + UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG, + null, + null, + testWifiConfig); + assertEquals( + testResultZxing.getUriScheme(), + UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG); + assertNull(testResultZxing.getPublicKey()); + assertNull(testResultZxing.getInformation()); + assertEquals(testWifiConfig.toString(), testResultZxing.getWifiConfiguration().toString()); + + UriParserResults testResultDpp = + new UriParserResults( + UriParserResults.URI_SCHEME_DPP, + TEST_PUBLIC_KEY, + TEST_INFORMATION, + null); + assertEquals(testResultDpp.getUriScheme(), UriParserResults.URI_SCHEME_DPP); + assertEquals(testResultDpp.getPublicKey(), TEST_PUBLIC_KEY); + assertEquals(testResultDpp.getInformation(), TEST_INFORMATION); + assertNull(testResultDpp.getWifiConfiguration()); + } +} diff --git a/framework/tests/src/android/net/wifi/WifiConfigurationTest.java b/framework/tests/src/android/net/wifi/WifiConfigurationTest.java index defcc5248c..240f2d1373 100644 --- a/framework/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/framework/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -41,6 +41,7 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; +import static org.mockito.Mockito.mock; import android.net.MacAddress; import android.net.ProxyInfo; @@ -62,6 +63,7 @@ import org.junit.Before; import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.List; @@ -122,6 +124,9 @@ public class WifiConfigurationTest { config.setSubscriptionGroup(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB")); config.getNetworkSelectionStatus().setDisableTime(12333); config.getNetworkSelectionStatus().setDisableEndTime(45666); + if (SdkLevel.isAtLeastV()) { + config.setVendorData(OuiKeyedDataUtil.createTestOuiKeyedDataList(5)); + } assertEquals(12333, config.getNetworkSelectionStatus().getDisableTime()); assertEquals(45666, config.getNetworkSelectionStatus().getDisableEndTime()); Parcel parcelW = Parcel.obtain(); @@ -160,6 +165,9 @@ public class WifiConfigurationTest { reconfig.getNetworkSelectionStatus().getDisableTime()); assertEquals(config.getNetworkSelectionStatus().getDisableEndTime(), reconfig.getNetworkSelectionStatus().getDisableEndTime()); + if (SdkLevel.isAtLeastV()) { + assertTrue(config.getVendorData().equals(reconfig.getVendorData())); + } Parcel parcelWW = Parcel.obtain(); reconfig.writeToParcel(parcelWW, 0); @@ -186,6 +194,9 @@ public class WifiConfigurationTest { config.restricted = true; config.isCurrentlyConnected = true; config.setIsUserSelected(true); + if (SdkLevel.isAtLeastV()) { + config.setVendorData(OuiKeyedDataUtil.createTestOuiKeyedDataList(5)); + } WifiConfiguration reconfig = new WifiConfiguration(config); @@ -203,6 +214,9 @@ public class WifiConfigurationTest { assertTrue(reconfig.restricted); assertTrue(reconfig.isCurrentlyConnected); assertTrue(reconfig.isUserSelected()); + if (SdkLevel.isAtLeastV()) { + assertTrue(config.getVendorData().equals(reconfig.getVendorData())); + } } @Test @@ -1406,4 +1420,18 @@ public class WifiConfigurationTest { assertTrue(config.getAllNetworkKeys().contains( config.getNetworkKeyFromSecurityType(SECURITY_TYPE_PASSPOINT_R1_R2))); } + + /** + * Verifies that vendor data can be set and retrieved successfully. + */ + @Test + public void testSetAndGetVendorData() { + assumeTrue(SdkLevel.isAtLeastV()); + WifiConfiguration config = new WifiConfiguration(); + assertNotNull(config.getVendorData()); // non-null default value + + List<OuiKeyedData> vendorData = Arrays.asList(mock(OuiKeyedData.class)); + config.setVendorData(vendorData); + assertTrue(vendorData.equals(config.getVendorData())); + } } diff --git a/framework/tests/src/android/net/wifi/WifiInfoTest.java b/framework/tests/src/android/net/wifi/WifiInfoTest.java index d860b7b713..b751b4fba1 100644 --- a/framework/tests/src/android/net/wifi/WifiInfoTest.java +++ b/framework/tests/src/android/net/wifi/WifiInfoTest.java @@ -73,6 +73,8 @@ public class WifiInfoTest { private static final int TEST_MLO_LINK_ID = 3; private static final int TEST_CHANNEL = 36; private static final int TEST_LINK_SPEED = 300; + private static final List<OuiKeyedData> TEST_VENDOR_DATA = + OuiKeyedDataUtil.createTestOuiKeyedDataList(5); private void addMloInfo(WifiInfo info) { info.setApMldMacAddress(MacAddress.fromString(AP_MLD_MAC_ADDRESS)); @@ -164,6 +166,9 @@ public class WifiInfoTest { if (SdkLevel.isAtLeastT()) { addMloInfo(info); } + if (SdkLevel.isAtLeastV()) { + info.setVendorData(TEST_VENDOR_DATA); + } return info; } @@ -211,6 +216,9 @@ public class WifiInfoTest { if (SdkLevel.isAtLeastT()) { assertMloNoRedaction(info); } + if (SdkLevel.isAtLeastV()) { + assertTrue(TEST_VENDOR_DATA.equals(info.getVendorData())); + } } /** @@ -521,6 +529,9 @@ public class WifiInfoTest { writeWifiInfo.setIsPrimary(true); writeWifiInfo.setRestricted(true); writeWifiInfo.enableApTidToLinkMappingNegotiationSupport(true); + if (SdkLevel.isAtLeastV()) { + writeWifiInfo.setVendorData(TEST_VENDOR_DATA); + } WifiInfo readWifiInfo = new WifiInfo(writeWifiInfo); @@ -548,6 +559,9 @@ public class WifiInfoTest { assertTrue(readWifiInfo.isPrimary()); } assertTrue(readWifiInfo.isApTidToLinkMappingNegotiationSupported()); + if (SdkLevel.isAtLeastV()) { + assertTrue(TEST_VENDOR_DATA.equals(readWifiInfo.getVendorData())); + } } /** @@ -577,6 +591,10 @@ public class WifiInfoTest { assertNull(wifiInfo.getApMldMacAddress()); assertEquals(0, wifiInfo.getAffiliatedMloLinks().size()); assertFalse(wifiInfo.isApTidToLinkMappingNegotiationSupported()); + if (SdkLevel.isAtLeastV()) { + assertNotNull(wifiInfo.getVendorData()); + assertTrue(wifiInfo.getVendorData().isEmpty()); + } } /** diff --git a/framework/tests/src/android/net/wifi/WifiManagerTest.java b/framework/tests/src/android/net/wifi/WifiManagerTest.java index 9f2c44a40c..c9355bda6d 100644 --- a/framework/tests/src/android/net/wifi/WifiManagerTest.java +++ b/framework/tests/src/android/net/wifi/WifiManagerTest.java @@ -45,6 +45,7 @@ import static android.net.wifi.WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MBB; import static android.net.wifi.WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET; import static android.net.wifi.WifiManager.WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED; import static android.net.wifi.WifiManager.WIFI_FEATURE_AP_STA; +import static android.net.wifi.WifiManager.WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED; import static android.net.wifi.WifiManager.WIFI_FEATURE_DECORATED_IDENTITY; import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP; import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP_AKM; @@ -58,9 +59,9 @@ import static android.net.wifi.WifiManager.WIFI_FEATURE_SCANNER; import static android.net.wifi.WifiManager.WIFI_FEATURE_T2LM_NEGOTIATION; import static android.net.wifi.WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE; import static android.net.wifi.WifiManager.WIFI_FEATURE_WEP; -import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA_PERSONAL; import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE; import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B; +import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA_PERSONAL; import static android.net.wifi.WifiManager.WpsCallback; import static org.junit.Assert.assertArrayEquals; @@ -100,6 +101,7 @@ import android.content.pm.ApplicationInfo; import android.net.DhcpInfo; import android.net.DhcpOption; import android.net.MacAddress; +import android.net.TetheringManager; import android.net.wifi.WifiManager.ActiveCountryCodeChangedCallback; import android.net.wifi.WifiManager.CoexCallback; import android.net.wifi.WifiManager.LocalOnlyHotspotCallback; @@ -120,6 +122,8 @@ import android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats; import android.net.wifi.WifiUsabilityStatsEntry.LinkStats; import android.net.wifi.WifiUsabilityStatsEntry.RadioStats; import android.net.wifi.WifiUsabilityStatsEntry.RateStats; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSessionCallback; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -185,6 +189,10 @@ public class WifiManagerTest { private static final byte[] TEST_OUI = new byte[]{0x01, 0x02, 0x03}; private static final int TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS = 1000; + private static final TetheringManager.TetheringRequest TEST_TETHERING_REQUEST = + new TetheringManager.TetheringRequest.Builder(TetheringManager.TETHERING_WIFI).build(); + private static final String TEST_INTERFACE_NAME = "test-wlan0"; + @Mock Context mContext; @Mock android.net.wifi.IWifiManager mWifiService; @Mock ApplicationInfo mApplicationInfo; @@ -1288,9 +1296,14 @@ public class WifiManagerTest { mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback); verify(mWifiService).registerSoftApCallback(callbackCaptor.capture()); - callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLED, 0); + SoftApState state = new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME); + callbackCaptor.getValue().onStateChanged(state); mLooper.dispatchAll(); verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); + ArgumentCaptor<SoftApState> softApStateCaptor = ArgumentCaptor.forClass(SoftApState.class); + verify(mSoftApCallback).onStateChanged(softApStateCaptor.capture()); + assertEquals(state, softApStateCaptor.getValue()); } /* @@ -1810,9 +1823,12 @@ public class WifiManagerTest { mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback); verify(mWifiService).registerSoftApCallback(callbackCaptor.capture()); - final List<WifiClient> testClients = new ArrayList(); - callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0); - callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); + SoftApState state0 = new SoftApState(WIFI_AP_STATE_ENABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME); + callbackCaptor.getValue().onStateChanged(state0); + SoftApState state1 = new SoftApState(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME); + callbackCaptor.getValue().onStateChanged(state1); callbackCaptor.getValue().onCapabilityChanged(testSoftApCapability); @@ -1820,6 +1836,11 @@ public class WifiManagerTest { verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0); verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); verify(mSoftApCallback).onCapabilityChanged(testSoftApCapability); + ArgumentCaptor<SoftApState> softApStateCaptor = + ArgumentCaptor.forClass(SoftApState.class); + verify(mSoftApCallback, times(2)).onStateChanged(softApStateCaptor.capture()); + assertEquals(state0, softApStateCaptor.getAllValues().get(0)); + assertEquals(state1, softApStateCaptor.getAllValues().get(1)); } /* @@ -1834,9 +1855,24 @@ public class WifiManagerTest { mWifiManager.registerSoftApCallback(new HandlerExecutor(altHandler), mSoftApCallback); verify(mWifiService).registerSoftApCallback(callbackCaptor.capture()); - callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLED, 0); + SoftApState state = new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME); + callbackCaptor.getValue().onStateChanged(state); altLooper.dispatchAll(); verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); + ArgumentCaptor<SoftApState> softApStateCaptor = + ArgumentCaptor.forClass(SoftApState.class); + verify(mSoftApCallback).onStateChanged(softApStateCaptor.capture()); + SoftApState softApState = softApStateCaptor.getValue(); + assertEquals(WIFI_AP_STATE_ENABLED, softApState.getState()); + try { + softApState.getFailureReason(); + fail("getFailureReason should throw if not in failure state"); + } catch (IllegalStateException e) { + // Pass. + } + assertEquals(TEST_INTERFACE_NAME, softApState.getIface()); + assertEquals(TEST_TETHERING_REQUEST, softApState.getTetheringRequest()); } /** @@ -2976,7 +3012,7 @@ public class WifiManagerTest { ArgumentCaptor<IActionListener> binderListenerCaptor = ArgumentCaptor.forClass(IActionListener.class); verify(mWifiService).connect(eq(null), eq(TEST_NETWORK_ID), binderListenerCaptor.capture(), - anyString()); + anyString(), any()); assertNotNull(binderListenerCaptor.getValue()); // Trigger on success. @@ -2996,7 +3032,7 @@ public class WifiManagerTest { @Test public void testConnectWithListenerHandleSecurityException() throws Exception { doThrow(new SecurityException()).when(mWifiService) - .connect(eq(null), anyInt(), any(IActionListener.class), anyString()); + .connect(eq(null), anyInt(), any(IActionListener.class), anyString(), any()); ActionListener externalListener = mock(ActionListener.class); mWifiManager.connect(TEST_NETWORK_ID, externalListener); @@ -3010,7 +3046,7 @@ public class WifiManagerTest { @Test public void testConnectWithListenerHandleRemoteException() throws Exception { doThrow(new RemoteException()).when(mWifiService) - .connect(eq(null), anyInt(), any(IActionListener.class), anyString()); + .connect(eq(null), anyInt(), any(IActionListener.class), anyString(), any()); ActionListener externalListener = mock(ActionListener.class); mWifiManager.connect(TEST_NETWORK_ID, externalListener); @@ -3027,7 +3063,7 @@ public class WifiManagerTest { mWifiManager.connect(configuration, null); verify(mWifiService).connect(eq(configuration), eq(WifiConfiguration.INVALID_NETWORK_ID), - eq(null), anyString()); + eq(null), anyString(), any()); } /** @@ -3861,7 +3897,9 @@ public class WifiManagerTest { verify(mWifiService).registerLocalOnlyHotspotSoftApCallback(callbackCaptor.capture(), any(Bundle.class)); - callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLED, 0); + SoftApState state = new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME); + callbackCaptor.getValue().onStateChanged(state); callbackCaptor.getValue().onConnectedClientsOrInfoChanged( (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(), (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, true); @@ -3871,6 +3909,10 @@ public class WifiManagerTest { mLooper.dispatchAll(); verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); + ArgumentCaptor<SoftApState> softApStateCaptor = + ArgumentCaptor.forClass(SoftApState.class); + verify(mSoftApCallback).onStateChanged(softApStateCaptor.capture()); + assertEquals(state, softApStateCaptor.getValue()); verify(mSoftApCallback).onConnectedClientsChanged(clientList); verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo1, clientList); @@ -4158,4 +4200,193 @@ public class WifiManagerTest { verify(mWifiService).queryWepAllowed( any(IBooleanListener.Stub.class)); } + + /** + * Verify {@link WifiManager#setPerSsidRoamingMode(WifiSsid, int)}. + */ + @Test + public void testSetPerSsidRoamingMode() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + // Invalid input throws exception. + assertThrows(IllegalArgumentException.class, + () -> mWifiManager.setPerSsidRoamingMode(WifiSsid.fromString(TEST_SSID), -1)); + assertThrows(IllegalArgumentException.class, + () -> mWifiManager.setPerSsidRoamingMode(WifiSsid.fromString(TEST_SSID), 3)); + assertThrows(NullPointerException.class, + () -> mWifiManager.setPerSsidRoamingMode(null, WifiManager.ROAMING_MODE_NORMAL)); + // Set and verify. + mWifiManager.setPerSsidRoamingMode(WifiSsid.fromString(TEST_SSID), + WifiManager.ROAMING_MODE_NORMAL); + verify(mWifiService).setPerSsidRoamingMode(WifiSsid.fromString(TEST_SSID), + WifiManager.ROAMING_MODE_NORMAL, TEST_PACKAGE_NAME); + } + + /** + * Verify {@link WifiManager#removePerSsidRoamingMode(WifiSsid)}. + */ + @Test + public void testRemovePerSsidRoamingMode() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + // Invalid input throws exception. + assertThrows(NullPointerException.class, + () -> mWifiManager.removePerSsidRoamingMode(null)); + // Remove and verify. + mWifiManager.removePerSsidRoamingMode(WifiSsid.fromString(TEST_SSID)); + verify(mWifiService).removePerSsidRoamingMode(WifiSsid.fromString(TEST_SSID), + TEST_PACKAGE_NAME); + } + + /** + * Verify {@link WifiManager#getPerSsidRoamingModes()}. + */ + @Test + public void testGetPerSsidRoamingModes() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + Consumer<Map<String, Integer>> resultsSetCallback = mock(Consumer.class); + SynchronousExecutor executor = mock(SynchronousExecutor.class); + // Null executor/callback exception. + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.getPerSsidRoamingModes(null, + resultsSetCallback)); + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.getPerSsidRoamingModes(executor, + null)); + // Get and verify. + mWifiManager.getPerSsidRoamingModes(executor, resultsSetCallback); + verify(mWifiService).getPerSsidRoamingModes(eq(TEST_PACKAGE_NAME), + any(IMapListener.Stub.class)); + } + + @Test + public void testGetTwtCapabilities() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + Consumer<Bundle> resultCallback = mock(Consumer.class); + SynchronousExecutor executor = mock(SynchronousExecutor.class); + ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + // Null check + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.getTwtCapabilities(executor, null)); + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.getTwtCapabilities(null, resultCallback)); + // Get and verify + mWifiManager.getTwtCapabilities(executor, resultCallback); + verify(mWifiService).getTwtCapabilities(any(ITwtCapabilitiesListener.Stub.class), + bundleCaptor.capture()); + verify(mContext.getAttributionSource()).equals( + bundleCaptor.getValue().getParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE)); + } + + @Test + public void testSetupTwtSession() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + TwtSessionCallback resultCallback = mock(TwtSessionCallback.class); + SynchronousExecutor executor = mock(SynchronousExecutor.class); + ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + TwtRequest twtRequest = mock(TwtRequest.class); + // Null check + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.setupTwtSession(null, executor, resultCallback)); + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.setupTwtSession(twtRequest, null, resultCallback)); + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.setupTwtSession(twtRequest, executor, null)); + // Call twtSessionSetup and verify + mWifiManager.setupTwtSession(twtRequest, executor, resultCallback); + verify(mWifiService).setupTwtSession(any(TwtRequest.class), any(ITwtCallback.class), + bundleCaptor.capture()); + verify(mContext.getAttributionSource()).equals( + bundleCaptor.getValue().getParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE)); + } + + @Test + public void testGetStatsTwtSession() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + Consumer<Bundle> resultCallback = mock(Consumer.class); + SynchronousExecutor executor = mock(SynchronousExecutor.class); + ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + // Null check + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.getStatsTwtSession(0, null, resultCallback)); + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.getStatsTwtSession(0, executor, null)); + // Call twtSessionGetStats and verify + mWifiManager.getStatsTwtSession(2, executor, resultCallback); + verify(mWifiService).getStatsTwtSession(eq(2), any(ITwtStatsListener.class), + bundleCaptor.capture()); + verify(mContext.getAttributionSource()).equals( + bundleCaptor.getValue().getParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE)); + } + + @Test + public void testTeardownTwtSession() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + // Call twtSessionTeardown and verify + mWifiManager.teardownTwtSession(10); + verify(mWifiService).teardownTwtSession(eq(10), bundleCaptor.capture()); + verify(mContext.getAttributionSource()).equals( + bundleCaptor.getValue().getParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE)); + } + + /** + * Test behavior of isD2dSupportedWhenInfraStaDisabled. + */ + @Test + public void testIsD2dSupportedWhenInfraStaDisabled() throws Exception { + when(mWifiService.getSupportedFeatures()) + .thenReturn(new Long(WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED)); + assertTrue(mWifiManager.isD2dSupportedWhenInfraStaDisabled()); + when(mWifiService.getSupportedFeatures()) + .thenReturn(new Long(~WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED)); + assertFalse(mWifiManager.isD2dSupportedWhenInfraStaDisabled()); + } + + @Test + public void testSetD2dAllowedInfraStaDisabled() throws Exception { + mWifiManager.setD2dAllowedWhenInfraStaDisabled(true); + verify(mWifiService).setD2dAllowedWhenInfraStaDisabled(true); + mWifiManager.setD2dAllowedWhenInfraStaDisabled(false); + verify(mWifiService).setD2dAllowedWhenInfraStaDisabled(false); + } + + @Test + public void testQueryD2dAllowedInfraStaDisabled() throws Exception { + Consumer<Boolean> resultsSetCallback = mock(Consumer.class); + SynchronousExecutor executor = mock(SynchronousExecutor.class); + // Null executor/callback exception. + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.queryD2dAllowedWhenInfraStaDisabled(null, resultsSetCallback)); + assertThrows("null listener should trigger exception", NullPointerException.class, + () -> mWifiManager.queryD2dAllowedWhenInfraStaDisabled(executor, null)); + // Set and verify. + mWifiManager.queryD2dAllowedWhenInfraStaDisabled(executor, resultsSetCallback); + verify(mWifiService).queryD2dAllowedWhenInfraStaDisabled( + any(IBooleanListener.Stub.class)); + } + + @Test + public void testRetrieveRestoreWifiBackupData() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + Consumer<byte[]> resultsSetCallback = mock(Consumer.class); + SynchronousExecutor executor = mock(SynchronousExecutor.class); + byte[] testByteArray = new byte[0]; + // Null executor/callback exception. + assertThrows("null executor should trigger exception", NullPointerException.class, + () -> mWifiManager.retrieveWifiBackupData(null, resultsSetCallback)); + assertThrows("null listener should trigger exception", NullPointerException.class, + () -> mWifiManager.retrieveWifiBackupData(executor, null)); + // Call and verify. + mWifiManager.retrieveWifiBackupData(executor, resultsSetCallback); + verify(mWifiService).retrieveWifiBackupData( + any(IByteArrayListener.Stub.class)); + mWifiManager.restoreWifiBackupData(testByteArray); + verify(mWifiService).restoreWifiBackupData(eq(testByteArray)); + } + + + @Test + public void testIsPreferredNetworkOffloadSupported() throws Exception { + mWifiManager.isPreferredNetworkOffloadSupported(); + verify(mWifiService).isPnoSupported(); + } } diff --git a/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java index 397ede4166..5d61ca7f0d 100644 --- a/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java +++ b/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java @@ -1735,4 +1735,22 @@ public class WifiNetworkSuggestionTest { .setWifiSsid(ssid) .build(); } + + /** + * Test set a network suggestion with Wi-Fi 7 + */ + @Test + public void testNetworkSuggestionForWifi7() { + // Validate default behavior + WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder().setSsid( + TEST_SSID).setWpa2Passphrase(TEST_PRESHARED_KEY).build(); + assertTrue(suggestion.isWifi7Enabled()); + assertTrue(suggestion.wifiConfiguration.isWifi7Enabled()); + + // Validate disable Wi-Fi 7 + suggestion = new WifiNetworkSuggestion.Builder().setSsid(TEST_SSID).setWpa2Passphrase( + TEST_PRESHARED_KEY).setWifi7Enabled(false).build(); + assertFalse(suggestion.isWifi7Enabled()); + assertFalse(suggestion.wifiConfiguration.isWifi7Enabled()); + } } diff --git a/framework/tests/src/android/net/wifi/WifiUriParserTest.java b/framework/tests/src/android/net/wifi/WifiUriParserTest.java new file mode 100644 index 0000000000..c38974bb59 --- /dev/null +++ b/framework/tests/src/android/net/wifi/WifiUriParserTest.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2024 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 android.net.wifi; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; + +import androidx.test.filters.SmallTest; + +import com.google.common.collect.ImmutableList; + +import org.junit.Test; + +import java.util.List; + +/** Unit tests for {@link com.android.server.wifi.WifiUriParser}. */ +@SmallTest +public class WifiUriParserTest { + + private static final String TEST_DPP_INFORMATION = "Easy_Connect_Demo"; + private static final String TEST_DPP_PUBLIC_KEY = "MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIg" + + "ACDmtXD1Sz6/5B4YRdmTkbkkFLDwk8f0yRnfm1Gokpx/0="; + private static final String TEST_DPP_URI = "DPP:C:81/1;I:" + TEST_DPP_INFORMATION + + ";K:" + TEST_DPP_PUBLIC_KEY + ";;"; + + private void verifyZxParsing( + UriParserResults uri, + String expectedSSID, + int expectedAuthType, + List<SecurityParams> expectedSecurityParamsList, + String expectedPreShareKey, + boolean isWep) { + assertNotNull(uri); + WifiConfiguration config = uri.getWifiConfiguration(); + assertNotNull(config); + assertThat(config.SSID).isEqualTo(expectedSSID); + assertThat(config.getAuthType()).isEqualTo(expectedAuthType); + if (isWep) { + assertThat(config.wepKeys[0]).isEqualTo(expectedPreShareKey); + } else { + assertThat(config.preSharedKey).isEqualTo(expectedPreShareKey); + } + List<SecurityParams> configSecurityParamsList = config.getSecurityParamsList(); + assertEquals(expectedSecurityParamsList, configSecurityParamsList); + assertNull(uri.getPublicKey()); + assertNull(uri.getInformation()); + assertEquals(UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG, uri.getUriScheme()); + } + + @Test + public void testZxParsing() { + // Test no password + List<SecurityParams> expectedSecurityParamsList = + ImmutableList.of( + SecurityParams.createSecurityParamsBySecurityType( + WifiConfiguration.SECURITY_TYPE_OPEN), + SecurityParams.createSecurityParamsBySecurityType( + WifiConfiguration.SECURITY_TYPE_OWE)); + UriParserResults uri = WifiUriParser.parseUri("WIFI:S:testAbC;T:nopass"); + verifyZxParsing( + uri, + "\"testAbC\"", + WifiConfiguration.KeyMgmt.NONE, + expectedSecurityParamsList, + null, + false); + // invalid code but it should work. + uri = WifiUriParser.parseUri("WIFI:S:testAbC; T:nopass"); + verifyZxParsing( + uri, + "\"testAbC\"", + WifiConfiguration.KeyMgmt.NONE, + expectedSecurityParamsList, + null, + false); + + // Test WEP + expectedSecurityParamsList = + ImmutableList.of( + SecurityParams.createSecurityParamsBySecurityType( + WifiConfiguration.SECURITY_TYPE_WEP)); + uri = WifiUriParser.parseUri("WIFI:S:reallyLONGone;T:WEP;P:somepasswo#%^**123rd"); + verifyZxParsing( + uri, + "\"reallyLONGone\"", + WifiConfiguration.KeyMgmt.NONE, + expectedSecurityParamsList, + "\"somepasswo#%^**123rd\"", + true); + // invalid code but it should work. + uri = WifiUriParser.parseUri("WIFI:S:reallyLONGone;T:WEP; P:somepassword"); + verifyZxParsing( + uri, + "\"reallyLONGone\"", + WifiConfiguration.KeyMgmt.NONE, + expectedSecurityParamsList, + "\"somepassword\"", + true); + + // Test WPA + expectedSecurityParamsList = + ImmutableList.of( + SecurityParams.createSecurityParamsBySecurityType( + WifiConfiguration.SECURITY_TYPE_PSK)); + uri = WifiUriParser.parseUri("WIFI:S:anotherone;T:WPA;P:3#=3j9asicla"); + verifyZxParsing( + uri, + "\"anotherone\"", + WifiConfiguration.KeyMgmt.WPA_PSK, + expectedSecurityParamsList, + "\"3#=3j9asicla\"", + false); + // invalid code but it should work. + uri = WifiUriParser.parseUri("WIFI: S:anotherone;T:WPA;P:abcdefghihklmn"); + verifyZxParsing( + uri, + "\"anotherone\"", + WifiConfiguration.KeyMgmt.WPA_PSK, + expectedSecurityParamsList, + "\"abcdefghihklmn\"", + false); + + // Test SAE + expectedSecurityParamsList = + ImmutableList.of( + SecurityParams.createSecurityParamsBySecurityType( + WifiConfiguration.SECURITY_TYPE_SAE)); + uri = WifiUriParser.parseUri("WIFI:S:xx;T:SAE;P:a"); + verifyZxParsing( + uri, + "\"xx\"", + WifiConfiguration.KeyMgmt.SAE, + expectedSecurityParamsList, + "\"a\"", + false); + // invalid code but it should work. + uri = WifiUriParser.parseUri("WIFI: S:xx; T:SAE; P:a"); + verifyZxParsing( + uri, + "\"xx\"", + WifiConfiguration.KeyMgmt.SAE, + expectedSecurityParamsList, + "\"a\"", + false); + } + + @Test + public void testDppParsing() { + UriParserResults uri = WifiUriParser.parseUri(TEST_DPP_URI); + assertEquals(UriParserResults.URI_SCHEME_DPP, uri.getUriScheme()); + assertEquals(TEST_DPP_INFORMATION, uri.getInformation()); + assertEquals(TEST_DPP_PUBLIC_KEY, uri.getPublicKey()); + assertNull(uri.getWifiConfiguration()); + } + + @Test + public void testInvalidUriParsing() { + assertThrows(IllegalArgumentException.class, + () -> WifiUriParser.parseUri("Invalid Uri")); + // Empty SSID + assertThrows(IllegalArgumentException.class, + () -> WifiUriParser.parseUri("WIFI:S:;T:nopass")); + // Empty passphrase + assertThrows(IllegalArgumentException.class, + () -> WifiUriParser.parseUri("WIFI: S:xx; T:SAE; P:")); + } +} diff --git a/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 0bb0e21239..e24fa354ad 100644 --- a/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -41,6 +41,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.MacAddress; import android.net.wifi.IBooleanListener; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.OuiKeyedDataUtil; import android.net.wifi.RttManager; import android.net.wifi.SynchronousExecutor; import android.net.wifi.util.HexEncoding; @@ -66,6 +68,7 @@ import org.mockito.MockitoAnnotations; import java.net.Inet6Address; import java.net.UnknownHostException; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -340,6 +343,8 @@ public class WifiAwareManagerTest { final PeerHandle peerHandle = new PeerHandle(873); final String string1 = "hey from here..."; final byte[] matchFilter = { 1, 12, 2, 31, 32 }; + final OuiKeyedData[] vendorData = new OuiKeyedData[5]; + OuiKeyedDataUtil.createTestOuiKeyedDataList(5).toArray(vendorData); final int messageId = 2123; final int reason = AWARE_STATUS_ERROR; @@ -379,7 +384,7 @@ public class WifiAwareManagerTest { // (3) ... publishSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes()); sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter, - 0, new byte[0], null, null); + 0, new byte[0], null, null, vendorData); sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes()); sessionProxyCallback.getValue().onMessageSendFail(messageId, reason); sessionProxyCallback.getValue().onMessageSendSuccess(messageId); @@ -499,6 +504,8 @@ public class WifiAwareManagerTest { final PeerHandle peerHandle = new PeerHandle(873); final String string1 = "hey from here..."; final byte[] matchFilter = { 1, 12, 3, 31, 32 }; // bad data! + final OuiKeyedData[] vendorData = new OuiKeyedData[5]; + OuiKeyedDataUtil.createTestOuiKeyedDataList(5).toArray(vendorData); final int messageId = 2123; final int reason = AWARE_STATUS_ERROR; final int distanceMm = 100; @@ -537,9 +544,9 @@ public class WifiAwareManagerTest { // (3) ... subscribeSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes()); sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter, - 0, new byte[0], null, null); + 0, new byte[0], null, null, vendorData); sessionProxyCallback.getValue().onMatchWithDistance(peerHandle.peerId, string1.getBytes(), - matchFilter, distanceMm, 0, new byte[0], null, null); + matchFilter, distanceMm, 0, new byte[0], null, null, vendorData); sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes()); sessionProxyCallback.getValue().onMessageSendFail(messageId, reason); sessionProxyCallback.getValue().onMessageSendSuccess(messageId); @@ -672,14 +679,18 @@ public class WifiAwareManagerTest { final boolean supportBand6g = true; final int dwWindow5GHz = 3; final int dwWindow6GHz = 4; + final List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); - ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh) + ConfigRequest.Builder builder = new ConfigRequest.Builder().setClusterHigh(clusterHigh) .setClusterLow(clusterLow).setMasterPreference(masterPreference) .setSupport5gBand(supportBand5g) .setSupport6gBand(supportBand6g) .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz) - .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz) - .build(); + .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz); + if (SdkLevel.isAtLeastV()) { + builder.setVendorData(vendorData); + } + ConfigRequest configRequest = builder.build(); collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh)); collector.checkThat("mClusterLow", clusterLow, equalTo(configRequest.mClusterLow)); @@ -695,6 +706,9 @@ public class WifiAwareManagerTest { equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ])); collector.checkThat("mDiscoveryWindowInterval[6GHz]", dwWindow6GHz, equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ])); + if (SdkLevel.isAtLeastV()) { + collector.checkThat("mVendorData", vendorData, equalTo(configRequest.getVendorData())); + } } @Test(expected = IllegalArgumentException.class) @@ -777,15 +791,19 @@ public class WifiAwareManagerTest { final int dwWindow24GHz = 1; final int dwWindow5GHz = 5; final int dwWindow6GHz = 4; + final List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); - ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh) + ConfigRequest.Builder builder = new ConfigRequest.Builder().setClusterHigh(clusterHigh) .setClusterLow(clusterLow).setMasterPreference(masterPreference) .setSupport5gBand(supportBand5g) .setSupport6gBand(supportBand6g) .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz) .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz) - .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz) - .build(); + .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz); + if (SdkLevel.isAtLeastV()) { + builder.setVendorData(vendorData); + } + ConfigRequest configRequest = builder.build(); Parcel parcelW = Parcel.obtain(); configRequest.writeToParcel(parcelW, 0); @@ -822,6 +840,10 @@ public class WifiAwareManagerTest { collector.checkThat("mMinDistanceMm", subscribeConfig.mMinDistanceMm, equalTo(0)); collector.checkThat("mMaxDistanceMmSet", subscribeConfig.mMaxDistanceMmSet, equalTo(false)); collector.checkThat("mMaxDistanceMm", subscribeConfig.mMaxDistanceMm, equalTo(0)); + if (SdkLevel.isAtLeastV()) { + collector.checkThat("mVendorData", subscribeConfig.getVendorData(), + equalTo(Collections.emptyList())); + } } @Test @@ -834,15 +856,21 @@ public class WifiAwareManagerTest { final boolean enableTerminateNotification = false; final int minDistance = 10; final int maxDistance = 50; - - SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( - new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) - .setSubscribeType(subscribeType) - .setTtlSec(subscribeTtl) - .setTerminateNotificationEnabled(enableTerminateNotification) - .setMinDistanceMm(minDistance) - .setMaxDistanceMm(maxDistance).build(); + final List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); + + SubscribeConfig.Builder subscribeConfigBuilder = + new SubscribeConfig.Builder().setServiceName(serviceName) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) + .setSubscribeType(subscribeType) + .setTtlSec(subscribeTtl) + .setTerminateNotificationEnabled(enableTerminateNotification) + .setMinDistanceMm(minDistance) + .setMaxDistanceMm(maxDistance); + if (SdkLevel.isAtLeastV()) { + subscribeConfigBuilder.setVendorData(vendorData); + } + SubscribeConfig subscribeConfig = subscribeConfigBuilder.build(); collector.checkThat("mServiceName", serviceName.getBytes(), equalTo(subscribeConfig.mServiceName)); @@ -858,6 +886,10 @@ public class WifiAwareManagerTest { collector.checkThat("mMinDistanceMm", minDistance, equalTo(subscribeConfig.mMinDistanceMm)); collector.checkThat("mMaxDistanceMmSet", true, equalTo(subscribeConfig.mMaxDistanceMmSet)); collector.checkThat("mMaxDistanceMm", maxDistance, equalTo(subscribeConfig.mMaxDistanceMm)); + if (SdkLevel.isAtLeastV()) { + collector.checkThat("mVendorData", vendorData, + equalTo(subscribeConfig.getVendorData())); + } } @Test @@ -870,15 +902,21 @@ public class WifiAwareManagerTest { final boolean enableTerminateNotification = true; final int minDistance = 10; final int maxDistance = 50; - - SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( - new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) - .setSubscribeType(subscribeType) - .setTtlSec(subscribeTtl) - .setTerminateNotificationEnabled(enableTerminateNotification) - .setMinDistanceMm(minDistance) - .setMaxDistanceMm(maxDistance).build(); + final List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); + + SubscribeConfig.Builder subscribeConfigBuilder = + new SubscribeConfig.Builder().setServiceName(serviceName) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) + .setSubscribeType(subscribeType) + .setTtlSec(subscribeTtl) + .setTerminateNotificationEnabled(enableTerminateNotification) + .setMinDistanceMm(minDistance) + .setMaxDistanceMm(maxDistance); + if (SdkLevel.isAtLeastV()) { + subscribeConfigBuilder.setVendorData(vendorData); + } + SubscribeConfig subscribeConfig = subscribeConfigBuilder.build(); Parcel parcelW = Parcel.obtain(); subscribeConfig.writeToParcel(parcelW, 0); @@ -922,6 +960,10 @@ public class WifiAwareManagerTest { collector.checkThat("mEnableTerminateNotification", publishConfig.mEnableTerminateNotification, equalTo(true)); collector.checkThat("mEnableRanging", publishConfig.mEnableRanging, equalTo(false)); + if (SdkLevel.isAtLeastV()) { + collector.checkThat("mVendorData", publishConfig.getVendorData(), + equalTo(Collections.emptyList())); + } } @Test @@ -933,14 +975,20 @@ public class WifiAwareManagerTest { final int publishTtl = 15; final boolean enableTerminateNotification = false; final boolean enableRanging = true; - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( - new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) - .setPublishType(publishType) - .setTtlSec(publishTtl) - .setTerminateNotificationEnabled(enableTerminateNotification) - .setRangingEnabled(enableRanging).build(); + final List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); + + PublishConfig.Builder publishConfigBuilder = + new PublishConfig.Builder().setServiceName(serviceName) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) + .setPublishType(publishType) + .setTtlSec(publishTtl) + .setTerminateNotificationEnabled(enableTerminateNotification) + .setRangingEnabled(enableRanging); + if (SdkLevel.isAtLeastV()) { + publishConfigBuilder.setVendorData(vendorData); + } + PublishConfig publishConfig = publishConfigBuilder.build(); collector.checkThat("mServiceName", serviceName.getBytes(), equalTo(publishConfig.mServiceName)); @@ -952,6 +1000,10 @@ public class WifiAwareManagerTest { collector.checkThat("mEnableTerminateNotification", enableTerminateNotification, equalTo(publishConfig.mEnableTerminateNotification)); collector.checkThat("mEnableRanging", enableRanging, equalTo(publishConfig.mEnableRanging)); + if (SdkLevel.isAtLeastV()) { + collector.checkThat("mVendorData", vendorData, equalTo( + publishConfig.getVendorData())); + } } @Test @@ -963,14 +1015,21 @@ public class WifiAwareManagerTest { final int publishTtl = 15; final boolean enableTerminateNotification = false; final boolean enableRanging = true; - - PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( - new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) - .setPublishType(publishType) - .setTtlSec(publishTtl) - .setTerminateNotificationEnabled(enableTerminateNotification) - .setRangingEnabled(enableRanging).build(); + final List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); + + PublishConfig.Builder publishConfigBuilder = + new PublishConfig.Builder().setServiceName(serviceName) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter) + .toList()) + .setPublishType(publishType) + .setTtlSec(publishTtl) + .setTerminateNotificationEnabled(enableTerminateNotification) + .setRangingEnabled(enableRanging); + if (SdkLevel.isAtLeastV()) { + publishConfigBuilder.setVendorData(vendorData); + } + PublishConfig publishConfig = publishConfigBuilder.build(); Parcel parcelW = Parcel.obtain(); publishConfig.writeToParcel(parcelW, 0); diff --git a/framework/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java b/framework/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java index 568d59963f..15eba6fd8c 100644 --- a/framework/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java +++ b/framework/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import android.net.MacAddress; +import android.net.wifi.OuiKeyedDataUtil; import android.os.Parcel; import androidx.test.filters.SmallTest; @@ -264,6 +265,9 @@ public class WifiP2pConfigTest { public void testWifiP2pConfig() throws Exception { WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = DEVICE_ADDRESS; + if (SdkLevel.isAtLeastV()) { + config.setVendorData(OuiKeyedDataUtil.createTestOuiKeyedDataList(5)); + } WifiP2pConfig copiedConfig = new WifiP2pConfig(config); // no equals operator, use toString for comparison. @@ -279,6 +283,9 @@ public class WifiP2pConfigTest { parcelR.setDataPosition(0); WifiP2pConfig configFromParcel = WifiP2pConfig.CREATOR.createFromParcel(parcelR); + if (SdkLevel.isAtLeastV()) { + assertTrue(config.getVendorData().equals(configFromParcel.getVendorData())); + } // no equals operator, use toString for comparison. assertEquals(config.toString(), configFromParcel.toString()); } diff --git a/framework/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java b/framework/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java index 7af86b9d2c..611792d7d7 100644 --- a/framework/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java +++ b/framework/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java @@ -20,7 +20,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; +import android.net.MacAddress; +import android.net.wifi.OuiKeyedDataUtil; import android.net.wifi.ScanResult; +import android.os.Parcel; import androidx.test.filters.SmallTest; @@ -28,6 +31,8 @@ import com.android.modules.utils.build.SdkLevel; import org.junit.Test; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -37,6 +42,8 @@ import java.util.List; */ @SmallTest public class WifiP2pDeviceTest { + private static final MacAddress INTERFACE_MAC_ADDRESS = + MacAddress.fromString("aa:bb:cc:dd:ee:10"); /** * Compare two p2p devices. @@ -138,4 +145,66 @@ public class WifiP2pDeviceTest { device.setVendorElements(ies); assertEquals(ies, device.getVendorElements()); } + + /** Tests that this class can be properly parceled and unparceled. */ + @Test + public void testParcelReadWrite() { + WifiP2pDevice device = new WifiP2pDevice(); + device.deviceName = "deviceName"; + device.deviceAddress = "11:22:33:44:55:66"; + device.primaryDeviceType = "primaryDeviceType"; + device.secondaryDeviceType = "secondaryDeviceType"; + device.wpsConfigMethodsSupported = 0x0008; + device.deviceCapability = 1; + device.groupCapability = 1; + device.status = WifiP2pDevice.CONNECTED; + if (SdkLevel.isAtLeastV()) { + device.setVendorData(OuiKeyedDataUtil.createTestOuiKeyedDataList(5)); + } + + Parcel parcel = Parcel.obtain(); + device.writeToParcel(parcel, 0); + parcel.setDataPosition(0); // Rewind data position back to the beginning for read. + WifiP2pDevice unparceledDevice = WifiP2pDevice.CREATOR.createFromParcel(parcel); + + assertEquals(device.deviceName, unparceledDevice.deviceName); + assertEquals(device.deviceAddress, unparceledDevice.deviceAddress); + assertEquals(device.primaryDeviceType, unparceledDevice.primaryDeviceType); + assertEquals(device.secondaryDeviceType, unparceledDevice.secondaryDeviceType); + assertEquals(device.wpsConfigMethodsSupported, unparceledDevice.wpsConfigMethodsSupported); + assertEquals(device.deviceCapability, unparceledDevice.deviceCapability); + assertEquals(device.groupCapability, unparceledDevice.groupCapability); + assertEquals(device.status, unparceledDevice.status); + if (SdkLevel.isAtLeastV()) { + assertEquals(device.getVendorData(), unparceledDevice.getVendorData()); + } + } + + /** + * Test the setter/getter for device interface MAC address. + */ + @Test + public void testInterfaceMacAddressSetterGetter() { + assumeTrue(SdkLevel.isAtLeastV()); + WifiP2pDevice device = new WifiP2pDevice(); + device.setInterfaceMacAddress(INTERFACE_MAC_ADDRESS); + assertEquals(INTERFACE_MAC_ADDRESS, device.getInterfaceMacAddress()); + } + + /** + * Test the setter/getter for device IP address. + */ + @Test + public void testIpAddressSetterGetter() { + assumeTrue(SdkLevel.isAtLeastV()); + WifiP2pDevice device = new WifiP2pDevice(); + InetAddress ipAddress; + try { + ipAddress = InetAddress.getByName("192.168.49.1"); + } catch (UnknownHostException e) { + return; + } + device.setIpAddress(ipAddress); + assertEquals("192.168.49.1", device.getIpAddress().getHostAddress()); + } } diff --git a/framework/tests/src/android/net/wifi/p2p/WifiP2pDiscoveryConfigTest.java b/framework/tests/src/android/net/wifi/p2p/WifiP2pDiscoveryConfigTest.java new file mode 100644 index 0000000000..9133ab724a --- /dev/null +++ b/framework/tests/src/android/net/wifi/p2p/WifiP2pDiscoveryConfigTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 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 android.net.wifi.p2p; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.net.wifi.OuiKeyedData; +import android.net.wifi.OuiKeyedDataUtil; +import android.os.Parcel; + +import com.android.modules.utils.build.SdkLevel; + +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class WifiP2pDiscoveryConfigTest { + private static final int TEST_SCAN_TYPE = WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ; + private static final int TEST_FREQUENCY_MHZ = 900; + + @Before + public void setUp() { + assumeTrue(SdkLevel.isAtLeastV()); + } + + /** Tests that the builder throws an exception if given an invalid integer argument. */ + @Test + public void testBuilderInvalidIntegerArgument() { + assertThrows(IllegalArgumentException.class, () -> + new WifiP2pDiscoveryConfig.Builder(-1 /* scan type */).build()); + + WifiP2pDiscoveryConfig.Builder singleFreqBuilder = + new WifiP2pDiscoveryConfig.Builder(WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ); + assertThrows(IllegalArgumentException.class, () -> singleFreqBuilder.setFrequencyMhz(-1)); + // Expect exception on build, since a valid frequency was not set. + assertThrows(IllegalArgumentException.class, () -> singleFreqBuilder.build()); + } + + /** Tests that the builder throws an exception if given a null vendor data value. */ + @Test + public void testBuilderNullVendorData() { + WifiP2pDiscoveryConfig.Builder builder = + new WifiP2pDiscoveryConfig.Builder(TEST_SCAN_TYPE); + assertThrows(IllegalArgumentException.class, () -> builder.setVendorData(null)); + } + + /** Tests that this class can be properly parceled and unparceled. */ + @Test + public void testParcelReadWrite() throws Exception { + List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); + WifiP2pDiscoveryConfig config = + new WifiP2pDiscoveryConfig.Builder(TEST_SCAN_TYPE) + .setFrequencyMhz(TEST_FREQUENCY_MHZ) + .setVendorData(vendorData) + .build(); + Parcel parcel = Parcel.obtain(); + config.writeToParcel(parcel, 0); + parcel.setDataPosition(0); // Rewind data position back to the beginning for read. + WifiP2pDiscoveryConfig unparceledConfig = + WifiP2pDiscoveryConfig.CREATOR.createFromParcel(parcel); + + assertEquals(TEST_SCAN_TYPE, unparceledConfig.getScanType()); + assertEquals(TEST_FREQUENCY_MHZ, unparceledConfig.getFrequencyMhz()); + assertTrue(vendorData.equals(unparceledConfig.getVendorData())); + } +} diff --git a/framework/tests/src/android/net/wifi/p2p/WifiP2pExtListenParamsTest.java b/framework/tests/src/android/net/wifi/p2p/WifiP2pExtListenParamsTest.java new file mode 100644 index 0000000000..7ac837c35b --- /dev/null +++ b/framework/tests/src/android/net/wifi/p2p/WifiP2pExtListenParamsTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024 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 android.net.wifi.p2p; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.net.wifi.OuiKeyedData; +import android.net.wifi.OuiKeyedDataUtil; +import android.os.Parcel; + +import com.android.modules.utils.build.SdkLevel; + +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class WifiP2pExtListenParamsTest { + @Before + public void setUp() { + assumeTrue(SdkLevel.isAtLeastV()); + } + + /** Tests that the builder throws an exception if given a null vendor data value. */ + @Test + public void testBuilderNullVendorData() { + WifiP2pExtListenParams.Builder builder = new WifiP2pExtListenParams.Builder(); + assertThrows(IllegalArgumentException.class, () -> builder.setVendorData(null)); + } + + /** Tests that this class can be properly parceled and unparceled. */ + @Test + public void testParcelReadWrite() throws Exception { + List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); + WifiP2pExtListenParams params = + new WifiP2pExtListenParams.Builder() + .setVendorData(vendorData) + .build(); + Parcel parcel = Parcel.obtain(); + params.writeToParcel(parcel, 0); + parcel.setDataPosition(0); // Rewind data position back to the beginning for read. + WifiP2pExtListenParams unparceledParams = + WifiP2pExtListenParams.CREATOR.createFromParcel(parcel); + assertTrue(vendorData.equals(unparceledParams.getVendorData())); + } +} diff --git a/framework/tests/src/android/net/wifi/p2p/WifiP2pGroupTest.java b/framework/tests/src/android/net/wifi/p2p/WifiP2pGroupTest.java index 9473e42184..e84a76bc28 100644 --- a/framework/tests/src/android/net/wifi/p2p/WifiP2pGroupTest.java +++ b/framework/tests/src/android/net/wifi/p2p/WifiP2pGroupTest.java @@ -18,14 +18,24 @@ package android.net.wifi.p2p; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import android.net.InetAddresses; +import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.OuiKeyedDataUtil; import android.os.Parcel; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Test; +import java.util.Collection; +import java.util.List; + /** * Unit test harness for {@link android.net.wifi.p2p.WifiP2pGroup} */ @@ -38,8 +48,15 @@ public class WifiP2pGroupTest { private static final String PASSPHRASE = "HelloWorld"; private static final WifiP2pDevice GROUP_OWNER = new WifiP2pDevice("de:ad:be:ef:00:01"); private static final int FREQUENCY = 5300; - private static final WifiP2pDevice CLIENT_1 = new WifiP2pDevice("aa:bb:cc:dd:ee:01"); - private static final WifiP2pDevice CLIENT_2 = new WifiP2pDevice("aa:bb:cc:dd:ee:02"); + private static final String CLIENT_1_DEV_ADDRESS = "aa:bb:cc:dd:ee:01"; + private static final String CLIENT_2_DEV_ADDRESS = "aa:bb:cc:dd:ee:02"; + private static final WifiP2pDevice CLIENT_1 = new WifiP2pDevice(CLIENT_1_DEV_ADDRESS); + private static final WifiP2pDevice CLIENT_2 = new WifiP2pDevice(CLIENT_2_DEV_ADDRESS); + private static final MacAddress CLIENT_1_INTERFACE_MAC_ADDRESS = + MacAddress.fromString("aa:bb:cc:dd:ee:10"); + private static final String CLIENT_1_IP_ADDRESS = "192.168.49.10"; + private static final List<OuiKeyedData> VENDOR_DATA = + OuiKeyedDataUtil.createTestOuiKeyedDataList(5); /** * Verify setter/getter functions. @@ -56,7 +73,16 @@ public class WifiP2pGroupTest { group.setOwner(GROUP_OWNER); group.setFrequency(FREQUENCY); group.addClient(CLIENT_1.deviceAddress); + group.setClientInterfaceMacAddress(CLIENT_1.deviceAddress, + CLIENT_1_INTERFACE_MAC_ADDRESS); + if (SdkLevel.isAtLeastV()) { + group.setClientIpAddress(CLIENT_1_INTERFACE_MAC_ADDRESS, + InetAddresses.parseNumericAddress(CLIENT_1_IP_ADDRESS)); + } group.addClient(CLIENT_2); + if (SdkLevel.isAtLeastV()) { + group.setVendorData(VENDOR_DATA); + } assertEquals(INTERFACE, group.getInterface()); assertEquals(NETWORK_ID, group.getNetworkId()); @@ -65,11 +91,28 @@ public class WifiP2pGroupTest { assertFalse(group.isGroupOwner()); assertEquals(GROUP_OWNER, group.getOwner()); assertEquals(FREQUENCY, group.getFrequency()); + if (SdkLevel.isAtLeastV()) { + assertTrue(VENDOR_DATA.equals(group.getVendorData())); + } assertFalse(group.isClientListEmpty()); assertTrue(group.contains(CLIENT_1)); assertEquals(2, group.getClientList().size()); + Collection<WifiP2pDevice> clientsList = group.getClientList(); + for (WifiP2pDevice client : clientsList) { + if (client.deviceAddress.equals(CLIENT_1_DEV_ADDRESS)) { + assertEquals(CLIENT_1_INTERFACE_MAC_ADDRESS, client.getInterfaceMacAddress()); + if (SdkLevel.isAtLeastV()) { + assertEquals(CLIENT_1_IP_ADDRESS, client.getIpAddress().getHostAddress()); + } + } else if (client.deviceAddress.equals(CLIENT_2_DEV_ADDRESS)) { + assertNull(client.getInterfaceMacAddress()); + if (SdkLevel.isAtLeastV()) { + assertNull(client.getIpAddress()); + } + } + } group.removeClient(CLIENT_1); group.removeClient(CLIENT_2.deviceAddress); @@ -86,6 +129,9 @@ public class WifiP2pGroupTest { parcelR.setDataPosition(0); WifiP2pGroup fromParcel = WifiP2pGroup.CREATOR.createFromParcel(parcelR); + if (SdkLevel.isAtLeastV()) { + assertTrue(VENDOR_DATA.equals(fromParcel.getVendorData())); + } assertEquals(group.toString(), fromParcel.toString()); } diff --git a/framework/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java b/framework/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java index 15116ebb47..21c42d8760 100644 --- a/framework/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java +++ b/framework/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java @@ -34,6 +34,7 @@ import static org.mockito.Mockito.when; import android.content.AttributionSource; import android.content.Context; import android.net.wifi.ScanResult; +import android.net.wifi.SynchronousExecutor; import android.os.Bundle; import android.os.test.TestLooper; import android.view.Display; @@ -267,4 +268,17 @@ public class WifiP2pManagerTest { WifiP2pManager.FEATURE_GROUP_OWNER_IPV6_LINK_LOCAL_ADDRESS_PROVIDED); assertTrue(mDut.isGroupOwnerIPv6LinkLocalAddressProvided()); } + + @Test + public void testWifiP2pListener() throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + SynchronousExecutor executor = mock(SynchronousExecutor.class); + WifiP2pManager.WifiP2pListener listener = mock(WifiP2pManager.WifiP2pListener.class); + mDut.initialize(mContextMock, mTestLooper.getLooper(), null); + mDut.registerWifiP2pListener(executor, listener); + verify(mP2pServiceMock).registerWifiP2pListener(any(IWifiP2pListener.Stub.class), + eq(PACKAGE_NAME), any(Bundle.class)); + mDut.unregisterWifiP2pListener(listener); + verify(mP2pServiceMock).unregisterWifiP2pListener(any(IWifiP2pListener.Stub.class)); + } } diff --git a/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java index 4f4e37e4b3..5514224ce6 100644 --- a/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java +++ b/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java @@ -29,6 +29,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; +import android.net.wifi.OuiKeyedDataUtil; import android.net.wifi.ScanResult; import android.net.wifi.aware.PeerHandle; import android.os.Bundle; @@ -38,6 +40,8 @@ import android.os.test.TestLooper; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -85,9 +89,17 @@ public class WifiRttManagerTest { public void testRangeSuccess() throws Exception { RangingRequest request = new RangingRequest.Builder().build(); List<RangingResult> results = new ArrayList<>(); - results.add( - new RangingResult(RangingResult.STATUS_SUCCESS, MacAddress.BROADCAST_ADDRESS, 15, 5, - 10, 8, 5, null, null, null, 666, true)); + results.add(new RangingResult.Builder() + .setStatus(RangingResult.STATUS_SUCCESS) + .setMacAddress(MacAddress.BROADCAST_ADDRESS) + .setDistanceMm(15) + .setDistanceStdDevMm(5) + .setRssi(10) + .setNumAttemptedMeasurements(8) + .setNumSuccessfulMeasurements(5) + .setRangingTimestampMillis(666) + .set80211mcMeasurement(true) + .build()); RangingResultCallback callbackMock = mock(RangingResultCallback.class); ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class); @@ -155,6 +167,9 @@ public class WifiRttManagerTest { builder.addWifiAwarePeer(mac1); builder.addWifiAwarePeer(peerHandle1); builder.setRttBurstSize(4); + if (SdkLevel.isAtLeastV()) { + builder.setVendorData(OuiKeyedDataUtil.createTestOuiKeyedDataList(5)); + } RangingRequest request = builder.build(); Parcel parcelW = Parcel.obtain(); @@ -444,11 +459,25 @@ public class WifiRttManagerTest { long timestamp = System.currentTimeMillis(); byte[] lci = { 0x5, 0x6, 0x7 }; byte[] lcr = { 0x1, 0x2, 0x3, 0xA, 0xB, 0xC }; + List<OuiKeyedData> vendorData = OuiKeyedDataUtil.createTestOuiKeyedDataList(5); // RangingResults constructed with a MAC address - RangingResult result = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, - numAttemptedMeasurements, numSuccessfulMeasurements, lci, lcr, null, timestamp, - true); + RangingResult.Builder resultBuilder = new RangingResult.Builder() + .setStatus(status) + .setMacAddress(mac) + .setDistanceMm(distanceCm) + .setDistanceStdDevMm(distanceStdDevCm) + .setRssi(rssi) + .setNumAttemptedMeasurements(numAttemptedMeasurements) + .setNumSuccessfulMeasurements(numSuccessfulMeasurements) + .setLci(lci) + .setLcr(lcr) + .setRangingTimestampMillis(timestamp) + .set80211mcMeasurement(true); + if (SdkLevel.isAtLeastV()) { + resultBuilder.setVendorData(vendorData); + } + RangingResult result = resultBuilder.build(); Parcel parcelW = Parcel.obtain(); result.writeToParcel(parcelW, 0); @@ -463,21 +492,19 @@ public class WifiRttManagerTest { assertEquals(result, rereadResult); // RangingResults constructed with a PeerHandle - result = - new RangingResult( - status, - peerHandle, - distanceCm, - distanceStdDevCm, - rssi, - numAttemptedMeasurements, - numSuccessfulMeasurements, - null, - null, - null, - timestamp, - RangingResult.UNSPECIFIED, - RangingResult.UNSPECIFIED); + resultBuilder = new RangingResult.Builder() + .setStatus(status) + .setPeerHandle(peerHandle) + .setDistanceMm(distanceCm) + .setDistanceStdDevMm(distanceStdDevCm) + .setRssi(rssi) + .setNumAttemptedMeasurements(numAttemptedMeasurements) + .setNumSuccessfulMeasurements(numSuccessfulMeasurements) + .setRangingTimestampMillis(timestamp); + if (SdkLevel.isAtLeastV()) { + resultBuilder.setVendorData(vendorData); + } + result = resultBuilder.build(); parcelW = Parcel.obtain(); result.writeToParcel(parcelW, 0); @@ -509,13 +536,30 @@ public class WifiRttManagerTest { byte[] lci = { }; byte[] lcr = { }; - RangingResult rr1 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, - numAttemptedMeasurements, numSuccessfulMeasurements, lci, lcr, null, timestamp, - true); - RangingResult rr2 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, - numAttemptedMeasurements, numSuccessfulMeasurements, null, null, null, timestamp, - true); - + RangingResult rr1 = new RangingResult.Builder() + .setStatus(status) + .setMacAddress(mac) + .setDistanceMm(distanceCm) + .setDistanceStdDevMm(distanceStdDevCm) + .setRssi(rssi) + .setNumAttemptedMeasurements(numAttemptedMeasurements) + .setNumSuccessfulMeasurements(numSuccessfulMeasurements) + .setLci(lci) + .setLcr(lcr) + .setRangingTimestampMillis(timestamp) + .set80211mcMeasurement(true) + .build(); + RangingResult rr2 = new RangingResult.Builder() + .setStatus(status) + .setMacAddress(mac) + .setDistanceMm(distanceCm) + .setDistanceStdDevMm(distanceStdDevCm) + .setRssi(rssi) + .setNumAttemptedMeasurements(numAttemptedMeasurements) + .setNumSuccessfulMeasurements(numSuccessfulMeasurements) + .setRangingTimestampMillis(timestamp) + .set80211mcMeasurement(true) + .build(); assertEquals(rr1, rr2); } @@ -525,9 +569,15 @@ public class WifiRttManagerTest { @Test public void testResponderConfigParcel() { // ResponderConfig constructed with a MAC address - ResponderConfig config = new ResponderConfig(MacAddress.fromString("00:01:02:03:04:05"), - ResponderConfig.RESPONDER_AP, true, ResponderConfig.CHANNEL_WIDTH_80MHZ, 2134, 2345, - 2555, ResponderConfig.PREAMBLE_LEGACY); + ResponderConfig config = new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromString("00:01:02:03:04:05")) + .set80211mcSupported(true) + .setChannelWidth(ScanResult.CHANNEL_WIDTH_80MHZ) + .setFrequencyMhz(2134) + .setCenterFreq0Mhz(2345) + .setCenterFreq1Mhz(2555) + .setPreamble(ScanResult.PREAMBLE_LEGACY) + .build(); Parcel parcelW = Parcel.obtain(); config.writeToParcel(parcelW, 0); @@ -542,9 +592,16 @@ public class WifiRttManagerTest { assertEquals(config, rereadConfig); // ResponderConfig constructed with a PeerHandle - config = new ResponderConfig(new PeerHandle(10), ResponderConfig.RESPONDER_AWARE, false, - ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ, 5555, 6666, 7777, - ResponderConfig.PREAMBLE_VHT); + config = new ResponderConfig.Builder() + .setPeerHandle(new PeerHandle(10)) + .setResponderType(ResponderConfig.RESPONDER_AWARE) + .set80211mcSupported(false) + .setChannelWidth(ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ) + .setFrequencyMhz(5555) + .setCenterFreq0Mhz(6666) + .setCenterFreq1Mhz(7777) + .setPreamble(ScanResult.PREAMBLE_VHT) + .build(); parcelW = Parcel.obtain(); config.writeToParcel(parcelW, 0); diff --git a/framework/tests/src/android/net/wifi/twt/TwtRequestTest.java b/framework/tests/src/android/net/wifi/twt/TwtRequestTest.java new file mode 100644 index 0000000000..81f5a61b33 --- /dev/null +++ b/framework/tests/src/android/net/wifi/twt/TwtRequestTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 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 android.net.wifi.twt; + +import static android.net.wifi.MloLink.MAX_MLO_LINK_ID; +import static android.net.wifi.MloLink.MIN_MLO_LINK_ID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit tests for {@link TwtRequest} + */ +@SmallTest +public class TwtRequestTest { + @Test + public void testTwtRequest() { + + final int testMinWakeDuration = 100; + final int testMaxWakeDuration = 1000; + final int testMinWakeInterval = 9999; + final int testMaxWakeInterval = 999999; + final int testMloLinkId = 2; + + TwtRequest.Builder builder = new TwtRequest.Builder(testMinWakeDuration, + testMaxWakeDuration, testMinWakeInterval, testMaxWakeInterval); + + assertThrows(IllegalArgumentException.class, () -> builder.setLinkId(MIN_MLO_LINK_ID - 1)); + assertThrows(IllegalArgumentException.class, () -> builder.setLinkId(MAX_MLO_LINK_ID + 1)); + + builder.setLinkId(testMloLinkId); + TwtRequest twtRequest = builder.build(); + assertEquals(testMinWakeDuration, twtRequest.getMinWakeDurationMicros()); + assertEquals(testMaxWakeDuration, twtRequest.getMaxWakeDurationMicros()); + assertEquals(testMinWakeInterval, twtRequest.getMinWakeIntervalMicros()); + assertEquals(testMaxWakeInterval, twtRequest.getMaxWakeIntervalMicros()); + assertEquals(testMloLinkId, twtRequest.getLinkId()); + } +} diff --git a/framework/tests/src/android/net/wifi/util/ScanResultUtilTest.java b/framework/tests/src/android/net/wifi/util/ScanResultUtilTest.java index b1116332de..4a485c06ab 100644 --- a/framework/tests/src/android/net/wifi/util/ScanResultUtilTest.java +++ b/framework/tests/src/android/net/wifi/util/ScanResultUtilTest.java @@ -44,8 +44,16 @@ public class ScanResultUtilTest { @Test public void testNetworkCreationFromScanResult() { final String ssid = "Another SSid"; - ScanResult scanResult = new ScanResult(ssid, "ab:cd:01:ef:45:89", 1245, 0, "", - -78, 2450, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); scanResult.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) }; @@ -137,22 +145,16 @@ public class ScanResultUtilTest { @Test public void testGenerateSecurityParamsListFromScanResult() { final String ssid = "Another SSid"; - ScanResult scanResult = - new ScanResult( - ssid, - "ab:cd:01:ef:45:89", - 1245, - 0, - "", - -78, - 2450, - 1025, - 22, - 33, - 20, - 0, - 0, - true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); scanResult.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -314,9 +316,17 @@ public class ScanResultUtilTest { final String ssid = "WPA3-Transition"; String caps = "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -333,9 +343,17 @@ public class ScanResultUtilTest { final String ssid = "WPA3-Transition"; String caps = "[WPA2-FT/PSK+PSK+SAE+FT/SAE-CCMP][ESS][WPS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -352,9 +370,17 @@ public class ScanResultUtilTest { final String ssid = "WPA2-Network"; String caps = "[WPA2-FT/PSK+PSK][ESS][WPS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -371,9 +397,17 @@ public class ScanResultUtilTest { final String ssid = "WPA3-Network"; String caps = "[WPA2-FT/SAE+SAE][ESS][WPS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -390,9 +424,17 @@ public class ScanResultUtilTest { final String ssid = "WPA3-AP"; String caps = "[RSN-SAE_EXT_KEY-CCMP][ESS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -409,9 +451,17 @@ public class ScanResultUtilTest { final String ssid = "FT-EAP-AP"; String caps = " [WPA2-FT/EAP-CCMP][RSN-FT/EAP-CCMP][ESS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -429,9 +479,17 @@ public class ScanResultUtilTest { String caps = "[WPA2-EAP-FILS-SHA256-CCMP]" + "[RSN-EAP-FILS-SHA256-CCMP][ESS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -450,9 +508,17 @@ public class ScanResultUtilTest { String caps = "[WPA2-EAP-FILS-SHA384-CCMP]" + "[RSN-EAP-FILS-SHA384-CCMP][ESS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -470,9 +536,17 @@ public class ScanResultUtilTest { final String ssid = "EAP-NETWORK"; String caps = "[EAP/SHA1][ESS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -488,9 +562,18 @@ public class ScanResultUtilTest { boolean isR1R2Network, boolean isR3Network) { final String ssid = "PASSPOINT-NETWORK"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); + if (isPasspoint) { input.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK); } @@ -545,9 +628,17 @@ public class ScanResultUtilTest { final String ssid = "UnknownAkm-Network"; String caps = "[RSN-?-TKIP+CCMP][ESS][WPS]"; - ScanResult input = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult input = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); input.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) @@ -558,9 +649,19 @@ public class ScanResultUtilTest { private ScanResult makeScanResult(String caps) { final String ssid = "TestSsid"; - ScanResult r = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + + ScanResult r = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); + return r; } @@ -645,8 +746,17 @@ public class ScanResultUtilTest { @Test public void testUnknownAkmForSecurityParamsGeneration() { final String ssid = "Another SSid"; - ScanResult scanResult = new ScanResult(ssid, "ab:cd:01:ef:45:89", 1245, 0, "", - -78, 2450, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); + scanResult.informationElements = new InformationElement[] { createIE(InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)) }; diff --git a/service/Android.bp b/service/Android.bp index 10bcdbadf9..220d9fb74a 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -121,7 +121,7 @@ java_library { "service-entitlement", "wifi-lite-protos", "wifi-nano-protos", - "wifi_aconfig_flags_lib", + "android.net.wifi.flags-aconfig-java", ], apex_available: ["com.android.wifi"], } diff --git a/service/ServiceWifiResources/res/values-af/strings.xml b/service/ServiceWifiResources/res/values-af/strings.xml index 5e429c91d8..3473553ae0 100644 --- a/service/ServiceWifiResources/res/values-af/strings.xml +++ b/service/ServiceWifiResources/res/values-af/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Aan:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Voer die vereiste PIN in:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Die tablet sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Jou Android TV-toestel sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Die foon sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Jou toestel sal tydelik van wi-fi af ontkoppel word terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Kan nie aan <xliff:g id="SSID">%1$s</xliff:g> koppel nie"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tik om privaatheidinstellings te verander en herprobeer"</string> diff --git a/service/ServiceWifiResources/res/values-am/strings.xml b/service/ServiceWifiResources/res/values-am/strings.xml index 24af7e8ad8..4adbe8c0fb 100644 --- a/service/ServiceWifiResources/res/values-am/strings.xml +++ b/service/ServiceWifiResources/res/values-am/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ለ፦"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"የሚፈለገውን ፒን ተይብ፦"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"ፒን፦"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ጡባዊው ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ተገናኝቶ ባለበት ጊዜ በጊዜያዊነት ከWi-Fi ጋር ይላቀቃል"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"ወደ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ተገናኝቶ ሳለ የእርስዎ Android TV መሣሪያ ለጊዜው ከ Wi-Fi ግንኙነቱ ይቋረጣል"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ስልኩ ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ተገናኝቶ ባለበት ጊዜ በጊዜያዊነት ከWi-Fi ጋር ያለው ግንኙነት ይቋረጣል"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"መሣሪያዎ ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር በሚገናኝበት ጊዜ ለጊዜው ከWi-Fi ጋር ግንኙነቱ ይቋረጣል"</string> <string name="dlg_ok" msgid="254496739491689405">"እሺ"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"ከ<xliff:g id="SSID">%1$s</xliff:g> ጋር መገናኘት አልተቻለም"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"የግላዊነት ቅንብሮችን ለመቀየር መታ ያድርጉ እና ዳግም ይሞክሩ"</string> diff --git a/service/ServiceWifiResources/res/values-ar/strings.xml b/service/ServiceWifiResources/res/values-ar/strings.xml index 9b015a264f..619d94501f 100644 --- a/service/ServiceWifiResources/res/values-ar/strings.xml +++ b/service/ServiceWifiResources/res/values-ar/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"إلى:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"اكتب رمز PIN المطلوب:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"رقم التعريف الشخصي:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"سيتم قطع اتصال الجهاز اللوحي مؤقتًا بشبكة Wi-Fi في الوقت الذي يكون فيه متصلاً بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"سيتم قطع اتصال جهاز Android TV بشبكة Wi-Fi مؤقتًا أثناء اتصاله بجهاز<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"سيتم قطع اتصال الهاتف مؤقتًا بشبكة Wi-Fi في الوقت الذي يكون فيه متصلاً بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"سيتم قطع اتصال الجهاز بشبكة Wi-Fi مؤقتًا أثناء اتصاله بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"حسنًا"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"يتعذّر الاتصال بـ <xliff:g id="SSID">%1$s</xliff:g>."</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"انقر لتغيير إعدادات الخصوصية وإعادة المحاولة."</string> diff --git a/service/ServiceWifiResources/res/values-as/strings.xml b/service/ServiceWifiResources/res/values-as/strings.xml index 7f47460530..4b2f966940 100644 --- a/service/ServiceWifiResources/res/values-as/strings.xml +++ b/service/ServiceWifiResources/res/values-as/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"প্ৰতি:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"প্ৰয়োজনীয় পিন নম্বৰটো লিখক:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"পিন:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"টি.ভি.টো <xliff:g id="DEVICE_NAME">%1$s</xliff:g> লৈ সংযোগ হৈ থকাৰ অৱস্থাত অস্থায়ীভাৱে ৱাই-ফাইৰ পৰা সংযোগ বিচ্ছিন্ন হ\'ব"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"আপোনাৰ Android TV ডিভাইচটো <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ লগত সংযোগ হ’লে অস্থায়ীভাৱে ৱাই-ফাইৰ পৰা সংযোগ বিচ্ছিন্ন হ’ব"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ফ\'নটো <xliff:g id="DEVICE_NAME">%1$s</xliff:g> লৈ সংযোগ হ\'লে ৱাই-ফাইৰ পৰা কিছু সময়ৰ বাবে সংযোগ স্বীকাৰ বিচ্ছিন্ন হ\'ব"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"আপোনাৰ ডিভাইচটো <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ লগত সংযুক্ত হৈ থকাৰ অৱস্থাত অস্থায়ীভাৱে ৱাই-ফাইৰ পৰা সংযোগ বিচ্ছিন্ন হ’ব"</string> <string name="dlg_ok" msgid="254496739491689405">"ঠিক আছে"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰিব নোৱাৰি"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"গোপনীয়তাৰ ছেটিং সলনি কৰিবলৈ আৰু পুনৰ চেষ্টা কৰিবলৈ টিপক"</string> diff --git a/service/ServiceWifiResources/res/values-az/strings.xml b/service/ServiceWifiResources/res/values-az/strings.xml index b9f844492e..b39b9715cc 100644 --- a/service/ServiceWifiResources/res/values-az/strings.xml +++ b/service/ServiceWifiResources/res/values-az/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kimə:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Tələb olunan PİN kodu daxil edin:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PİN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Bu planşet <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşulan zaman Wi-Fi şəbəkəsindən müvəqqəti ayrılmış olacaq"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşularkən Wi-Fi bağlantısı müvəqqəti olaraq kəsiləcək."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Bu telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşulan zaman Wi-Fi şəbəkəsindən müvəqqəti ayrılmış olacaq"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşulanda cihaz Wi-Fi-dan müvəqqəti ayrılacaq"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> şəbəkəsinə qoşulmaq mümkün deyil"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Toxunaraq məxfilik ayarını dəyişin və yenidən cəhd edin"</string> diff --git a/service/ServiceWifiResources/res/values-b+sr+Latn/strings.xml b/service/ServiceWifiResources/res/values-b+sr+Latn/strings.xml index 97bd1970cd..6799970ff6 100644 --- a/service/ServiceWifiResources/res/values-b+sr+Latn/strings.xml +++ b/service/ServiceWifiResources/res/values-b+sr+Latn/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kome:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Unesite potrebni PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablet će privremeno prekinuti vezu sa WiFi-em dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV uređaj će privremeno prekinuti vezu sa WiFi mrežom dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefon će privremeno prekinuti vezu sa WiFi-em dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Uređaj će privremeno prekinuti vezu sa WiFi mrežom dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Potvrdi"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Povezivanje na mrežu <xliff:g id="SSID">%1$s</xliff:g> nije uspelo"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Dodirnite da biste promenili podešavanja privatnosti i probali ponovo"</string> diff --git a/service/ServiceWifiResources/res/values-be/strings.xml b/service/ServiceWifiResources/res/values-be/strings.xml index 9212251cc3..ae333d9730 100644 --- a/service/ServiceWifiResources/res/values-be/strings.xml +++ b/service/ServiceWifiResources/res/values-be/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Каму:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Увядзіце патрэбны PIN-код:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-код"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Тэлефон будзе часова адключаны ад сеткі Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Прылада Android TV будзе часова адключана ад сеткі Wi-Fi, пакуль яна падключана да прылады \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\""</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Тэлефон будзе часова адключаны ад Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Прылада будзе часова заставацца адключанай ад сеткі Wi-Fi, пакуль падключана да прылады \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\""</string> <string name="dlg_ok" msgid="254496739491689405">"ОК"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Не ўдалося падключыцца да сеткі \"<xliff:g id="SSID">%1$s</xliff:g>\""</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Націсніце, каб змяніць налады прыватнасці, і паўтарыце спробу"</string> diff --git a/service/ServiceWifiResources/res/values-bg/strings.xml b/service/ServiceWifiResources/res/values-bg/strings.xml index 16cf7424df..eb2f5f49da 100644 --- a/service/ServiceWifiResources/res/values-bg/strings.xml +++ b/service/ServiceWifiResources/res/values-bg/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"До:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Въведете задължителния ПИН:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"ПИН:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Таблетът временно ще прекъсне връзката с Wi-Fi, докато е свързан с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Wi-Fi връзката на устройството ви с Android TV временно ще бъде прекратена, докато то е свързано към <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Телефонът временно ще прекрати връзката с Wi-Fi, докато е свързан с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Връзката с Wi-Fi на устройството ви временно ще бъде прекратена, докато то е свързано с(ъс) <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Не може да се установи връзка с(ъс) <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Докоснете, за да промените настройките за поверителност, и опитайте отново"</string> diff --git a/service/ServiceWifiResources/res/values-bn/strings.xml b/service/ServiceWifiResources/res/values-bn/strings.xml index f43872581d..f981dc2988 100644 --- a/service/ServiceWifiResources/res/values-bn/strings.xml +++ b/service/ServiceWifiResources/res/values-bn/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"প্রাপক:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"প্রয়োজনীয় পিনটি লিখুন:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"পিন:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ট্যাবলেটটি যখন <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত হবে তখন এটি ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-এ কানেক্ট থাকা অবস্থায় আপনার Android TV ডিভাইস সাময়িকভাবে ওয়াই-ফাই থেকে ডিসকানেক্ট হয়ে যাবে"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ফোনটি যখন <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত হবে তখন এটি ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-এ কানেক্ট থাকা অবস্থায় আপনার ডিভাইস সাময়িকভাবে ওয়াই-ফাই থেকে ডিসকানেক্ট হয়ে যাবে"</string> <string name="dlg_ok" msgid="254496739491689405">"ঠিক আছে"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>-এর সাথে কানেক্ট করা যাচ্ছে না"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"গোপনীয়তা সেটিংস পরিবর্তন করতে এবং আবার চেষ্টা করতে ট্যাপ করুন"</string> diff --git a/service/ServiceWifiResources/res/values-bs/strings.xml b/service/ServiceWifiResources/res/values-bs/strings.xml index 73414bdde2..ca0ea80d7a 100644 --- a/service/ServiceWifiResources/res/values-bs/strings.xml +++ b/service/ServiceWifiResources/res/values-bs/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Prima:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Unesite potrebni PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablet će privremeno prekinuti WiFi vezu dok bude povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Povezanost Android TV uređaja i WiFi mreže će se privremeno prekinuti dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefon će privremeno prekinuti WiFi vezu dok bude povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Povezanost uređaja s WiFi mrežom će se privremeno prekinuti dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Uredu"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Nije se moguće povezati s mrežom <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Dodirnite da promijenite postavke privatnosti i pokušajte ponovo"</string> diff --git a/service/ServiceWifiResources/res/values-ca/strings.xml b/service/ServiceWifiResources/res/values-ca/strings.xml index 86c4fe2d7c..97483600ba 100644 --- a/service/ServiceWifiResources/res/values-ca/strings.xml +++ b/service/ServiceWifiResources/res/values-ca/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Per a:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Introdueix el PIN sol·licitat:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"La tauleta es desconnectarà temporalment de la Wi-Fi mentre estigui connectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"El dispositiu Android TV es desconnectarà temporalment de la Wi‑Fi mentre estigui connectat a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"El telèfon es desconnectarà temporalment de la Wi-Fi mentre estigui connectat a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"El dispositiu es desconnectarà temporalment de la Wi‑Fi mentre estigui connectat a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"D\'acord"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"No es pot connectar a <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Toca per canviar la configuració de privadesa i torna-ho a provar"</string> diff --git a/service/ServiceWifiResources/res/values-cs/strings.xml b/service/ServiceWifiResources/res/values-cs/strings.xml index 99640357a9..e26e53cedb 100644 --- a/service/ServiceWifiResources/res/values-cs/strings.xml +++ b/service/ServiceWifiResources/res/values-cs/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Komu:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Zadejte požadovaný kód PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablet se při připojení k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasně odpojí od sítě Wi-Fi"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Zatímco bude zařízení Android TV připojeno k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, dočasně se odpojí od sítě Wi-Fi."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefon se při připojení k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasně odpojí od sítě Wi-Fi"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Zatímco bude zařízení připojeno k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, dočasně se odpojí od Wi-Fi"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"K síti <xliff:g id="SSID">%1$s</xliff:g> se nelze připojit"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Klepnutím změníte nastavení ochrany soukromí a budete opakovat pokus"</string> diff --git a/service/ServiceWifiResources/res/values-da/strings.xml b/service/ServiceWifiResources/res/values-da/strings.xml index 5d08fa5298..6a27388ae7 100644 --- a/service/ServiceWifiResources/res/values-da/strings.xml +++ b/service/ServiceWifiResources/res/values-da/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Til:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Skriv den påkrævede pinkode:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"Pinkode:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Wi-Fi-forbindelse til tabletten vil midlertidigt blive afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Wi-Fi-forbindelsen til din Android TV-enhed bliver midlertidigt afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefonens Wi-Fi-forbindelse vil midlertidigt blive afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Enhedens Wi-Fi-forbindelse afbrydes midlertidigt, når den er tilknyttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Der kan ikke oprettes forbindelse til <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tryk for at ændre privatlivsindstillingerne, og prøv igen"</string> diff --git a/service/ServiceWifiResources/res/values-de/strings.xml b/service/ServiceWifiResources/res/values-de/strings.xml index 1f5c2bdf9c..4032ff10e2 100644 --- a/service/ServiceWifiResources/res/values-de/strings.xml +++ b/service/ServiceWifiResources/res/values-de/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"An:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Gib die PIN ein:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Das Tablet wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> besteht."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Das Android TV-Gerät wird vorübergehend vom WLAN getrennt, während es mit \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" verbunden ist."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Das Telefon wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hergestellt wird."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Dein Gerät wird vorübergehend vom WLAN getrennt, während es mit „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ verbunden ist"</string> <string name="dlg_ok" msgid="254496739491689405">"Ok"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Verbindung zu <xliff:g id="SSID">%1$s</xliff:g> nicht möglich"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tippe, um die Datenschutzeinstellung zu ändern und es noch einmal zu versuchen"</string> diff --git a/service/ServiceWifiResources/res/values-el/strings.xml b/service/ServiceWifiResources/res/values-el/strings.xml index 09ae52a997..1e3a8e0b0e 100644 --- a/service/ServiceWifiResources/res/values-el/strings.xml +++ b/service/ServiceWifiResources/res/values-el/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Προς:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Πληκτρολογήστε τον απαιτούμενο κωδικό PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Το tablet θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ συνδέεται στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Η συσκευή σας Android TV θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi, ενόσω είναι συνδεδεμένη στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Το τηλέφωνο θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ συνδέεται στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Η συσκευή σας θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ είναι συνδεδεμένη στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"ΟΚ"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Δεν είναι δυνατή η σύνδεση με <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Πατήστε για αλλαγή των ρυθμίσεων απορρήτου και δοκιμάστε ξανά"</string> diff --git a/service/ServiceWifiResources/res/values-en-rAU/strings.xml b/service/ServiceWifiResources/res/values-en-rAU/strings.xml index c5540fef7e..03afd3affa 100644 --- a/service/ServiceWifiResources/res/values-en-rAU/strings.xml +++ b/service/ServiceWifiResources/res/values-en-rAU/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"To:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Type the required PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Your device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Can\'t connect to <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tap to change privacy settings and retry"</string> diff --git a/service/ServiceWifiResources/res/values-en-rCA/strings.xml b/service/ServiceWifiResources/res/values-en-rCA/strings.xml index b89fb28d5f..d15645c2c7 100644 --- a/service/ServiceWifiResources/res/values-en-rCA/strings.xml +++ b/service/ServiceWifiResources/res/values-en-rCA/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"To:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Type the required PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Your device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Can\'t connect to <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tap to change privacy settings and retry"</string> diff --git a/service/ServiceWifiResources/res/values-en-rGB/strings.xml b/service/ServiceWifiResources/res/values-en-rGB/strings.xml index c5540fef7e..03afd3affa 100644 --- a/service/ServiceWifiResources/res/values-en-rGB/strings.xml +++ b/service/ServiceWifiResources/res/values-en-rGB/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"To:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Type the required PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Your device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Can\'t connect to <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tap to change privacy settings and retry"</string> diff --git a/service/ServiceWifiResources/res/values-en-rIN/strings.xml b/service/ServiceWifiResources/res/values-en-rIN/strings.xml index c5540fef7e..03afd3affa 100644 --- a/service/ServiceWifiResources/res/values-en-rIN/strings.xml +++ b/service/ServiceWifiResources/res/values-en-rIN/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"To:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Type the required PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Your device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Can\'t connect to <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tap to change privacy settings and retry"</string> diff --git a/service/ServiceWifiResources/res/values-en-rXC/strings.xml b/service/ServiceWifiResources/res/values-en-rXC/strings.xml index d5e5c56c98..6c41c5400c 100644 --- a/service/ServiceWifiResources/res/values-en-rXC/strings.xml +++ b/service/ServiceWifiResources/res/values-en-rXC/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"To:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Type the required PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Your device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Can\'t connect to <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tap to change privacy settings and retry"</string> diff --git a/service/ServiceWifiResources/res/values-es-rUS/strings.xml b/service/ServiceWifiResources/res/values-es-rUS/strings.xml index 66ddc08d91..200eb24cba 100644 --- a/service/ServiceWifiResources/res/values-es-rUS/strings.xml +++ b/service/ServiceWifiResources/res/values-es-rUS/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Escribe el PIN solicitado:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"La tablet se desconectará temporalmente de la red Wi-Fi mientras esté conectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Se desconectará temporalmente el dispositivo Android TV de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"El dispositivo se desconectará temporalmente de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Se desconectará temporalmente el dispositivo de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Aceptar"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"No se puede establecer conexión con <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Presiona para cambiar la configuración de privacidad y volver a intentarlo"</string> diff --git a/service/ServiceWifiResources/res/values-es/strings.xml b/service/ServiceWifiResources/res/values-es/strings.xml index 6302a34ff4..33f0d5e984 100644 --- a/service/ServiceWifiResources/res/values-es/strings.xml +++ b/service/ServiceWifiResources/res/values-es/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Escribe el PIN solicitado:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"El tablet se desconectará temporalmente de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Mientras el dispositivo Android TV esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, se desconectará temporalmente de la red Wi‑Fi"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"El teléfono se desconectará temporalmente de la red Wi-Fi mientras está conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Tu dispositivo se desconectará temporalmente de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Aceptar"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"No se puede conectar a <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Toca para cambiar los ajustes de privacidad y vuelve a intentarlo"</string> diff --git a/service/ServiceWifiResources/res/values-et/strings.xml b/service/ServiceWifiResources/res/values-et/strings.xml index 6ad483c705..444af98731 100644 --- a/service/ServiceWifiResources/res/values-et/strings.xml +++ b/service/ServiceWifiResources/res/values-et/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Saaja:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Sisestage nõutav PIN-kood:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-kood:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tahvelarvuti ühendus WiFi-ga katkestatakse ajutiselt, kui see on ühendatud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ühendamisel katkestatakse ajutiselt Android TV seadme ühendus WiFi-võrguga."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefoni ühendus WiFi-ga katkestatakse ajutiselt, kui see on ühendatud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ühenduse loomisel katkestatakse ajutiselt teie seadme ühendus WiFi-võrguga."</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Võrguga <xliff:g id="SSID">%1$s</xliff:g> ei õnnestu ühendada"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Puudutage privaatsusseadete muutmiseks ja uuesti proovimiseks"</string> diff --git a/service/ServiceWifiResources/res/values-eu/strings.xml b/service/ServiceWifiResources/res/values-eu/strings.xml index c1463a4871..9ec4e91d5c 100644 --- a/service/ServiceWifiResources/res/values-eu/strings.xml +++ b/service/ServiceWifiResources/res/values-eu/strings.xml @@ -40,10 +40,10 @@ <string name="wifi_suggestion_imsi_privacy_exemption_confirmation_content" msgid="9211241189147807136">"Konektatzen bazara, baliteke <xliff:g id="CARRIERNAME">%s</xliff:g> operadorearen wifi-sareek zure SIM txartelarekin lotutako identifikatzaile esklusiboa atzitzea edo partekatzea. Horrela, baliteke zure gailuaren kokapenaren jarraipena egiteko aukera izatea."</string> <string name="wifi_suggestion_action_allow_imsi_privacy_exemption_confirmation" msgid="2168947026413431603">"Konektatu"</string> <string name="wifi_suggestion_action_disallow_imsi_privacy_exemption_confirmation" msgid="5156881939985876066">"Ez konektatu"</string> - <string name="wifi_wakeup_onboarding_title" msgid="3868826648004934540">"Wi‑Fi konexioa automatikoki aktibatuko da"</string> + <string name="wifi_wakeup_onboarding_title" msgid="3868826648004934540">"Wifi-konexioa automatikoki aktibatuko da"</string> <string name="wifi_wakeup_onboarding_subtext" msgid="5705886295837387430">"Gordeta daukazun kalitate handiko sare batetik gertu zaudenean"</string> <string name="wifi_wakeup_onboarding_action_disable" msgid="6209706680391785825">"Ez aktibatu berriro"</string> - <string name="wifi_wakeup_enabled_title" msgid="5043486751612595850">"Automatikoki aktibatu da Wi‑Fi konexioa"</string> + <string name="wifi_wakeup_enabled_title" msgid="5043486751612595850">"Automatikoki aktibatu da wifi-konexioa"</string> <string name="wifi_wakeup_enabled_content" msgid="3911262526267025882">"Gordetako sare honetatik gertu zaude: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string> <string name="wifi_watchdog_network_disabled" msgid="5769226742956006362">"Ezin izan da wifi-sarera konektatu"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="1725243835135539125">" SSIDak Interneteko konexio txarra du."</string> @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Hartzaileak:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Idatzi beharrezko PINa:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PINa:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tableta wifi-saretik deskonektatuko da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV gailua wifi-saretik deskonektatuko da aldi batez <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefonoa wifi-saretik deskonektatuko da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Gailua wifi-saretik deskonektatuko da aldi batez <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string> <string name="dlg_ok" msgid="254496739491689405">"Ados"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Ezin da konektatu <xliff:g id="SSID">%1$s</xliff:g> sarera"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Sakatu hau pribatutasun-ezarpenak aldatzeko, eta saiatu berriro"</string> diff --git a/service/ServiceWifiResources/res/values-fa/strings.xml b/service/ServiceWifiResources/res/values-fa/strings.xml index f4c842608c..c1012ffb3f 100644 --- a/service/ServiceWifiResources/res/values-fa/strings.xml +++ b/service/ServiceWifiResources/res/values-fa/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"به:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"پین لازم را تایپ کنید:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"پین:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"در حین اتصال به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ارتباط این رایانه لوحی با Wi-Fi موقتاً قطع خواهد شد."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"وقتی دستگاه Android TV به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> متصل است، اتصال آن به Wi-Fi موقتاً قطع میشود"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"این گوشی بهطور موقت از Wi-Fi قطع خواهد شد، در حالی که به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> وصل است"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"وقتی دستگاهتان به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> متصل است، اتصال آن به Wi-Fi موقتاً قطع میشود"</string> <string name="dlg_ok" msgid="254496739491689405">"تأیید"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"اتصال به <xliff:g id="SSID">%1$s</xliff:g> امکانپذیر نیست"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"برای تغییر تنظیم حریم خصوصی ضربه بزنید و دوباره امتحان کنید"</string> diff --git a/service/ServiceWifiResources/res/values-fi/strings.xml b/service/ServiceWifiResources/res/values-fi/strings.xml index 4c1dbf467d..dcda428a8f 100644 --- a/service/ServiceWifiResources/res/values-fi/strings.xml +++ b/service/ServiceWifiResources/res/values-fi/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kohde:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Kirjoita pyydetty PIN-koodi:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-koodi:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablet-laitteen yhteys Wi-Fi-verkkoon katkaistaan väliaikaisesti tabletin ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV ‑laitteen Wi-Fi-yhteys katkeaa tilapäisesti, kun siihen on yhdistetty <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Puhelimen yhteys Wi-Fi-verkkoon katkaistaan väliaikaisesti puhelimen ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Laitteen Wi-Fi-yhteys katkeaa tilapäisesti, kun siihen on yhdistetty <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Verkkoon <xliff:g id="SSID">%1$s</xliff:g> ei saada yhteyttä"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Napauta muuttaaksesi yksityisyysasetusta ja yritä uudelleen"</string> diff --git a/service/ServiceWifiResources/res/values-fr-feminine/strings.xml b/service/ServiceWifiResources/res/values-fr-feminine/strings.xml new file mode 100644 index 0000000000..bc890db014 --- /dev/null +++ b/service/ServiceWifiResources/res/values-fr-feminine/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wifi_eap_error_message_code_32763_carrier_overrides"> + <item msgid="591026649262091217">"<xliff:g id="CARRIER_ID_PREFIX">:::1839:::</xliff:g> <xliff:g id="SSID">%1$s</xliff:g> : vous êtes déjà connectée à Verizon Wi-Fi Access. (Erreur 32763)"</item> + </string-array> +</resources> diff --git a/service/ServiceWifiResources/res/values-fr-masculine/strings.xml b/service/ServiceWifiResources/res/values-fr-masculine/strings.xml new file mode 100644 index 0000000000..9ed7470594 --- /dev/null +++ b/service/ServiceWifiResources/res/values-fr-masculine/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wifi_eap_error_message_code_32763_carrier_overrides"> + <item msgid="591026649262091217">"<xliff:g id="CARRIER_ID_PREFIX">:::1839:::</xliff:g> <xliff:g id="SSID">%1$s</xliff:g> : vous êtes déjà connecté à Verizon Wi-Fi Access. (Erreur 32763)"</item> + </string-array> +</resources> diff --git a/service/ServiceWifiResources/res/values-fr-neuter/strings.xml b/service/ServiceWifiResources/res/values-fr-neuter/strings.xml new file mode 100644 index 0000000000..025a654e2d --- /dev/null +++ b/service/ServiceWifiResources/res/values-fr-neuter/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wifi_eap_error_message_code_32763_carrier_overrides"> + <item msgid="591026649262091217">"<xliff:g id="CARRIER_ID_PREFIX">:::1839:::</xliff:g> <xliff:g id="SSID">%1$s</xliff:g> : vous êtes déjà connecté·e à Verizon Wi-Fi Access. (Erreur 32763)"</item> + </string-array> +</resources> diff --git a/service/ServiceWifiResources/res/values-fr-rCA/strings.xml b/service/ServiceWifiResources/res/values-fr-rCA/strings.xml index a0a7495fcd..ff9cceaf2b 100644 --- a/service/ServiceWifiResources/res/values-fr-rCA/strings.xml +++ b/service/ServiceWifiResources/res/values-fr-rCA/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"À :"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Saisissez le NIP requis :"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"NIP :"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"La tablette sera déconnectée du réseau Wi-Fi tant qu\'elle sera connectée à l\'appareil \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Votre appareil Android TV se déconnectera temporairement du Wi-Fi lors de sa connexion à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Le téléphone sera déconnecté du réseau Wi-Fi tant qu\'il sera connecté à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Votre appareil sera déconnecté temporairement de la connexion Wi-Fi lorsqu\'il sera connecté à <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Impossible de se connecter à <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Touchez pour modifier les paramètres de confidentialité et réessayer"</string> diff --git a/service/ServiceWifiResources/res/values-fr/strings.xml b/service/ServiceWifiResources/res/values-fr/strings.xml index 181f2a6c1e..cbc4374ae2 100644 --- a/service/ServiceWifiResources/res/values-fr/strings.xml +++ b/service/ServiceWifiResources/res/values-fr/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"À :"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Saisissez le code PIN requis :"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"Code :"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"La tablette sera déconnectée du réseau Wi-Fi tant qu\'elle sera connectée à l\'appareil \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Votre appareil Android TV se déconnectera temporairement du Wi-Fi lors de sa connexion à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Le téléphone sera déconnecté du réseau Wi-Fi tant qu\'il sera connecté à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Tant que votre appareil sera connecté à <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, il sera temporairement déconnecté du Wi-Fi"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Impossible de se connecter à <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Appuyez pour modifier les paramètres de confidentialité, puis réessayez"</string> diff --git a/service/ServiceWifiResources/res/values-gl/strings.xml b/service/ServiceWifiResources/res/values-gl/strings.xml index bdadda5351..5123f9a754 100644 --- a/service/ServiceWifiResources/res/values-gl/strings.xml +++ b/service/ServiceWifiResources/res/values-gl/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Escribe o PIN obrigatorio:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"A tableta desconectarase temporalmente da wifi mentres está conectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"O dispositivo Android TV desconectarase temporalmente da wifi mentres estea conectado a: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"O teléfono desconectarase temporalmente da wifi mentres está conectado con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"O dispositivo desconectarase temporalmente da wifi mentres estea conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Aceptar"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Non se puido establecer conexión co <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Toca para cambiar a configuración de privacidade e tentalo de novo"</string> diff --git a/service/ServiceWifiResources/res/values-gu/strings.xml b/service/ServiceWifiResources/res/values-gu/strings.xml index 4a5a38dac9..3ef9523ea7 100644 --- a/service/ServiceWifiResources/res/values-gu/strings.xml +++ b/service/ServiceWifiResources/res/values-gu/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"પ્રતિ:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"આવશ્યક પિન લખો:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"પિન:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ટેબ્લેટ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> થી કનેક્ટ હોય તે વખતે વાઇ-ફાઇ થી અસ્થાયી રૂપે ડિસ્કનેક્ટ કરવામાં આવશે"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"તમારું Android TV ડિવાઇસ, <xliff:g id="DEVICE_NAME">%1$s</xliff:g>થી કનેક્ટ હોય તે વખતે વાઇ-ફાઇથી અસ્થાયી રૂપે ડિસ્કનેક્ટ કરવામાં આવશે"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ફોન <xliff:g id="DEVICE_NAME">%1$s</xliff:g> થી કનેક્ટ હોય તે વખતે વાઇ-ફાઇ થી અસ્થાયી રૂપે ડિસ્કનેક્ટ કરવામાં આવશે"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"જ્યારે તમારું ડિવાઇસ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> સાથે કનેક્ટેડ હોય, ત્યારે તેને વાઇ-ફાઇથી હંગામી રીતે ડિસ્કનેક્ટ કરવામાં આવશે"</string> <string name="dlg_ok" msgid="254496739491689405">"ઓકે"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> સાથે કનેક્ટ કરી શકાતું નથી"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"પ્રાઇવસી સેટિંગ બદલવા અને ફરી પ્રયાસ કરવા ટૅપ કરો"</string> diff --git a/service/ServiceWifiResources/res/values-hi/strings.xml b/service/ServiceWifiResources/res/values-hi/strings.xml index f9ad27a479..0b6ba44e9a 100644 --- a/service/ServiceWifiResources/res/values-hi/strings.xml +++ b/service/ServiceWifiResources/res/values-hi/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"प्रति:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"आवश्यक पिन लिखें:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"पिन:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहने पर टैबलेट वाई-फ़ाई से अस्थायी रूप से डिसकनेक्ट हो जाएगा"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>से कनेक्ट रहने के दौरान आपका Android TV डिवाइस, Wi-Fi से अस्थायी रूप से डिसकनेक्ट हो जाएगा."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"फ़ोन <xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहते समय वाई-फ़ाई से अस्थायी रूप से डिसकनेक्ट हो जाएगा"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहने के दौरान आपका डिवाइस, वाई-फ़ाई से अस्थायी रूप से डिसकनेक्ट हो जाएगा"</string> <string name="dlg_ok" msgid="254496739491689405">"ठीक है"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> से कनेक्ट नहीं किया जा सकता"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"निजता सेटिंग बदलने के लिए टैप करें और फिर से कोशिश करें"</string> diff --git a/service/ServiceWifiResources/res/values-hr/strings.xml b/service/ServiceWifiResources/res/values-hr/strings.xml index 92e6d14cad..dd3bfba71e 100644 --- a/service/ServiceWifiResources/res/values-hr/strings.xml +++ b/service/ServiceWifiResources/res/values-hr/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Prima:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Upišite potreban PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablet će se privremeno isključiti s Wi-Fija dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV uređaj privremeno će prekinuti vezu s Wi-Fijem dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefon će se privremeno isključiti s Wi-Fija dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Vaš će uređaj privremeno prekinuti vezu s Wi-Fijem dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"U redu"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Povezivanje s mrežom <xliff:g id="SSID">%1$s</xliff:g> nije uspjelo"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Dodirnite da biste promijenili postavke privatnosti i pokušajte ponovo"</string> diff --git a/service/ServiceWifiResources/res/values-hu/strings.xml b/service/ServiceWifiResources/res/values-hu/strings.xml index 983ef1311c..bd7e938bef 100644 --- a/service/ServiceWifiResources/res/values-hu/strings.xml +++ b/service/ServiceWifiResources/res/values-hu/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Címzett:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Adja meg a szükséges PIN kódot:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-kód:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"A táblagép ideiglenesen lecsatlakozik a Wi-Fi hálózatról, míg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Az Android TV eszköz ideiglenesen bontja a Wi-Fi-kapcsolatot arra az időre, amíg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"A telefon ideiglenesen kilép a Wi-Fi hálózatról, míg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Az eszköze ideiglenesen bontja a Wi-Fi-kapcsolatot arra az időre, amíg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Nem lehet csatlakozni a következőhöz: <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Koppintson az adatvédelmi beállítások módosításához, majd próbálja újra"</string> diff --git a/service/ServiceWifiResources/res/values-hy/strings.xml b/service/ServiceWifiResources/res/values-hy/strings.xml index 2a771d82ab..84738c1722 100644 --- a/service/ServiceWifiResources/res/values-hy/strings.xml +++ b/service/ServiceWifiResources/res/values-hy/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Ում`"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Մուտքագրեք պահանջվող PIN-ը:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-ը՝"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Գրասալիկը ժամանակավորապես կանջատվի Wi-Fi-ից, քանի դեռ այն կապակցված է <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ին"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Ձեր Android TV սարքը ժամանակավորապես կանջատվի Wi-Fi-ից, քանի դեռ այն միացված է <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ին"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Հեռախոսը ժամանակավորապես կանջատվի Wi-Fi-ից, քանի դեռ այն միացված է <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ին"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Ձեր սարքը ժամանակավորապես կանջատվի Wi-Fi-ից, քանի դեռ միացված է <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ին"</string> <string name="dlg_ok" msgid="254496739491689405">"Եղավ"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Չհաջողվեց միանալ <xliff:g id="SSID">%1$s</xliff:g> սարքին"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Հպեք՝ գաղտնիության կարգավորումները փոփոխելու և նորից փորձելու համար։"</string> diff --git a/service/ServiceWifiResources/res/values-in/strings.xml b/service/ServiceWifiResources/res/values-in/strings.xml index 514dfca230..5e818035dd 100644 --- a/service/ServiceWifiResources/res/values-in/strings.xml +++ b/service/ServiceWifiResources/res/values-in/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kepada:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Ketik PIN yang diminta:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Sambungan tablet akan diputuskan dari Wi-Fi untuk sementara saat terhubung dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Perangkat Android TV akan memutuskan hubungan sementara dari Wi-Fi saat terhubung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Ponsel akan terputus sementara dari Wi-Fi saat terhubung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Koneksi perangkat akan terputus sementara dari Wi-Fi saat terhubung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Oke"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Tidak dapat terhubung ke <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Ketuk untuk mengubah setelan privasi dan coba lagi"</string> diff --git a/service/ServiceWifiResources/res/values-is/strings.xml b/service/ServiceWifiResources/res/values-is/strings.xml index 15818b8312..ebb850acea 100644 --- a/service/ServiceWifiResources/res/values-is/strings.xml +++ b/service/ServiceWifiResources/res/values-is/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Til:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Sláðu inn PIN-númerið sem er krafist:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-númer:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Wi-Fi tengingu spjaldtölvunnar verður tímabundið slitið á meðan hún er tengd við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV mun tímabundið aftengjast Wi-Fi á meðan það er tengt við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Síminn mun tímabundið aftengjast Wi-Fi á meðan hann er tengdur við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Tækið þitt mun tímabundið aftengjast Wi-Fi á meðan það er tengt við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Í lagi"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Ekki hægt að tengjast <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Ýttu til að breyta persónuverndarstillingum og reyna aftur"</string> diff --git a/service/ServiceWifiResources/res/values-it/strings.xml b/service/ServiceWifiResources/res/values-it/strings.xml index 1143108a18..d029f4e01c 100644 --- a/service/ServiceWifiResources/res/values-it/strings.xml +++ b/service/ServiceWifiResources/res/values-it/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"A:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Inserisci il PIN richiesto:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Il tablet verrà momentaneamente scollegato dalla rete Wi-Fi durante il collegamento a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Il dispositivo Android TV verrà scollegato temporaneamente dalla rete Wi-Fi mentre è connesso a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Il telefono verrà momentaneamente scollegato dalla rete Wi-Fi durante il collegamento a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Il dispositivo verrà scollegato temporaneamente dalla rete Wi-Fi mentre è connesso a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Impossibile connettersi alla rete <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tocca per cambiare le impostazioni sulla privacy e riprova"</string> diff --git a/service/ServiceWifiResources/res/values-iw/strings.xml b/service/ServiceWifiResources/res/values-iw/strings.xml index e1291128a9..3bd7d33c0f 100644 --- a/service/ServiceWifiResources/res/values-iw/strings.xml +++ b/service/ServiceWifiResources/res/values-iw/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"אל:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"יש להקליד את קוד האימות הנדרש:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"קוד אימות:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"הטאבלט יתנתק מרשת ה-Wi-Fi באופן זמני כשהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"מכשיר ה-Android TV יתנתק מרשת ה-Wi-Fi באופן זמני כשהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"הטלפון יתנתק מרשת ה-Wi-Fi באופן זמני כשהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"המכשיר יתנתק מרשת ה-Wi-Fi באופן זמני כשהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"אישור"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"לא ניתן להתחבר אל <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"יש להקיש כדי לשנות את הגדרות הפרטיות ולנסות שוב"</string> diff --git a/service/ServiceWifiResources/res/values-ja/strings.xml b/service/ServiceWifiResources/res/values-ja/strings.xml index ccc60f380e..6c31f68c3d 100644 --- a/service/ServiceWifiResources/res/values-ja/strings.xml +++ b/service/ServiceWifiResources/res/values-ja/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"受信側:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"必要なPINを入力してください:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"タブレットが<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に接続されている間は一時的にWi-Fi接続が切断されます"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV デバイスが <xliff:g id="DEVICE_NAME">%1$s</xliff:g> に接続されている間は一時的に Wi-Fi 接続が解除されます"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"モバイル デバイスが<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に接続されている間は一時的にWi-Fi接続が解除されます。"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"デバイスが <xliff:g id="DEVICE_NAME">%1$s</xliff:g> に接続されている間は一時的に Wi-Fi 接続が解除されます"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> に接続できません"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"タップしてプライバシー設定を変更し、もう一度お試しください"</string> diff --git a/service/ServiceWifiResources/res/values-ka/strings.xml b/service/ServiceWifiResources/res/values-ka/strings.xml index 4528330297..0ae523bc61 100644 --- a/service/ServiceWifiResources/res/values-ka/strings.xml +++ b/service/ServiceWifiResources/res/values-ka/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"მიმღები:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"შეიყვანეთ საჭირო PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"პინ-კოდი:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ტაბლეტი დროებით გაითიშება Wi-Fi-დან, სანამ მიერთებულია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ზე"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"თქვენი Android TV მოწყობილობა დროებით გაითიშება Wi-Fi-დან, სანამ ის <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-თან იქნება დაკავშირებული"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ტელეფონი დროებით გაითიშება Wi-Fi-დან, სანამ მიერთებულია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ზე"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"თქვენი მოწყობილობა დროებით გაითიშება Wi-Fi-დან, სანამ ის <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-თან იქნება დაკავშირებული"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>-თან დაკავშირება ვერ ხერხდება"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"შეეხეთ კონფიდენციალურობის პარამეტრების შესაცვლელად და ცადეთ ხელახლა"</string> diff --git a/service/ServiceWifiResources/res/values-kk/strings.xml b/service/ServiceWifiResources/res/values-kk/strings.xml index 003869d405..33fcbeb648 100644 --- a/service/ServiceWifiResources/res/values-kk/strings.xml +++ b/service/ServiceWifiResources/res/values-kk/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Кімге:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Өтінілген PIN кодты теру:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Планшет <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысына қосылғанша Wi-Fi байланысынан уақытша ажыратылады"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысына қосулы тұрғанда, Android TV құрылғысы Wi-Fi желісінен уақытша ажырайды."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысына жалғанып тұрғанда телефон уақытша Wi-Fi байланысынан ажыратылады"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысына қосулы тұрғанда, құрылғыңыз Wi-Fi желісінен уақытша ажырайды."</string> <string name="dlg_ok" msgid="254496739491689405">"Жарайды"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> құрылғысына қосылмайды."</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Құпиялық параметрін өзгерту үшін түртіп, әрекетті қайталаңыз."</string> diff --git a/service/ServiceWifiResources/res/values-km/strings.xml b/service/ServiceWifiResources/res/values-km/strings.xml index 318c11bf5c..6a63936625 100644 --- a/service/ServiceWifiResources/res/values-km/strings.xml +++ b/service/ServiceWifiResources/res/values-km/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ទៅ៖"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"បញ្ចូលកូដ PIN ដែលទាមទារ៖"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"កូដ PIN ៖"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"កុំព្យូទ័របន្ទះនឹងផ្ដាច់ជាបណ្ដោះអាសន្នពីវ៉ាយហ្វាយ ខណៈដែលវាភ្ជាប់ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"ឧបករណ៍ Android TV របស់អ្នកនឹងផ្ដាច់ពី Wi-Fi ជាបណ្តោះអាសន្ន នៅពេលឧបករណ៍នេះភ្ជាប់ជាមួយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ទូរស័ព្ទនឹងផ្ដាច់ពីវ៉ាយហ្វាយខណៈដែលវាត្រូវបានតភ្ជាប់ទៅ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"ឧបករណ៍របស់អ្នកនឹងផ្ដាច់ពី Wi-Fi ជាបណ្ដោះអាសន្ន នៅពេលឧបករណ៍នេះភ្ជាប់ជាមួយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"យល់ព្រម"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"មិនអាចភ្ជាប់ជាមួយ <xliff:g id="SSID">%1$s</xliff:g> បានទេ"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"ចុច ដើម្បីប្ដូរការកំណត់ឯកជនភាព រួចព្យាយាមម្ដងទៀត"</string> diff --git a/service/ServiceWifiResources/res/values-kn/strings.xml b/service/ServiceWifiResources/res/values-kn/strings.xml index fba1a5d9bd..5bc762e2e2 100644 --- a/service/ServiceWifiResources/res/values-kn/strings.xml +++ b/service/ServiceWifiResources/res/values-kn/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ಗೆ:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"ಅಗತ್ಯವಿರುವ ಪಿನ್ ಟೈಪ್ ಮಾಡಿ:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"ಪಿನ್:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ಟ್ಯಾಬ್ಲೆಟ್ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಾಗ ಅದನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ವೈ-ಫೈ ನಿಂದ ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತದೆ"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"ನಿಮ್ಮ Android TV ಸಾಧನವು <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಾಗ, ವೈ-ಫೈ ನಿಂದ ತಾತ್ಕಾಲಿಕವಾಗಿ ಸಂಪರ್ಕ ಕಡಿದುಕೊಳ್ಳುತ್ತದೆ"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ಫೋನ್ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಾಗ ವೈ-ಫೈ ನಿಂದ ಅದು ತಾತ್ಕಾಲಿಕವಾಗಿ ಸಂಪರ್ಕ ಕಡಿತಗೊಳ್ಳುತ್ತದೆ"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"ನಿಮ್ಮ ಸಾಧನವು <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಗೆ ಕನೆಕ್ಟ್ ಆಗಿರುವಾಗ, ವೈ-ಫೈನಿಂದ ಅದು ತಾತ್ಕಾಲಿಕವಾಗಿ ಡಿಸ್ಕನೆಕ್ಟ್ ಆಗುತ್ತದೆ"</string> <string name="dlg_ok" msgid="254496739491689405">"ಸರಿ"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"ಗೌಪ್ಯತೆ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಮರುಪ್ರಯತ್ನಿಸಿ"</string> diff --git a/service/ServiceWifiResources/res/values-ko/strings.xml b/service/ServiceWifiResources/res/values-ko/strings.xml index 747167ee0a..e77fb11b13 100644 --- a/service/ServiceWifiResources/res/values-ko/strings.xml +++ b/service/ServiceWifiResources/res/values-ko/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"수신:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"필수 PIN 입력:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 일시적으로 태블릿의 Wi-Fi 연결이 해제됩니다."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 Android TV 기기의 Wi-Fi 연결이 일시적으로 해제됩니다."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 일시적으로 휴대전화의 Wi-Fi 연결이 해제됩니다."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 기기의 Wi-Fi 연결이 일시적으로 해제됩니다"</string> <string name="dlg_ok" msgid="254496739491689405">"확인"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>에 연결할 수 없습니다."</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"탭하여 개인정보 보호 설정을 변경하고 다시 시도하세요."</string> diff --git a/service/ServiceWifiResources/res/values-ky/strings.xml b/service/ServiceWifiResources/res/values-ky/strings.xml index f574c1ab46..1dac1db9f7 100644 --- a/service/ServiceWifiResources/res/values-ky/strings.xml +++ b/service/ServiceWifiResources/res/values-ky/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Алуучу:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Талап кылынган PIN\'ди териңиз:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Планшет <xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен байланышып турганда, Wi-Fi\'дан убактылуу ажыратылат"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүнө туташып турганда убактылуу Wi-Fi\'дан ажыратылат"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Телефон <xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен байланышып турганда, Wi-Fi\'дан убактылуу ажыратылат"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Түзмөгүңүз <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүнө туташып турганда убактылуу Wi-Fi\'дан ажыратылат"</string> <string name="dlg_ok" msgid="254496739491689405">"Жарайт"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> менен туташпай жатат"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Купуялык параметрлерин өзгөртүү үчүн таптап, кайталап көрүңүз"</string> diff --git a/service/ServiceWifiResources/res/values-lo/strings.xml b/service/ServiceWifiResources/res/values-lo/strings.xml index f362fa7e91..4d99e108cd 100644 --- a/service/ServiceWifiResources/res/values-lo/strings.xml +++ b/service/ServiceWifiResources/res/values-lo/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ຈາກ:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"ພິມລະຫັດ PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ແທັບເລັດຈະຖືກຕັດການເຊື່ອມຕໍ່ຈາກ Wi-Fi ເປັນການຊົ່ວຄາວ ໃນຂະນະທີ່ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຢູ່."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"ອຸປະກອນ Android TV ຂອງທ່ານຈະຕັດການເຊື່ອມຕໍ່ຈາກ Wi-Fi ເປັນການຊົ່ວຄາວໃນລະຫວ່າງທີ່ມັນເຊື່ອມຕໍ່ຫາ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ໂທລະສັບຈະຖືກຢຸດການເຊື່ອມຕໍ່ຊົ່ວຄາວຈາກ Wi-Fi ໃນຂະນະທີ່ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"ອຸປະກອນຂອງທ່ານຈະຕັດການເຊື່ອມຕໍ່ຈາກ Wi-Fi ເປັນການຊົ່ວຄາວໃນລະຫວ່າງທີ່ມັນເຊື່ອມຕໍ່ຫາ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"ຕົກລົງ"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"ບໍ່ສາມາດເຊື່ອມຕໍ່ຫາ <xliff:g id="SSID">%1$s</xliff:g> ໄດ້"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"ແຕະເພື່ອປ່ຽນການຕັ້ງຄ່າຄວາມເປັນສ່ວນຕົວແລ້ວລອງໃໝ່"</string> diff --git a/service/ServiceWifiResources/res/values-lt/strings.xml b/service/ServiceWifiResources/res/values-lt/strings.xml index 8580219070..e496179c51 100644 --- a/service/ServiceWifiResources/res/values-lt/strings.xml +++ b/service/ServiceWifiResources/res/values-lt/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Skirta:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Įveskite reikiamą PIN kodą:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN kodas:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Planšetinis kompiuteris bus laikinai atjungtas nuo „Wi-Fi“, kol jis prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"„Android TV“ įrenginys bus laikinai atjungtas nuo „Wi-Fi“, kol bus prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefonas bus laikinai atjungtas nuo „Wi-Fi“, kol bus prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Įrenginys bus laikinai atjungtas nuo „Wi-Fi“, kol bus prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string> <string name="dlg_ok" msgid="254496739491689405">"Gerai"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Nepavyksta prisijungti prie „<xliff:g id="SSID">%1$s</xliff:g>“"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Palieskite, kad pakeistumėte privatumo nustatymus, ir bandykite dar kartą"</string> diff --git a/service/ServiceWifiResources/res/values-lv/strings.xml b/service/ServiceWifiResources/res/values-lv/strings.xml index 68da3783ed..6523fd3bdc 100644 --- a/service/ServiceWifiResources/res/values-lv/strings.xml +++ b/service/ServiceWifiResources/res/values-lv/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kam:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Ierakstiet pieprasīto PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Planšetdators tiks īslaicīgi atvienots no Wi-Fi tīkla, kamēr būs izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV ierīce tiks īslaicīgi atvienota no Wi-Fi tīkla, kamēr ir izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Tālrunis tiks īslaicīgi atvienots no Wi-Fi tīkla, kamēr būs izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Jūsu ierīce tiks īslaicīgi atvienota no Wi-Fi tīkla, kamēr ir izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> <string name="dlg_ok" msgid="254496739491689405">"Labi"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Nevar izveidot savienojumu ar: <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Pieskarieties, lai mainītu konfidencialitātes iestatījumus un mēģinātu vēlreiz"</string> diff --git a/service/ServiceWifiResources/res/values-mk/strings.xml b/service/ServiceWifiResources/res/values-mk/strings.xml index 513b33d6a4..f8db829ddb 100644 --- a/service/ServiceWifiResources/res/values-mk/strings.xml +++ b/service/ServiceWifiResources/res/values-mk/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"До:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Внеси го бараниот PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Таблетот привремено ќе се исклучи од Wi-Fi, додека да се приклучи на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Привремено ќе се прекине врската на вашиот уред Android TV со Wi-Fi додека е поврзан со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Телефонот привремено ќе се исклучи од Wi-Fi додека е приклучен на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Ќе се прекине врската на вашиот уред со Wi-Fi привремено додека е поврзан со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Во ред"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Не може да се поврзе на „<xliff:g id="SSID">%1$s</xliff:g>“"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Допрете за да ги промените поставките за приватност и обидете се повторно"</string> diff --git a/service/ServiceWifiResources/res/values-ml/strings.xml b/service/ServiceWifiResources/res/values-ml/strings.xml index ca56e784b0..18f1ada5b2 100644 --- a/service/ServiceWifiResources/res/values-ml/strings.xml +++ b/service/ServiceWifiResources/res/values-ml/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ടു:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"ആവശ്യമായ പിൻ ടൈപ്പുചെയ്യുക:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"പിൻ:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ടാബ്ലെറ്റ് <xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിൽ കണക്റ്റുചെയ്തിരിക്കുമ്പോൾ അത് താൽക്കാലികമായി Wi-Fi-യിൽ നിന്നും വിച്ഛേദിക്കപ്പെടും."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"നിങ്ങളുടെ Android TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ഉപകരണവുമായി കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ അത് താൽക്കാലികമായി വൈഫൈയിൽ നിന്ന് വിച്ഛേദിക്കും"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തിരിക്കുമ്പോൾ ഫോൺ Wi-Fi-യിൽ നിന്ന് താൽക്കാലികമായി വിച്ഛേദിക്കും"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"നിങ്ങളുടെ ഉപകരണം <xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതുമായി കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ, അത് വൈഫൈയിൽ നിന്ന് താൽക്കാലികമായി വിച്ഛേദിക്കും"</string> <string name="dlg_ok" msgid="254496739491689405">"ശരി"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>-ലേക്ക് കണക്റ്റ് ചെയ്യാനാവുന്നില്ല"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"സ്വകാര്യതാ ക്രമീകരണം മാറ്റാൻ ടാപ്പ് ചെയ്യുക, വീണ്ടും ശ്രമിക്കുക"</string> diff --git a/service/ServiceWifiResources/res/values-mn/strings.xml b/service/ServiceWifiResources/res/values-mn/strings.xml index 69b1376e34..9ab92aca8f 100644 --- a/service/ServiceWifiResources/res/values-mn/strings.xml +++ b/service/ServiceWifiResources/res/values-mn/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Хэнд:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Шаардлагатай ПИН-г бичнэ үү:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"ПИН:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Таблет <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тэй холбогдох үедээ түр зуур Wi-Fi-с салах болно."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Таны Android TV төхөөрөмж <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-д холбогдсон үед Wi-Fi-с түр хугацаанд сална"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Утас <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай холбогдох үедээ түр зуур Wi-Fi-с салах болно."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Таны төхөөрөмж <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-д холбогдсон үедээ Wi-Fi-с түр сална"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>-д холбогдож чадсангүй"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Нууцлалын тохиргоог өөрчлөхийн тулд товшоод, дахин оролдоно уу"</string> diff --git a/service/ServiceWifiResources/res/values-mr/strings.xml b/service/ServiceWifiResources/res/values-mr/strings.xml index 57fd585057..5cdd82f0d2 100644 --- a/service/ServiceWifiResources/res/values-mr/strings.xml +++ b/service/ServiceWifiResources/res/values-mr/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"प्रति:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"आवश्यक पिन टाइप करा:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"पिन:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"टॅबलेट <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ला कनेक्ट केलेले असताना तात्पुरते वाय-फाय वरून डिस्कनेक्ट होईल"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>शी तुमचे Android TV डिव्हाइस कनेक्ट केलेले असताना ते वाय-फाय वरून तात्पुरते डिस्कनेक्ट केले जाईल"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> वर फोन कनेक्ट केलेला असताना तो वाय-फाय वरून तात्पुरता डिस्कनेक्ट केला जाईल"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"तुमचे डिव्हाइस <xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी कनेक्ट केलेले असताना वाय-फायवरून तात्पुरते डिस्कनेक्ट होईल"</string> <string name="dlg_ok" msgid="254496739491689405">"ठीक"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> शी कनेक्ट करता आले नाही"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"गोपनीयता सेटिंग्ज बदलण्यासाठी टॅप करा आणि पुन्हा प्रयत्न करा"</string> diff --git a/service/ServiceWifiResources/res/values-ms/strings.xml b/service/ServiceWifiResources/res/values-ms/strings.xml index bbb0c84764..66e5b8b5c6 100644 --- a/service/ServiceWifiResources/res/values-ms/strings.xml +++ b/service/ServiceWifiResources/res/values-ms/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kepada:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Taipkan PIN yang diperlukan:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Sambungan tablet ke Wi-Fi akan diputuskan buat sementara waktu semasa tablet bersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Peranti Android TV anda akan diputuskan sambungan daripada Wi-Fi untuk sementara waktu semasa peranti ini disambungkan ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Sambungan telefon ke Wi-Fi akan diputuskan buat sementara waktu semasa telefon bersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Peranti anda akan diputuskan sambungan daripada Wi-Fi untuk sementara waktu semasa peranti ini disambungkan kepada <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Tidak dapat menyambung ke <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Ketik untuk menukar tetapan privasi, kemudian cuba semula"</string> diff --git a/service/ServiceWifiResources/res/values-my/strings.xml b/service/ServiceWifiResources/res/values-my/strings.xml index 6bba39c317..ea57a2a317 100644 --- a/service/ServiceWifiResources/res/values-my/strings.xml +++ b/service/ServiceWifiResources/res/values-my/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"သို့:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"လိုအပ်သော ပင် နံပါတ် ရိုက်ရန်:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"ပင် နံပါတ်:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> နှင့် ဆက်သွယ်ထားစဉ် တက်ဘလက်ဟာ Wi-Fi နှင့် ဆက်သွယ်မှု ရပ်ဆိုင်းထားမှာ ဖြစ်ပါတယ်"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"သင်၏ Android TV စက်ပစ္စည်းသည် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည့်အခါ Wi-Fi မှနေ၍ ယာယီ ချိတ်ဆက်မှုဖြုတ်သွားပါမည်။"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို ဆက်သွယ်ထားစဉ် ဖုန်းအား ဝိုင်ဖိုင်မှ ဆက်သွယ်မှု ရပ်ဆိုင်းထားပါမည်"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"သင့်စက်သည် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားစဉ် Wi-Fi နှင့် ချိတ်ဆက်မှုကို ယာယီဖြုတ်ထားမည်"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> နှင့် ချိတ်ဆက်၍မရပါ။"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"ကိုယ်ရေးလုံခြုံမှုဆက်တင်ကို ပြောင်းရန် တို့ပြီးနောက် ပြန်စမ်းကြည့်ပါ"</string> diff --git a/service/ServiceWifiResources/res/values-nb/strings.xml b/service/ServiceWifiResources/res/values-nb/strings.xml index 48f781463b..f97c308e43 100644 --- a/service/ServiceWifiResources/res/values-nb/strings.xml +++ b/service/ServiceWifiResources/res/values-nb/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Til:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Skriv inn påkrevd PIN-kode:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Nettbrettet frakobles Wifi midlertidig mens den er tilkoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV-enheten din blir midlertidig koblet fra wifi mens den er koblet til <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefonen frakobles Wifi midlertidig mens den er tilkoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Enheten din blir midlertidig koblet fra wifi mens den er koblet til <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Kan ikke koble til <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Trykk for å endre personverninnstillingene og prøve på nytt"</string> diff --git a/service/ServiceWifiResources/res/values-ne/strings.xml b/service/ServiceWifiResources/res/values-ne/strings.xml index 6d4f3b68a8..e4a33a2f0f 100644 --- a/service/ServiceWifiResources/res/values-ne/strings.xml +++ b/service/ServiceWifiResources/res/values-ne/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"प्रापक:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"आवश्यक PIN टाइप गर्नुहोस्:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"यो <xliff:g id="DEVICE_NAME">%1$s</xliff:g>सँग जोडिएको बेला ट्याब्लेट अस्थायी रूपमा वाइ-फाइबाट विच्छेद गरिने छ।"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"तपाईंको Android टिभी यन्त्र <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा कनेक्ट भएको बेला यो केही समयका लागि Wi-Fi बाट विच्छेद हुने छ।"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"जब यो <xliff:g id="DEVICE_NAME">%1$s</xliff:g> सँग जडित हुन्छ, फोन अस्थायी रूपमा वाइ-फाइबाट विच्छेद हुने छ"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"तपाईंको डिभाइस <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा कनेक्ट गरिएको बेलामा यो केही बेर Wi-Fi बाट डिस्कनेक्ट हुने छ"</string> <string name="dlg_ok" msgid="254496739491689405">"ठिक छ"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> मा जडान गर्न सकिएन"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"गोपनीयता सेटिङ परिवर्तन गर्न ट्याप गरेर फेरि प्रयास गर्नुहोस्"</string> diff --git a/service/ServiceWifiResources/res/values-nl/strings.xml b/service/ServiceWifiResources/res/values-nl/strings.xml index 97424752f9..4c6e2d7da9 100644 --- a/service/ServiceWifiResources/res/values-nl/strings.xml +++ b/service/ServiceWifiResources/res/values-nl/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Naar:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Voer de gewenste pincode in:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"Pincode"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"De verbinding met het wifi-netwerk wordt tijdelijk uitgezet terwijl de telefoon is verbonden met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"De verbinding met het wifi-netwerk wordt tijdelijk uitgezet terwijl het Android TV-apparaat is verbonden met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"De verbinding met het wifi-netwerk wordt tijdelijk uitgezet terwijl de telefoon verbonden is met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Je apparaat verbreekt tijdelijk de verbinding met wifi terwijl het verbonden is met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Kan niet verbinden met <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tik om de privacyinstellingen aan te passen en probeer het opnieuw"</string> diff --git a/service/ServiceWifiResources/res/values-or/strings.xml b/service/ServiceWifiResources/res/values-or/strings.xml index 71fb148738..6abb1e6c34 100644 --- a/service/ServiceWifiResources/res/values-or/strings.xml +++ b/service/ServiceWifiResources/res/values-or/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ପ୍ରାପ୍ତେଷୁ:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"ଆବଶ୍ୟକ PIN ଟାଇପ୍ କରନ୍ତୁ:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୁକ୍ତ ହୋଇଥିବାବେଳେ, ୱାଇ-ଫାଇଠାରୁ ଟାବଲେଟ୍ଟି ଅସ୍ଥାୟୀ ଭାବେ ବିଚ୍ଛିନ୍ନ ହେବ"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"ଆପଣଙ୍କର Android TV ଡିଭାଇସ୍ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୋଗ ହେଉଥିବା ସମୟରେ ୱାଇ-ଫାଇରୁ ଅସ୍ଥାୟୀ ଭାବେ ବିଚ୍ଛିନ୍ନ ହେବ"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୋଗ ଥିବାବେଳେ ଫୋନ୍ଟି ୱାଇ-ଫାଇରୁ ଅସ୍ଥାୟୀ ଭାବରେ ବିଚ୍ଛିନ୍ନ ହେବ"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"ଆପଣଙ୍କ ଡିଭାଇସ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ କନେକ୍ଟ ଥିବା ସମୟରେ ଏହା ଅସ୍ଥାୟୀ ଭାବେ ୱାଇ-ଫାଇରୁ ଡିସକନେକ୍ଟ ହୋଇଯିବ"</string> <string name="dlg_ok" msgid="254496739491689405">"ଠିକ ଅଛି"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> ସହିତ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"ଗୋପନୀୟତା ସେଟିଂସ୍ ବଦଳେଇବାକୁ ଟାପ୍ କରନ୍ତୁ ଏବଂ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string> diff --git a/service/ServiceWifiResources/res/values-pa/strings.xml b/service/ServiceWifiResources/res/values-pa/strings.xml index d01fe9c170..2589be4766 100644 --- a/service/ServiceWifiResources/res/values-pa/strings.xml +++ b/service/ServiceWifiResources/res/values-pa/strings.xml @@ -25,9 +25,9 @@ <string name="wifi_available_action_connect" msgid="5636634933476946222">"ਕਨੈਕਟ ਕਰੋ"</string> <string name="wifi_available_action_all_networks" msgid="8491109932336522211">"ਸਾਰੇ ਨੈੱਟਵਰਕ"</string> <string name="notification_channel_network_status" msgid="1631786866932924838">"ਨੈੱਟਵਰਕ ਅਵਸਥਾ"</string> - <string name="notification_channel_network_alerts" msgid="1391603215241200880">"ਨੈੱਟਵਰਕ ਸੁਚੇਤਨਾਵਾਂ"</string> + <string name="notification_channel_network_alerts" msgid="1391603215241200880">"ਨੈੱਟਵਰਕ ਅਲਰਟ"</string> <string name="notification_channel_network_available" msgid="8454366142428864948">"ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਹੈ"</string> - <string name="notification_channel_apm_alerts" msgid="6775293475896473489">"APM ਸੁਚੇਤਨਾਵਾਂ"</string> + <string name="notification_channel_apm_alerts" msgid="6775293475896473489">"APM ਅਲਰਟ"</string> <string name="wifi_suggestion_title" msgid="2564179935989099139">"ਕੀ ਸੁਝਾਏ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਵਰਤਣੇ ਹਨ?"</string> <string name="wifi_suggestion_content" msgid="6985149577828091835">"<xliff:g id="NAME">%s</xliff:g> ਦੇ ਸੁਝਾਏ ਨੈੱਟਵਰਕ। ਸ਼ਾਇਦ ਡੀਵਾਈਸ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਹੋਵੇ।"</string> <string name="wifi_suggestion_action_allow_app" msgid="7757859972144671588">"ਵਰਤਣ ਦਿਓ"</string> @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ਵੱਲ:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"ਲੋੜੀਂਦਾ ਪਿੰਨ ਟਾਈਪ ਕਰੋ:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"ਪਿੰਨ:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ਟੈਬਲੈੱਟ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਵੇਗਾ"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"ਤੁਹਾਡਾ Android TV ਡੀਵਾਈਸ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ \'ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਵੇਗਾ"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ਫ਼ੋਨ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗਾ"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋਣ \'ਤੇ, ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਕੁਝ ਸਮੇਂ ਲਈ ਵਾਈ-ਫਾਈ ਤੋਂ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਵੇਗਾ"</string> <string name="dlg_ok" msgid="254496739491689405">"ਠੀਕ ਹੈ"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"ਪਰਦੇਦਾਰੀ ਸੈਟਿੰਗਾਂ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰਕੇ ਮੁੜ-ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> diff --git a/service/ServiceWifiResources/res/values-pl/strings.xml b/service/ServiceWifiResources/res/values-pl/strings.xml index 2f2b3b8771..e3afb51815 100644 --- a/service/ServiceWifiResources/res/values-pl/strings.xml +++ b/service/ServiceWifiResources/res/values-pl/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Do:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Wpisz wymagany kod PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"Kod PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tablet zostanie tymczasowo odłączony od Wi-Fi"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Urządzenie z Androidem TV zostanie odłączone od sieci Wi-Fi na czas połączenia z urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> telefon zostanie tymczasowo odłączony od Wi-Fi"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Gdy urządzenie zostanie podłączone do urządzenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, tymczasowo rozłączy się z Wi-Fi"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Nie można połączyć się z siecią <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Kliknij, by zmienić ustawienia prywatności, i spróbuj jeszcze raz"</string> diff --git a/service/ServiceWifiResources/res/values-pt-rBR/strings.xml b/service/ServiceWifiResources/res/values-pt-rBR/strings.xml index 71aa053e88..2f2060c0e2 100644 --- a/service/ServiceWifiResources/res/values-pt-rBR/strings.xml +++ b/service/ServiceWifiResources/res/values-pt-rBR/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Digite o PIN obrigatório:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"O tablet desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"O dispositivo Android TV desconectará o Wi-Fi temporariamente enquanto estiver conectado ao <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"O telefone desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"O dispositivo vai desconectar o Wi-Fi temporariamente enquanto estiver conectado ao <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Não foi possível se conectar à rede <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Toque para mudar as configurações de privacidade e tentar novamente"</string> diff --git a/service/ServiceWifiResources/res/values-pt-rPT/strings.xml b/service/ServiceWifiResources/res/values-pt-rPT/strings.xml index 3804873187..e3b51b2959 100644 --- a/service/ServiceWifiResources/res/values-pt-rPT/strings.xml +++ b/service/ServiceWifiResources/res/values-pt-rPT/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Introduza o PIN solicitado:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"O tablet sera temporariamente desligado da rede Wi-Fi enquanto estiver ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"O seu dispositivo Android TV irá desligar-se temporariamente da rede Wi-Fi enquanto está ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"O telemóvel irá desligar-se temporariamente da rede Wi-Fi enquanto está ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"O seu dispositivo vai desligar-se temporariamente da rede Wi-Fi enquanto está ligado ao dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Não é possível ligar a <xliff:g id="SSID">%1$s</xliff:g>."</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Toque para alterar as definições de privacidade e tente novamente."</string> diff --git a/service/ServiceWifiResources/res/values-pt/strings.xml b/service/ServiceWifiResources/res/values-pt/strings.xml index 71aa053e88..2f2060c0e2 100644 --- a/service/ServiceWifiResources/res/values-pt/strings.xml +++ b/service/ServiceWifiResources/res/values-pt/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Digite o PIN obrigatório:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"O tablet desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"O dispositivo Android TV desconectará o Wi-Fi temporariamente enquanto estiver conectado ao <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"O telefone desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"O dispositivo vai desconectar o Wi-Fi temporariamente enquanto estiver conectado ao <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Não foi possível se conectar à rede <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Toque para mudar as configurações de privacidade e tentar novamente"</string> diff --git a/service/ServiceWifiResources/res/values-ro/strings.xml b/service/ServiceWifiResources/res/values-ro/strings.xml index c150310f6e..40271f5458 100644 --- a/service/ServiceWifiResources/res/values-ro/strings.xml +++ b/service/ServiceWifiResources/res/values-ro/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Către:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Introdu codul PIN necesar:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"Cod PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tableta se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectată la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Dispozitivul Android TV se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefonul se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Dispozitivul se va deconecta temporar de la Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Nu se poate conecta la <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Atinge pentru a modifica setările de confidențialitate și a încerca din nou"</string> diff --git a/service/ServiceWifiResources/res/values-ru/strings.xml b/service/ServiceWifiResources/res/values-ru/strings.xml index d4629ef513..a47cd0e788 100644 --- a/service/ServiceWifiResources/res/values-ru/strings.xml +++ b/service/ServiceWifiResources/res/values-ru/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Кому:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Введите PIN-код:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-код:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> планшетный ПК будет временно отключаться от сети Wi-Fi"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> устройство Android TV будет временно отключаться от сети Wi-Fi."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон будет временно отключаться от сети Wi-Fi"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"На время подключения к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ваше устройство отключится от сети Wi-Fi."</string> <string name="dlg_ok" msgid="254496739491689405">"ОК"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Не удалось подключиться к устройству \"<xliff:g id="SSID">%1$s</xliff:g>\""</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Нажмите, чтобы изменить настройки конфиденциальности и повторить попытку."</string> diff --git a/service/ServiceWifiResources/res/values-si/strings.xml b/service/ServiceWifiResources/res/values-si/strings.xml index 2e65f866bb..d9c7cb4bd2 100644 --- a/service/ServiceWifiResources/res/values-si/strings.xml +++ b/service/ServiceWifiResources/res/values-si/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"වෙත:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"අවශ්ය PIN එක ටයිප් කරන්න:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ටැබ්ලටය <xliff:g id="DEVICE_NAME">%1$s</xliff:g> වෙත සම්බන්ධ වන අතරතුර එය Wi-Fi වලින් තාවකාලිකව විසන්ධි කෙරේ."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"ඔබගේ Android TV උපාංගය <xliff:g id="DEVICE_NAME">%1$s</xliff:g> වෙත සම්බන්ධ වී පවතින විට Wi-Fi වෙතින් එය තාවකාලිකව විසන්ධි වනු ඇත"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"දුරකථනය <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ට සම්බන්ධ වී පවතින විට Wi-Fi වලින් එය තාවකාලිකව විසන්ධි වෙයි."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> වෙත සම්බන්ධ වී ඇති අතරේ ඔබේ උපාංගය Wi-Fi වෙතින් තාවකාලිකව විසන්ධි වනු ඇත"</string> <string name="dlg_ok" msgid="254496739491689405">"හරි"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> වෙත සම්බන්ධ විය නොහැකිය"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"රහස්යතා සැකසීම් වෙනස් කිරීමට තට්ටු කර යළි උත්සාහ කරන්න"</string> diff --git a/service/ServiceWifiResources/res/values-sk/strings.xml b/service/ServiceWifiResources/res/values-sk/strings.xml index a1cea844a3..397dc9f33c 100644 --- a/service/ServiceWifiResources/res/values-sk/strings.xml +++ b/service/ServiceWifiResources/res/values-sk/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Komu:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Zadajte požadovaný kód PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablet bude počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> od siete Wi‑Fi dočasne odpojený."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Zariadenie Android TV sa počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasne odpojí od siete Wi‑Fi"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefón bude počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> od siete Wi‑Fi dočasne odpojený."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> sa vaše zariadenie dočasne odpojí od siete Wi‑Fi"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"K sieti <xliff:g id="SSID">%1$s</xliff:g> sa nedá pripojiť"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Klepnutím zmeňte nastavenia ochrany súkromia a skúste to znova"</string> diff --git a/service/ServiceWifiResources/res/values-sl/strings.xml b/service/ServiceWifiResources/res/values-sl/strings.xml index ab99da0faa..e05b77dae6 100644 --- a/service/ServiceWifiResources/res/values-sl/strings.xml +++ b/service/ServiceWifiResources/res/values-sl/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Za:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Vnesite zahtevano kodo PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablični računalnik bo začasno prekinil povezavo z Wi-Fi-jem, medtem ko je povezan z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Naprava Android TV bo začasno prekinila povezavo z omrežjem Wi-Fi, medtem ko je povezana z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefon bo začasno prekinil povezavo z Wi-Fi-jem, ko je povezan z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Naprava bo začasno prekinila povezavo z omrežjem Wi-Fi, medtem ko je povezana z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"V redu"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Povezava z omrežjem <xliff:g id="SSID">%1$s</xliff:g> ni mogoča"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Dotaknite se za spremembo nastavitev zasebnosti in poskusite znova"</string> diff --git a/service/ServiceWifiResources/res/values-sq/strings.xml b/service/ServiceWifiResources/res/values-sq/strings.xml index 92fe6fa9bc..a71a892754 100644 --- a/service/ServiceWifiResources/res/values-sq/strings.xml +++ b/service/ServiceWifiResources/res/values-sq/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Për:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Shkruaj PIN-in e kërkuar:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-i:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tableti do të shkëputet përkohësisht nga Wi-Fi gjatë kohës së lidhjes me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Pajisja jote Android TV do të shkëputet përkohësisht nga Wi-Fi ndërkohë që është e lidhur me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefoni do të shkëputet përkohësisht nga Wi-Fi gjatë kohës së lidhjes me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Pajisja jote do të shkëputet përkohësisht nga Wi-Fi ndërkohë që është e lidhur me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Në rregull"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Nuk mund të lidhet me <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Trokit për të ndryshuar cilësimet e privatësisë dhe provo përsëri"</string> diff --git a/service/ServiceWifiResources/res/values-sr/strings.xml b/service/ServiceWifiResources/res/values-sr/strings.xml index 4b4491e596..ae3eff432e 100644 --- a/service/ServiceWifiResources/res/values-sr/strings.xml +++ b/service/ServiceWifiResources/res/values-sr/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Коме:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Унесите потребни PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Таблет ће привремено прекинути везу са WiFi-ем док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV уређај ће привремено прекинути везу са WiFi мрежом док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Телефон ће привремено прекинути везу са WiFi-ем док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Уређај ће привремено прекинути везу са WiFi мрежом док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Потврди"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Повезивање на мрежу <xliff:g id="SSID">%1$s</xliff:g> није успело"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Додирните да бисте променили подешавања приватности и пробали поново"</string> diff --git a/service/ServiceWifiResources/res/values-sv/strings.xml b/service/ServiceWifiResources/res/values-sv/strings.xml index 07f76a1d3e..d02a82d58b 100644 --- a/service/ServiceWifiResources/res/values-sv/strings.xml +++ b/service/ServiceWifiResources/res/values-sv/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Till:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Ange den obligatoriska PIN-koden:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-kod:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Surfplattans wifi-anslutning kommer tillfälligt att avbrytas när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV-enheten kopplas tillfälligt från wifi medan den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Mobilen kommer tillfälligt att kopplas från wifi när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Enheten kopplas tillfälligt från wifi när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Det gick inte att ansluta till <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Tryck för att ändra integritetsinställningar och försök igen"</string> diff --git a/service/ServiceWifiResources/res/values-sw/strings.xml b/service/ServiceWifiResources/res/values-sw/strings.xml index 30af5eab02..b63f476ffa 100644 --- a/service/ServiceWifiResources/res/values-sw/strings.xml +++ b/service/ServiceWifiResources/res/values-sw/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kwa:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Charaza PIN inayohitajika:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Kompyuta ndogo itaukata muunganisho kwa muda kutoka kwenye Wi-Fi inapokuwa imeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Kifaa chako cha Android TV kitatenganishwa na Wi-Fi kwa muda wakati kimeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Simu itaukata muunganisho kwa muda kutoka kwenye Wi-Fi inapokuwa imeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Kifaa chako kitatenganishwa na Wi-Fi kwa muda wakati kimeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"Sawa"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Imeshindwa kuunganisha kwenye <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Gusa ili ubadilishe mipangilio ya faragha na ujaribu tena"</string> diff --git a/service/ServiceWifiResources/res/values-ta/strings.xml b/service/ServiceWifiResources/res/values-ta/strings.xml index d565756e59..005dfe55a5 100644 --- a/service/ServiceWifiResources/res/values-ta/strings.xml +++ b/service/ServiceWifiResources/res/values-ta/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"பெறுநர்:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"பின்வரும் அவசியமான பின்னை உள்ளிடவும்:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"பின்:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் டேப்லெட் இணைக்கப்படும்போது, வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"உங்கள் Android TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்துடன் இணைக்கப்பட்டிருக்கும் போது வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் மொபைல் இணைக்கப்படும்போது, வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்கப்பட்டிருக்கும்போது உங்கள் சாதனம் வைஃபை இணைப்பில் இருந்து தற்காலிகமாகத் துண்டிக்கப்படும்"</string> <string name="dlg_ok" msgid="254496739491689405">"சரி"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"தனியுரிமை அமைப்புகளை மாற்ற தட்டி மீண்டும் முயலவும்"</string> diff --git a/service/ServiceWifiResources/res/values-te/strings.xml b/service/ServiceWifiResources/res/values-te/strings.xml index 0de30c809a..ec40546f41 100644 --- a/service/ServiceWifiResources/res/values-te/strings.xml +++ b/service/ServiceWifiResources/res/values-te/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"వీరికి:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"అవసరమైన పిన్ను టైప్ చేయండి:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"పిన్:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"టాబ్లెట్ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కు కనెక్ట్ చేయబడినప్పుడు Wi-Fi నుండి తాత్కాలికంగా డిస్కనెక్ట్ చేయబడుతుంది"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"మీ Android TV పరికరం <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కి కనెక్ట్ అయి ఉన్నప్పుడు తాత్కాలికంగా Wi-Fi నుండి డిస్కనెక్ట్ అవుతుంది"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"ఫోన్ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కి కనెక్ట్ అయినప్పుడు అది Wi-Fi నుండి తాత్కాలికంగా డిస్కనెక్ట్ చేయబడుతుంది"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"మీ పరికరం <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కి కనెక్ట్ అయి ఉన్నప్పుడు తాత్కాలికంగా Wi-Fi నుండి డిస్కనెక్ట్ అవుతుంది"</string> <string name="dlg_ok" msgid="254496739491689405">"సరే"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>కు కనెక్ట్ చేయడం సాధ్యపడదు"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"మీ గోప్యతా సెట్టింగ్లను మార్చడానికి నొక్కి, మళ్లీ ట్రై చేయండి"</string> diff --git a/service/ServiceWifiResources/res/values-th/strings.xml b/service/ServiceWifiResources/res/values-th/strings.xml index 8d2ed19641..0958cc3ceb 100644 --- a/service/ServiceWifiResources/res/values-th/strings.xml +++ b/service/ServiceWifiResources/res/values-th/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"ถึง:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"พิมพ์ PIN ที่ต้องการ:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"แท็บเล็ตนี้จะยกเลิกการเชื่อมต่อกับ WiFi ชั่วคราวในขณะที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"อุปกรณ์ Android TV จะยกเลิกการเชื่อมต่อ Wi-Fi ชั่วคราวระหว่างที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"โทรศัพท์จะยกเลิกการเชื่อมต่อกับ WiFi ชั่วคราวในขณะที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"อุปกรณ์ของคุณจะยกเลิกการเชื่อมต่อ Wi-Fi ชั่วคราวระหว่างที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"ตกลง"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"เชื่อมต่อกับ <xliff:g id="SSID">%1$s</xliff:g> ไม่ได้"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"แตะเพื่อเปลี่ยนการตั้งค่าความเป็นส่วนตัวแล้วลองใหม่"</string> diff --git a/service/ServiceWifiResources/res/values-tl/strings.xml b/service/ServiceWifiResources/res/values-tl/strings.xml index 9966aec343..7b16618e41 100644 --- a/service/ServiceWifiResources/res/values-tl/strings.xml +++ b/service/ServiceWifiResources/res/values-tl/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kay:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"I-type ang kinakailangang PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Pansamantalang madidiskoneta ang tablet sa Wi-Fi habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Pansamantalang madidiskonekta sa Wi-Fi ang iyong Android TV device habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Pansamantalang madidiskoneta ang telepono sa Wi-Fi habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Pansamantalang madidiskonekta sa Wi-Fi ang iyong device habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Hindi makakonekta sa <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"I-tap para baguhin ang mga setting ng privacy at subukan ulit"</string> diff --git a/service/ServiceWifiResources/res/values-tr/strings.xml b/service/ServiceWifiResources/res/values-tr/strings.xml index 15504803de..efc4d1b7ad 100644 --- a/service/ServiceWifiResources/res/values-tr/strings.xml +++ b/service/ServiceWifiResources/res/values-tr/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Alıcı:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Gerekli PIN\'i yazın:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Tablet <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV cihazınız <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken kablosuz ağ bağlantısı geçici olarak kesilecek"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Cihazınız <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken kablosuz bağlantısı geçici olarak kesilecek"</string> <string name="dlg_ok" msgid="254496739491689405">"Tamam"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> ağına bağlanılamıyor"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Gizlilik ayarını değiştirip tekrar denemek için dokunun"</string> diff --git a/service/ServiceWifiResources/res/values-uk/strings.xml b/service/ServiceWifiResources/res/values-uk/strings.xml index 2afa400fe3..456be30cbc 100644 --- a/service/ServiceWifiResources/res/values-uk/strings.xml +++ b/service/ServiceWifiResources/res/values-uk/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Кому:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Введіть потрібний PIN-код:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN-код:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Під час з’єднання з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> планшетний ПК тимчасово від’єднається від мережі Wi-Fi"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"На час підключення до пристрою <xliff:g id="DEVICE_NAME">%1$s</xliff:g> Android TV тимчасово відключиться від мережі Wi-Fi"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Під час з’єднання з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон тимчасово від’єднається від мережі Wi-Fi"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"На час підключення до пристрою \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" ваш пристрій буде від’єднано від мережі Wi-Fi"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Не вдалося підключитися до мережі \"<xliff:g id="SSID">%1$s</xliff:g>\""</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Натисніть, щоб змінити налаштування конфіденційності й повторити спробу"</string> diff --git a/service/ServiceWifiResources/res/values-ur/strings.xml b/service/ServiceWifiResources/res/values-ur/strings.xml index 9305ac6f01..d96adbadbc 100644 --- a/service/ServiceWifiResources/res/values-ur/strings.xml +++ b/service/ServiceWifiResources/res/values-ur/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"بنام:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"مطلوبہ PIN ٹائپ کریں:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"ٹیبلیٹ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> سے مربوط ہونے پر عارضی طور پر Wi-Fi سے منقطع ہو جائے گا"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"آپ کا Android TV آلہ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> سے منسلک ہونے پر عارضی طور پر Wi-Fi سے غیر منسلک ہو جائے گا"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"فون <xliff:g id="DEVICE_NAME">%1$s</xliff:g> سے مربوط رہنے کے وقت عارضی طور پر Wi-Fi سے منقطع ہوجائے گا"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"آپ کا آلہ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> سے منسلک ہونے پر، عارضی طور پر Wi-Fi سے غیر منسلک ہو جائے گا"</string> <string name="dlg_ok" msgid="254496739491689405">"ٹھیک ہے"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> سے منسلک نہیں کر سکتے"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"رازداری کی ترتیبات تبدیل کرنے اور دوبارہ کوشش کرنے کے لیے تھپتھپائیں"</string> diff --git a/service/ServiceWifiResources/res/values-uz/strings.xml b/service/ServiceWifiResources/res/values-uz/strings.xml index fa24256ffd..ebd27bd65a 100644 --- a/service/ServiceWifiResources/res/values-uz/strings.xml +++ b/service/ServiceWifiResources/res/values-uz/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Kimga:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"So‘ralgan PIN kodni kiriting:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN kod:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Planshet <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ga ulanganligi tufayli vaqtincha Wi-Fi tarmog‘idan uzildi."</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV qurilmangiz <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulangani uchun u vaqtincha Wi-Fi tarmoqdan uzildi."</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ga ulanganligi tufayli vaqtincha Wi-Fi tarmog‘idan uzildi."</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Qurilmangiz <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulangani uchun u vaqtincha Wi-Fi tarmoqdan uzildi."</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g> bilan aloqa oʻrnatilmadi"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Maxfiylik sozlamalarini oʻzgartirish uchun bosing va qayta urining"</string> diff --git a/service/ServiceWifiResources/res/values-vi/strings.xml b/service/ServiceWifiResources/res/values-vi/strings.xml index fe43095eae..bd2e416ca5 100644 --- a/service/ServiceWifiResources/res/values-vi/strings.xml +++ b/service/ServiceWifiResources/res/values-vi/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Người nhận:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Nhập PIN bắt buộc:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"Mã PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Máy tính bảng sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi máy tính bảng được kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Thiết bị Android TV sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Điện thoại sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi điện thoại được kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Thiết bị của bạn sẽ tạm thời ngắt kết nối với Wi-Fi trong khi kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"OK"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Không thể kết nối với <xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Nhấn để thay đổi các tùy chọn cài đặt quyền riêng tư rồi thử lại"</string> diff --git a/service/ServiceWifiResources/res/values-zh-rCN/strings.xml b/service/ServiceWifiResources/res/values-zh-rCN/strings.xml index 737a627623..5a0871e7af 100644 --- a/service/ServiceWifiResources/res/values-zh-rCN/strings.xml +++ b/service/ServiceWifiResources/res/values-zh-rCN/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"收件人:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"输入所需的PIN码:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN 码:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"平板电脑连接到“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”时会暂时断开与WLAN的连接"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"当 Android TV 设备连接到 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 时,它会暂时断开 WLAN 连接"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"手机连接到<xliff:g id="DEVICE_NAME">%1$s</xliff:g>时会暂时断开与WLAN的连接。"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"当设备连接到<xliff:g id="DEVICE_NAME">%1$s</xliff:g>时,它会暂时断开 WLAN 连接"</string> <string name="dlg_ok" msgid="254496739491689405">"确定"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"无法连接到“<xliff:g id="SSID">%1$s</xliff:g>”"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"点按以更改隐私设置并重试"</string> diff --git a/service/ServiceWifiResources/res/values-zh-rHK/strings.xml b/service/ServiceWifiResources/res/values-zh-rHK/strings.xml index 00009b2f08..635311749b 100644 --- a/service/ServiceWifiResources/res/values-zh-rHK/strings.xml +++ b/service/ServiceWifiResources/res/values-zh-rHK/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"收件者:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"請輸入必要的 PIN 碼:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN 碼:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"平板電腦與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV 裝置與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間,系統將暫時中斷 Wi-Fi 連線"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"手機與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"裝置與「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」連線期間將暫時中斷 Wi-Fi 連線"</string> <string name="dlg_ok" msgid="254496739491689405">"確定"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"無法連接「<xliff:g id="SSID">%1$s</xliff:g>」"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"輕按以更改私隱設定,然後重試"</string> diff --git a/service/ServiceWifiResources/res/values-zh-rTW/strings.xml b/service/ServiceWifiResources/res/values-zh-rTW/strings.xml index 90a9b2deb9..6aed027f4c 100644 --- a/service/ServiceWifiResources/res/values-zh-rTW/strings.xml +++ b/service/ServiceWifiResources/res/values-zh-rTW/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"收件者:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"請輸入必要的 PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN 碼:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"平板電腦與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Android TV 裝置與「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」連線期間將暫時中斷 Wi-Fi 連線"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"手機與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"裝置與「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」連線期間將暫時中斷 Wi-Fi 連線"</string> <string name="dlg_ok" msgid="254496739491689405">"確定"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"無法連線至「<xliff:g id="SSID">%1$s</xliff:g>」"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"輕觸即可變更隱私權設定並重試"</string> diff --git a/service/ServiceWifiResources/res/values-zu/strings.xml b/service/ServiceWifiResources/res/values-zu/strings.xml index 23c754f1b3..d8e04f070e 100644 --- a/service/ServiceWifiResources/res/values-zu/strings.xml +++ b/service/ServiceWifiResources/res/values-zu/strings.xml @@ -60,9 +60,7 @@ <string name="wifi_p2p_to_message" msgid="3809923305696994787">"Ku:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5200220251738047620">"Faka i-PIN edingekayo:"</string> <string name="wifi_p2p_show_pin_message" msgid="1000091690967930798">"PIN:"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="2875937871590955304">"Ithebulethi izonqamuka okwesikhashana ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="9133053225387001827">"Idivayisi yakho ye-Android TV izonqamula okwesikhashana kusuka ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> - <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="2226863827636191980">"Ifoni izonqamuka okwesikhashana ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="wifi_p2p_frequency_conflict_message" msgid="8535404941723941766">"Idivayisi yakho izonqamuka okwesikhashana ku-Wi-Fi ngenkathi uxhume ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="dlg_ok" msgid="254496739491689405">"KULUNGILE"</string> <string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"Ayikwazi ukuxhumeka ku-<xliff:g id="SSID">%1$s</xliff:g>"</string> <string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"Thepha ukuze ushintshe izilungiselelo zobumfihlo uphinde uzame futhi"</string> diff --git a/service/ServiceWifiResources/res/values/config.xml b/service/ServiceWifiResources/res/values/config.xml index 14b83ebc94..eb1845c0e8 100644 --- a/service/ServiceWifiResources/res/values/config.xml +++ b/service/ServiceWifiResources/res/values/config.xml @@ -611,6 +611,12 @@ <integer translatable="false" name="config_wifiDisableReasonAuthenticationNoSubscriptionDurationMs"> -1 </integer> <integer translatable="false" name="config_wifiDisableReasonConsecutiveFailuresDurationMs"> 300000 </integer> + <!-- Configuration for disabling a network due to repeated NUD failures --> + <!-- The number of NUD failures that need to happen to trigger blocking --> + <integer translatable="false" name="config_wifiDisableReasonRepeatedNudFailuresThreshold"> 5 </integer> + <!-- The NUD failures need to happen within this time window or else the counter will be reset --> + <integer translatable="false" name="config_wifiDisableReasonRepeatedNudFailuresWindowMs"> 60000 </integer> + <!-- List of constants that indicate the number of consecutive failures per type needed to block a BSSID. A blocked BSSID will not be considered in network selection and firmware roaming.--> <integer translatable="false" name="config_wifiBssidBlocklistMonitorApUnableToHandleNewStaThreshold"> 1 </integer> @@ -660,9 +666,6 @@ <!-- Indicates that hidden networks are to be scanned during scan only mode --> <bool translatable="false" name="config_wifiScanHiddenNetworksScanOnlyMode">false</bool> - <!-- Enable logging WifiIsUnusableEvent in metrics which gets triggered when wifi becomes unusable. --> - <bool translatable="false" name="config_wifiIsUnusableEventMetricsEnabled">true</bool> - <!-- The minimum number of txBad the framework has to observe to trigger a wifi data stall. --> <integer translatable="false" name="config_wifiDataStallMinTxBad">1</integer> @@ -1273,4 +1276,54 @@ regulatory domain. false: disconnect on NUD failures (normal/default action). --> <bool translatable="false" name ="config_wifiDisableNudDisconnectsForWapiInSpecificCc">false</bool> + <!-- A list of AKM suite selector mapping to configure the unknown AKM suite specifier to + known AKM suite specifier (Refer IEEE-80211-2020 section 9.4.2.24.3 AKM suites). + An AKM suite selector is defined as a combination of OUI (Organizationally unique + identifier) and AKMP (Authentication and key management protocol) suite type in IEEE80211 + spec. For example 00-0F-AC:1 represents Authentication negotiated over IEEE Std 802.1X, + where the OUI is 00-0F-AC and AKMP is 1. + The Values specified here is for OEMs to allow setting the security type for APs which + advertise the AKMs not defined in Wi-Fi framework(unknown to framework). If a mapping is + available, framework sets the AP's key management type to the mapped known AKM and the + security type will be derived based on the known AKM. Then it is up to the HAL + implementation to derive the actual AKM to use in connection. + The mapping specified here is in integer decimal format separated by a comma: + (Unknown AKM, Known AKM). + When defining the integer AKM value here, follow this rule, the most significant byte + should carry the AKMP suite type. Use the below method to compute the integer decimal + AKM suite selector value - AKM_VALUE(0x00, 0x0f, 0xac, 0x1) + AKM_VALUE(a, b, c, d) -> ((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) + | (u32) (d)) = 28053248 (Hex value - 0x01ac0f00) --> + <string-array translatable="false" name="config_wifiUnknownAkmToKnownAkmMapping"> + <!-- Below is a sample configuration for this list: + <item>unknownAkm1,knownAkm</item> + <item>unknownAkm2,knownAkm</item> + --> + </string-array> + <!-- Integer for minimum time between IEEE 802.11az non-trigger based ranging measurements in + microseconds. Note that ranging request converts this to units of 100 microseconds. So the + value should be a multiple of 100 microseconds. Non-zero values in this setting take + precedence over individual responder settings, effectively enforcing a system-wide minimum + measurement interval for non-trigger based ranging operations.. --> + <integer translatable="false" name="config_wifi80211azMinTimeBetweenNtbMeasurementsMicros">250000</integer> + <!-- Integer for maximum time between IEEE 802.11az non-trigger based ranging measurements in + microseconds. Note that ranging request converts this to units of 10 milliseconds. So the + value should be a multiple of 10000 microseconds. Non-zero values in this setting take + precedence over individual responder settings, effectively enforcing a system-wide maximum + measurement interval for non-trigger based ranging operations. --> + <integer translatable="false" name="config_wifi80211azMaxTimeBetweenNtbMeasurementsMicros">15000000</integer> + + <!-- Boolean indicating whether the device supports d2d allowed control when infra STA is disabled --> + <bool translatable="false" name ="config_wifiD2dAllowedControlSupportedWhenInfraStaDisabled">false</bool> + <!-- Array describing MAC OUI list to block TWT session setup request. If the primary station is + connected to an AP with a MAC address OUI (https://standards-oui.ieee.org/oui/oui.txt) + matching with any of entries in this blocked list, WifiManager#setupTwtSession() will fail + with TwtSessionCallback#onFailure(errorCode = TWT_ERROR_CODE_AP_OUI_BLOCKLISTED). + --> + <integer-array translatable="false" name="config_wifiTwtBlockedOuiList"> + <!-- Below is a sample configuration for this list: + <item>0x001122</item> + <item>0x334455</item> + --> + </integer-array> </resources> diff --git a/service/ServiceWifiResources/res/values/overlayable.xml b/service/ServiceWifiResources/res/values/overlayable.xml index 0504a5e74d..5764f263d6 100644 --- a/service/ServiceWifiResources/res/values/overlayable.xml +++ b/service/ServiceWifiResources/res/values/overlayable.xml @@ -179,6 +179,8 @@ <item type="integer" name="config_wifiDisableReasonByWrongPasswordDurationMs" /> <item type="integer" name="config_wifiDisableReasonAuthenticationNoSubscriptionDurationMs" /> <item type="integer" name="config_wifiDisableReasonConsecutiveFailuresDurationMs" /> + <item type="integer" name="config_wifiDisableReasonRepeatedNudFailuresThreshold" /> + <item type="integer" name="config_wifiDisableReasonRepeatedNudFailuresWindowMs" /> <item type="integer" name="config_wifiBssidBlocklistMonitorApUnableToHandleNewStaThreshold" /> <item type="integer" name="config_wifiBssidBlocklistMonitorNetworkValidationFailureThreshold" /> @@ -199,7 +201,6 @@ <item type="integer" name="config_wifiBssidBlocklistMonitorValidationFailureBaseBlockDurationMs" /> <item type="bool" name="config_wifiScanHiddenNetworksScanOnlyMode" /> <item type="integer" name="config_wifiHardwareSoftapMaxClientCount" /> - <item type="bool" name="config_wifiIsUnusableEventMetricsEnabled" /> <item type="integer" name="config_wifiDataStallMinTxBad" /> <item type="integer" name="config_wifiDataStallMinTxSuccessWithoutRx" /> <item type="bool" name="config_wifiLinkSpeedMetricsEnabled" /> @@ -336,6 +337,11 @@ <item type="bool" name="config_wifiSofapHalMapWpa3TransitionModeToWpa3OnlyIn6GHzBand" /> <item type="bool" name ="config_wifiRemainConnectedAfterIpProvisionTimeout" /> <item type="bool" name ="config_wifiDisableNudDisconnectsForWapiInSpecificCc" /> + <item type="array" name="config_wifiUnknownAkmToKnownAkmMapping" /> + <item type="integer" name="config_wifi80211azMinTimeBetweenNtbMeasurementsMicros"/> + <item type="integer" name="config_wifi80211azMaxTimeBetweenNtbMeasurementsMicros"/> + <item type="bool" name="config_wifiD2dAllowedControlSupportedWhenInfraStaDisabled" /> + <item type="array" name="config_wifiTwtBlockedOuiList" /> <!-- Params from config.xml that can be overlayed --> diff --git a/service/ServiceWifiResources/res/values/strings.xml b/service/ServiceWifiResources/res/values/strings.xml index 8b7f383ad8..26624b023e 100644 --- a/service/ServiceWifiResources/res/values/strings.xml +++ b/service/ServiceWifiResources/res/values/strings.xml @@ -112,9 +112,7 @@ <string name="wifi_p2p_enter_pin_message">Type the required PIN: </string> <string name="wifi_p2p_show_pin_message">PIN: </string> - <string name="wifi_p2p_frequency_conflict_message" product="tablet">The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string> - <string name="wifi_p2p_frequency_conflict_message" product="tv">Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string> - <string name="wifi_p2p_frequency_conflict_message" product="default">The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string> + <string name="wifi_p2p_frequency_conflict_message">Your device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string> <!-- Dialog ok button--> <string name="dlg_ok">OK</string> diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java index 9b776bd53c..ccd85abf37 100644 --- a/service/java/com/android/server/wifi/ActiveModeWarden.java +++ b/service/java/com/android/server/wifi/ActiveModeWarden.java @@ -18,6 +18,8 @@ package com.android.server.wifi; import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; +import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; @@ -47,6 +49,7 @@ import android.net.wifi.IWifiConnectedNetworkScorer; import android.net.wifi.IWifiNetworkStateChangedListener; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; +import android.net.wifi.SoftApState; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -214,9 +217,9 @@ public class ActiveModeWarden { } /** - * Get the request WorkSource for secondary CMM + * Get the request WorkSource for secondary LOCAL-ONLY CMM * - * @return the WorkSources of the current secondary CMMs + * @return the WorkSources of the current secondary LOCAL-ONLY CMMs */ public Set<WorkSource> getSecondaryRequestWs() { synchronized (mServiceApiLock) { @@ -716,6 +719,7 @@ public class ActiveModeWarden { } }, new IntentFilter(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED)); } + mWifiGlobals.setD2dStaConcurrencySupported(mWifiNative.isP2pStaConcurrencySupported()); // Initialize the supported feature set. setSupportedFeatureSet(mWifiNative.getSupportedFeatureSet(null), mWifiNative.isStaApConcurrencySupported(), @@ -1414,7 +1418,7 @@ public class ActiveModeWarden { ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager( listener, requestorWs, role, mVerboseLoggingEnabled); mClientModeManagers.add(manager); - if (ROLE_CLIENT_SECONDARY_LONG_LIVED.equals(role) || ROLE_CLIENT_LOCAL_ONLY.equals(role)) { + if (ROLE_CLIENT_LOCAL_ONLY.equals(role)) { synchronized (mServiceApiLock) { mRequestWs.add(new WorkSource(requestorWs)); } @@ -1435,7 +1439,7 @@ public class ActiveModeWarden { synchronized (mServiceApiLock) { mRequestWs.remove(manager.getRequestorWs()); } - if (ROLE_CLIENT_SECONDARY_LONG_LIVED.equals(role) || ROLE_CLIENT_LOCAL_ONLY.equals(role)) { + if (ROLE_CLIENT_LOCAL_ONLY.equals(role)) { synchronized (mServiceApiLock) { mRequestWs.add(new WorkSource(requestorWs)); } @@ -1690,8 +1694,7 @@ public class ActiveModeWarden { private void onStoppedOrStartFailure(ConcreteClientModeManager clientModeManager) { mClientModeManagers.remove(clientModeManager); - if (ROLE_CLIENT_SECONDARY_LONG_LIVED.equals(clientModeManager.getPreviousRole()) - || ROLE_CLIENT_LOCAL_ONLY.equals(clientModeManager.getPreviousRole())) { + if (ROLE_CLIENT_LOCAL_ONLY.equals(clientModeManager.getPreviousRole())) { synchronized (mServiceApiLock) { mRequestWs.remove(clientModeManager.getRequestorWs()); } @@ -2048,8 +2051,9 @@ public class ActiveModeWarden { softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY ? mLohsCallback : mSoftApCallback; // need to notify SoftApCallback that start/stop AP failed - callback.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + callback.onStateChanged(new SoftApState( + WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL, + softApConfig.getTetheringRequest(), null /* iface */)); } break; default: @@ -2107,7 +2111,7 @@ public class ActiveModeWarden { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ActiveModeWarden.class.getSimpleName() + "." + DefaultState.class.getSimpleName() + "." + getWhatToString(what); } @@ -2140,17 +2144,17 @@ public class ActiveModeWarden { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ActiveModeWarden.class.getSimpleName() + "." + DefaultState.class.getSimpleName() + "." + getWhatToString(what); } @Override - void enterImpl() { + public void enterImpl() { } @Override - void exitImpl() { + public void exitImpl() { } private void checkAndHandleAirplaneModeState() { @@ -2238,7 +2242,8 @@ public class ActiveModeWarden { } private boolean shouldEnableSta() { - return mSettingsStore.isWifiToggleEnabled() || shouldEnableScanOnlyMode(); + return (mSettingsStore.isWifiToggleEnabled() || shouldEnableScanOnlyMode()) + && !mSettingsStore.isSatelliteModeOn(); } private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) { @@ -2422,7 +2427,8 @@ public class ActiveModeWarden { if (mAllowRootToGetLocalOnlyCmm && curUid == 0) { // 0 is root UID. continue; } - if (mWifiPermissionsUtil.checkEnterCarModePrioritized(curUid)) { + if (curUid != Process.SYSTEM_UID + && mWifiPermissionsUtil.checkEnterCarModePrioritized(curUid)) { requestInfo.listener.onAnswer(primaryManager); if (mVerboseLoggingEnabled) { Log.w(TAG, "Uid " + curUid @@ -2510,8 +2516,7 @@ public class ActiveModeWarden { // fallback decision if (requestInfo.clientRole == ROLE_CLIENT_LOCAL_ONLY - && mContext.getResources().getBoolean( - R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled) + && isStaStaConcurrencySupportedForLocalOnlyConnections() && !mWifiPermissionsUtil.isTargetSdkLessThan( requestInfo.requestorWs.getPackageName(0), Build.VERSION_CODES.S, requestInfo.requestorWs.getUid(0))) { @@ -2768,6 +2773,9 @@ public class ActiveModeWarden { // The WPA didn't be deprecated, set it. additionalFeatureSet |= WifiManager.WIFI_FEATURE_WPA_PERSONAL; } + if (mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()) { + additionalFeatureSet |= WifiManager.WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED; + } mSupportedFeatureSet.set( (supportedFeatureSet | concurrencyFeatureSet | additionalFeatureSet) & ~excludedFeatureSet); diff --git a/service/java/com/android/server/wifi/ApplicationQosPolicyRequestHandler.java b/service/java/com/android/server/wifi/ApplicationQosPolicyRequestHandler.java index 088ad63652..f5893d5817 100644 --- a/service/java/com/android/server/wifi/ApplicationQosPolicyRequestHandler.java +++ b/service/java/com/android/server/wifi/ApplicationQosPolicyRequestHandler.java @@ -30,6 +30,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; import com.android.wifi.resources.R; import java.io.PrintWriter; @@ -353,16 +354,33 @@ public class ApplicationQosPolicyRequestHandler { * Request to send all tracked policies to the specified interface. * * @param ifaceName Interface name to send the policies to. + * @param apSupportsQosChars Whether the AP connected on this interface + * supports QosCharacteristics. */ - public void queueAllPoliciesOnIface(String ifaceName) { - List<QosPolicyParams> policyList = mPolicyTrackingTable.getAllPolicies(); + public void queueAllPoliciesOnIface(String ifaceName, boolean apSupportsQosChars) { + List<QosPolicyParams> policiesWithoutQosChars = + mPolicyTrackingTable.getAllPolicies(false); + List<QosPolicyParams> policiesWithQosChars = SdkLevel.isAtLeastV() && apSupportsQosChars + ? mPolicyTrackingTable.getAllPolicies(true) : Collections.emptyList(); + int totalNumPolicies = policiesWithoutQosChars.size() + policiesWithQosChars.size(); + Log.i(TAG, "Queueing all policies on iface=" + ifaceName + ". numPolicies=" - + policyList.size()); - if (policyList.isEmpty()) return; + + totalNumPolicies); + Log.i(TAG, policiesWithQosChars.size() + " policies contain QosCharacteristics"); + if (totalNumPolicies == 0) return; + + // Divide policies into batches of size MAX_POLICIES_PER_TRANSACTION. Separate batches + // should be created for policies that contain QosCharacteristics, and those that do + // not contain them. + List<List<QosPolicyParams>> batches = new ArrayList<>(); + if (!policiesWithoutQosChars.isEmpty()) { + batches.addAll(divideRequestIntoBatches(policiesWithoutQosChars)); + } + if (!policiesWithQosChars.isEmpty()) { + batches.addAll(divideRequestIntoBatches(policiesWithQosChars)); + } - // Divide policyList into batches of size MAX_POLICIES_PER_TRANSACTION, - // and queue each batch on the specified interface. - List<List<QosPolicyParams>> batches = divideRequestIntoBatches(policyList); + // Queue all batches on the specified interface. for (List<QosPolicyParams> batch : batches) { QueuedRequest request = new QueuedRequest( REQUEST_TYPE_ADD, batch, null, null, null, DEFAULT_UID); diff --git a/service/java/com/android/server/wifi/ApplicationQosPolicyTrackingTable.java b/service/java/com/android/server/wifi/ApplicationQosPolicyTrackingTable.java index 014fe7b1c0..d8509d4b3d 100644 --- a/service/java/com/android/server/wifi/ApplicationQosPolicyTrackingTable.java +++ b/service/java/com/android/server/wifi/ApplicationQosPolicyTrackingTable.java @@ -19,6 +19,8 @@ package com.android.server.wifi; import android.net.wifi.QosPolicyParams; import android.net.wifi.WifiManager; +import com.android.modules.utils.build.SdkLevel; + import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; @@ -26,6 +28,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.stream.Stream; /** * Table containing application-added QoS policies that are being tracked by the framework. @@ -214,13 +217,20 @@ public class ApplicationQosPolicyTrackingTable { /** * Get all policies that are tracked by this table. * + * @param shouldContainQosChars Whether the returned policies should contain QosCharacteristics. + * Only applicable if SDK >= V. * @return List of policies, or empty list if there are no policies in the table. */ - public List<QosPolicyParams> getAllPolicies() { + public List<QosPolicyParams> getAllPolicies(boolean shouldContainQosChars) { if (mPolicyHashToPolicyMap.isEmpty()) { return new ArrayList<>(); } - return mPolicyHashToPolicyMap.values().stream().toList(); + Stream<QosPolicyParams> policyStream = mPolicyHashToPolicyMap.values().stream(); + if (SdkLevel.isAtLeastV()) { + policyStream = policyStream.filter(p -> + shouldContainQosChars == (p.getQosCharacteristics() != null)); + } + return policyStream.toList(); } /** diff --git a/service/java/com/android/server/wifi/AvailableNetworkNotifier.java b/service/java/com/android/server/wifi/AvailableNetworkNotifier.java index c4d43c578b..03d6cf567c 100644 --- a/service/java/com/android/server/wifi/AvailableNetworkNotifier.java +++ b/service/java/com/android/server/wifi/AvailableNetworkNotifier.java @@ -467,7 +467,7 @@ public class AvailableNetworkNotifier { // only keep netId, discard other fields new NetworkUpdateResult(result.getNetworkId()), new ActionListenerWrapper(listener), - Process.SYSTEM_UID, mContext.getOpPackageName())); + Process.SYSTEM_UID, mContext.getOpPackageName(), null)); addNetworkToBlocklist(mRecommendedNetwork.SSID); } diff --git a/service/java/com/android/server/wifi/BackupRestoreController.java b/service/java/com/android/server/wifi/BackupRestoreController.java new file mode 100644 index 0000000000..374743b8cb --- /dev/null +++ b/service/java/com/android/server/wifi/BackupRestoreController.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2024 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.util.Log; +import android.util.Xml; + +import com.android.internal.util.FastXmlSerializer; +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.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Class used to backup/restore data. + */ +public class BackupRestoreController { + private static final String TAG = "BackupRestoreController"; + + private final WifiSettingsBackupRestore mWifiSettingsBackupRestore; + private final Clock mClock; + + private static final String XML_TAG_DOCUMENT_HEADER = "WifiSettingsBackupData"; + private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); + + /** + * Verbose logging flag. + */ + private boolean mVerboseLoggingEnabled = false; + /** + * Store the dump of the backup/restore data for debugging. This is only stored when verbose + * logging is enabled. + */ + private byte[] mDebugLastBackupDataRetrieved; + private long mLastBackupDataRetrievedTimestamp = 0; + private byte[] mDebugLastBackupDataRestored; + private long mLastBackupDataRestoredTimestamp = 0; + + public BackupRestoreController(WifiSettingsBackupRestore wifiSettingsBackupRestore, + Clock clock) { + mWifiSettingsBackupRestore = wifiSettingsBackupRestore; + mClock = clock; + } + + /** + * Retrieve an XML byte stream representing the data that needs to be backed up. + * + * @return Raw byte stream of XML that needs to be backed up. + */ + public byte[] retrieveBackupData() { + try { + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, XML_TAG_DOCUMENT_HEADER); + + mWifiSettingsBackupRestore.retrieveBackupDataFromSettingsConfigStore(out, outputStream); + + XmlUtil.writeDocumentEnd(out, XML_TAG_DOCUMENT_HEADER); + byte[] backupData = outputStream.toByteArray(); + if (mVerboseLoggingEnabled) { + mDebugLastBackupDataRetrieved = backupData; + } + mLastBackupDataRetrievedTimestamp = mClock.getWallClockMillis(); + return backupData; + } catch (IOException e) { + Log.e(TAG, "Error retrieving the backup data: " + e); + } + return new byte[0]; + } + + private void distpatchBackupData(String sectionName, XmlPullParser in, int depth) + throws XmlPullParserException, IOException { + switch (sectionName) { + case WifiSettingsBackupRestore.XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA: + mWifiSettingsBackupRestore.restoreSettingsFromBackupData(in, depth); + break; + default: + Log.i(TAG, "unknown tag: (backed up from newer version?)" + sectionName); + } + } + + /** + * Split the back up data to retrieve each back up session. + * + * @param data raw byte stream representing the XML data. + */ + public void parserBackupDataAndDispatch(byte[] data) { + if (data == null || data.length == 0) { + Log.e(TAG, "Invalid backup data received"); + return; + } + if (mVerboseLoggingEnabled) { + mDebugLastBackupDataRestored = data; + } + try { + final XmlPullParser in = Xml.newPullParser(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(data); + in.setInput(inputStream, StandardCharsets.UTF_8.name()); + // Start parsing the XML stream. + XmlUtil.gotoDocumentStart(in, XML_TAG_DOCUMENT_HEADER); + int sectionDepth = in.getDepth(); + String[] sectionName = new String[1]; + while (XmlUtil.gotoNextSectionOrEnd(in, sectionName, sectionDepth)) { + try { + if (sectionName[0] == null) { + throw new XmlPullParserException("Missing value name"); + } + distpatchBackupData(sectionName[0], in, sectionDepth); + } catch (XmlPullParserException | IOException ex) { + Log.e(TAG, "Error to parser tag: " + sectionName[0]); + } + } + mLastBackupDataRestoredTimestamp = mClock.getWallClockMillis(); + } catch (XmlPullParserException | IOException ex) { + Log.e(TAG, "Error :" + ex); + } + + } + + /** + * Enable verbose logging. + * + * @param verboseEnabled whether or not verbosity log level is enabled. + */ + public void enableVerboseLogging(boolean verboseEnabled) { + mVerboseLoggingEnabled = verboseEnabled; + } + + /** + * Dump out the last backup/restore data if verbose logging is enabled. + * + * @param fd unused + * @param pw PrintWriter for writing dump to + * @param args unused + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Dump of " + TAG); + if (mDebugLastBackupDataRetrieved != null) { + pw.println("Last backup data retrieved: " + + createLogFromBackupData(mDebugLastBackupDataRetrieved)); + + } + pw.println("mLastBackupDataRetrievedTimestamp: " + + (mLastBackupDataRetrievedTimestamp != 0 + ? FORMATTER.format(new Date(mLastBackupDataRetrievedTimestamp)) : "N/A")); + if (mDebugLastBackupDataRestored != null) { + pw.println("Last backup data restored: " + + createLogFromBackupData(mDebugLastBackupDataRestored)); + } + pw.println("mLastBackupDataRestoredTimestamp: " + + (mLastBackupDataRestoredTimestamp != 0 + ? FORMATTER.format(new Date(mLastBackupDataRestoredTimestamp)) : "N/A")); + } + + private String createLogFromBackupData(byte[] data) { + if (data != null) { + StringBuilder sb = new StringBuilder(); + try { + String xmlString = new String(data, StandardCharsets.UTF_8.name()); + for (String line : xmlString.split("\n")) { + sb.append(line).append("\n"); + } + return sb.toString(); + } catch (UnsupportedEncodingException e) { + Log.e(TAG, "fail to create log from backup data. " + e); + } + } + return ""; + } +} diff --git a/service/java/com/android/server/wifi/ClientMode.java b/service/java/com/android/server/wifi/ClientMode.java index 1427a8dba4..7292de3338 100644 --- a/service/java/com/android/server/wifi/ClientMode.java +++ b/service/java/com/android/server/wifi/ClientMode.java @@ -66,7 +66,7 @@ public interface ClientMode { void enableVerboseLogging(boolean verbose); void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, - @NonNull String packageName); + @NonNull String packageName, @Nullable String attributionTag); void saveNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, @NonNull String packageName); diff --git a/service/java/com/android/server/wifi/ClientModeDefaults.java b/service/java/com/android/server/wifi/ClientModeDefaults.java index 115dfaf533..f526f2dc6a 100644 --- a/service/java/com/android/server/wifi/ClientModeDefaults.java +++ b/service/java/com/android/server/wifi/ClientModeDefaults.java @@ -17,6 +17,7 @@ package com.android.server.wifi; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.DhcpResultsParcelable; import android.net.MacAddress; import android.net.Network; @@ -47,7 +48,7 @@ public interface ClientModeDefaults extends ClientMode { default void dump(FileDescriptor fd, PrintWriter pw, String[] args) { } default void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, - int callingUid, @NonNull String packageName) { + int callingUid, @NonNull String packageName, @Nullable String attributionTag) { // wifi off, can't connect. wrapper.sendFailure(WifiManager.ActionListener.FAILURE_BUSY); } diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index c5a891f708..4b3cf17404 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -93,6 +93,7 @@ import android.net.wifi.WifiManager.DeviceMobilityState; import android.net.wifi.WifiNetworkAgentSpecifier; import android.net.wifi.WifiNetworkSpecifier; import android.net.wifi.WifiSsid; +import android.net.wifi.flags.Flags; import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.nl80211.DeviceWiphyCapabilities; @@ -194,6 +195,11 @@ public class ClientModeImpl extends StateMachine implements ClientMode { @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE = 3000; private static final String TAG = "WifiClientModeImpl"; + // Hardcoded constant used for caller to avoid triggering connect choice that force framework + // to stick to the selected network. Do not change this value to maintain backward + // compatibility. + public static final String ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE = + "ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE"; private static final int IPCLIENT_STARTUP_TIMEOUT_MS = 2_000; private static final int IPCLIENT_SHUTDOWN_TIMEOUT_MS = 60_000; // 60 seconds @@ -214,15 +220,15 @@ public class ClientModeImpl extends StateMachine implements ClientMode { */ @Override protected void loge(String s) { - Log.e(getTag(), s); + Log.e(getTag(), s, null); } @Override protected void logd(String s) { - Log.d(getTag(), s); + Log.d(getTag(), s, null); } @Override protected void log(String s) { - Log.d(getTag(), s); + Log.d(getTag(), s, null); } private final WifiContext mContext; private final WifiMetrics mWifiMetrics; @@ -358,6 +364,9 @@ public class ClientModeImpl extends StateMachine implements ClientMode { // This is is used to track the number of TDLS peers enabled in driver via enableTdls() private Set<String> mEnabledTdlsPeers = new ArraySet<>(); + // Tracks the last NUD failure timestamp, and number of failures. + private Pair<Long, Integer> mNudFailureCounter = new Pair<>(0L, 0); + /** * Method to clear {@link #mTargetBssid} and reset the current connected network's * bssid in wpa_supplicant after a roam/connect attempt. @@ -1240,6 +1249,16 @@ public class ClientModeImpl extends StateMachine implements ClientMode { // nothing to do. return; } + + if (newConfig.isWifi7Enabled() != oldConfig.isWifi7Enabled()) { + Log.w(getTag(), "Wi-Fi " + (newConfig.isWifi7Enabled() ? "enabled" : "disabled") + + " triggering disconnect"); + mFrameworkDisconnectReasonOverride = + WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_NETWORK_WIFI7_TOGGLED; + sendMessage(CMD_DISCONNECT, StaEvent.DISCONNECT_NETWORK_WIFI7_TOGGLED); + return; + } + boolean isMetered = WifiConfiguration.isMetered(newConfig, mWifiInfo); boolean wasMetered = WifiConfiguration.isMetered(oldConfig, mWifiInfo); // Check if user/app change meteredOverride or trusted for connected network. @@ -1443,14 +1462,14 @@ public class ClientModeImpl extends StateMachine implements ClientMode { * @param packageName package name of the app requesting the connection. */ private void connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect, - @NonNull String packageName) { + @NonNull String packageName, @Nullable String attributionTag) { if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) { mIsUserSelected = true; } logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid + ", package " + packageName + ", forceReconnect = " + forceReconnect + ", isUserSelected = " - + mIsUserSelected); + + mIsUserSelected + ", attributionTag = " + attributionTag); updateSaeAutoUpgradeFlagForUserSelectNetwork(netId); if (!forceReconnect && (mLastNetworkId == netId || mTargetNetworkId == netId)) { // We're already connecting/connected to the user specified network, don't trigger a @@ -1487,6 +1506,10 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } }, mWifiThreadRunner).launchDialog(); } else { + if (mIsUserSelected && ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE.equals(attributionTag)) { + mIsUserSelected = false; + logd("connectToUserSelectNetwork attributionTag override to disable user selected"); + } mWifiConnectivityManager.prepareForForcedConnection(netId); if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) { mWifiMetrics.setNominatorForNetwork(netId, @@ -1632,6 +1655,11 @@ public class ClientModeImpl extends StateMachine implements ClientMode { if (mContext.getResources().getBoolean(R.bool.config_wifi11axSupportOverride)) { cap.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, true); } + // Enable WPA3 SAE auto-upgrade offload + if (Flags.getDeviceCrossAkmRoamingSupport() && SdkLevel.isAtLeastV() + && cap.getMaxNumberAkms() >= 2) { + mWifiGlobals.setWpa3SaeUpgradeOffloadEnabled(); + } mWifiNative.setDeviceWiphyCapabilities(mInterfaceName, cap); } @@ -1652,6 +1680,15 @@ public class ClientModeImpl extends StateMachine implements ClientMode { return mWifiNative.isWifiStandardSupported(mInterfaceName, standard); } + /** + * Check whether 11ax is supported by the most recent connection. + */ + public boolean mostRecentConnectionSupports11ax() { + return mLastConnectionCapabilities != null + && (mLastConnectionCapabilities.wifiStandard == ScanResult.WIFI_STANDARD_11AX + || mLastConnectionCapabilities.wifiStandard == ScanResult.WIFI_STANDARD_11BE); + } + private byte[] getDstMacForKeepalive(KeepalivePacketData packetData) throws InvalidPacketException { try { @@ -2672,6 +2709,40 @@ public class ClientModeImpl extends StateMachine implements ClientMode { if (mVerboseLoggingEnabled) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); } + private void updateMloLinkFromPollResults(MloLink link, WifiSignalPollResults pollResults) { + if (link == null) return; + int linkId = link.getLinkId(); + link.setRssi(pollResults.getRssi(linkId)); + link.setTxLinkSpeedMbps(pollResults.getTxLinkSpeed(linkId)); + link.setRxLinkSpeedMbps(pollResults.getRxLinkSpeed(linkId)); + link.setChannel(ScanResult.convertFrequencyMhzToChannelIfSupported( + pollResults.getFrequency(linkId))); + link.setBand(ScanResult.toBand(pollResults.getFrequency(linkId))); + if (mVerboseLoggingEnabled) { + logd("updateMloLinkFromPollResults: linkId=" + linkId + " rssi=" + link.getRssi() + + " channel=" + link.getChannel() + + " band=" + link.getBand() + + " TxLinkspeed=" + link.getTxLinkSpeedMbps() + + " RxLinkSpeed=" + link.getRxLinkSpeedMbps()); + + } + } + + private void updateMloLinkFromScanResult(MloLink link) { + if (link == null || link.getApMacAddress() == null) return; + ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork( + mWifiInfo.getNetworkId()); + if (scanDetailCache == null) return; + ScanResult matchingScanResult = scanDetailCache.getScanResult( + link.getApMacAddress().toString()); + if (matchingScanResult == null) return; + link.setRssi(matchingScanResult.level); + if (mVerboseLoggingEnabled) { + logd("updateMloLinkFromScanResult: linkId=" + link.getLinkId() + " rssi=" + + link.getRssi()); + } + } + /* * Fetch link layer stats, RSSI, linkspeed, and frequency on current connection * and update Network capabilities @@ -2696,21 +2767,13 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + " RxLinkSpeed=" + newRxLinkSpeed); } - /* Set link specific signal poll results for associated links */ - for (MloLink link : mWifiInfo.getAssociatedMloLinks()) { - int linkId = link.getLinkId(); - link.setRssi(pollResults.getRssi(linkId)); - link.setTxLinkSpeedMbps(pollResults.getTxLinkSpeed(linkId)); - link.setRxLinkSpeedMbps(pollResults.getRxLinkSpeed(linkId)); - link.setChannel(ScanResult.convertFrequencyMhzToChannelIfSupported( - pollResults.getFrequency(linkId))); - link.setBand(ScanResult.toBand(pollResults.getFrequency(linkId))); - if (mVerboseLoggingEnabled) { - logd("linkId=" + linkId + " rssi=" + link.getRssi() - + " channel=" + link.getChannel() - + " band=" + link.getBand() - + " TxLinkspeed=" + link.getTxLinkSpeedMbps() - + " RxLinkSpeed=" + link.getRxLinkSpeedMbps()); + for (MloLink link : mWifiInfo.getAffiliatedMloLinks()) { + if (pollResults.isAvailable(link.getLinkId()) + && (link.getState() == MloLink.MLO_LINK_STATE_IDLE + || link.getState() == MloLink.MLO_LINK_STATE_ACTIVE)) { + updateMloLinkFromPollResults(link, pollResults); + } else { + updateMloLinkFromScanResult(link); } } @@ -3369,10 +3432,15 @@ public class ClientModeImpl extends StateMachine implements ClientMode { mLastConnectionCapabilities.apTidToLinkMapNegotiationSupported); mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps(mInterfaceName, maxTxLinkSpeedMbps, maxRxLinkSpeedMbps); + mWifiMetrics.setConnectionChannelWidth(mInterfaceName, + mLastConnectionCapabilities.channelBandwidth); if (mLastConnectionCapabilities.wifiStandard == ScanResult.WIFI_STANDARD_11BE) { updateMloLinkAddrAndStates(mWifiNative.getConnectionMloLinksInfo(mInterfaceName)); updateBlockListAffiliatedBssids(); } + if (SdkLevel.isAtLeastV() && mLastConnectionCapabilities.vendorData != null) { + mWifiInfo.setVendorData(mLastConnectionCapabilities.vendorData); + } if (mVerboseLoggingEnabled) { StringBuilder sb = new StringBuilder(); logd(sb.append("WifiStandard: ").append(ScanResult.wifiStandardToString( @@ -3502,6 +3570,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mCurrentConnectionDetectedCaptivePortal = false; mLastSimBasedConnectionCarrierName = null; + mNudFailureCounter = new Pair<>(0L, 0); checkAbnormalDisconnectionAndTakeBugReport(); mWifiScoreCard.resetConnectionState(mInterfaceName); updateLayer2Information(); @@ -3676,7 +3745,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { * Inform other components that a new connection attempt is starting. */ private void reportConnectionAttemptStart( - WifiConfiguration config, String targetBSSID, int roamType) { + WifiConfiguration config, String targetBSSID, int roamType, int uid) { boolean isOobPseudonymEnabled = false; if (config.enterpriseConfig != null && config.enterpriseConfig.isAuthenticationSimBased() && mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(config.carrierId)) { @@ -3685,7 +3754,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { int overlapWithLastConnectionMs = mWifiMetrics.startConnectionEvent( mInterfaceName, config, targetBSSID, roamType, isOobPseudonymEnabled, - getClientRoleForMetrics(config)); + getClientRoleForMetrics(config), uid); if (mDeviceConfigFacade.isOverlappingConnectionBugreportEnabled() && overlapWithLastConnectionMs > mDeviceConfigFacade.getOverlappingConnectionDurationThresholdMs()) { @@ -4005,16 +4074,28 @@ public class ClientModeImpl extends StateMachine implements ClientMode { // roaming. The linked network roaming reset the mLastNetworkId which results in // the connected configuration to be null. config = getConnectingWifiConfigurationInternal(); + if (config == null) { + // config could be null if it had been removed from WifiConfigManager. In this case + // we should simply disconnect. + handleIpReachabilityLost(lossReason); + return; + } + } + final long curTime = mClock.getElapsedSinceBootMillis(); + if (curTime - mNudFailureCounter.first <= mWifiGlobals.getRepeatedNudFailuresWindowMs()) { + mNudFailureCounter = new Pair<>(curTime, mNudFailureCounter.second + 1); + } else { + mNudFailureCounter = new Pair<>(curTime, 1); } - if (config == null || (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC)) { - // config could be null if it had been removed from WifiConfigManager. In this case - // we should simply disconnect. And if IP reachability failures come from static IP - // case(e.g. a misconfigured default gateway IP address), refreshing L3 provisioning - // doesn't help improve the situation and also introduces a loop, it's better to - // disconnect and disable the auto-rejoin on that network. + if (mNudFailureCounter.second >= mWifiGlobals.getRepeatedNudFailuresThreshold()) { + // Disable and disconnect due to repeated NUD failures within limited time window. + mWifiConfigManager.updateNetworkSelectionStatus(config.networkId, + WifiConfiguration.NetworkSelectionStatus.DISABLED_REPEATED_NUD_FAILURES); handleIpReachabilityLost(lossReason); + mNudFailureCounter = new Pair<>(0L, 0); return; } + final NetworkAgentConfig naConfig = getNetworkAgentConfigInternal(config); final NetworkCapabilities nc = getCapabilities( getConnectedWifiConfigurationInternal(), getConnectedBssidInternal()); @@ -4367,10 +4448,10 @@ public class ClientModeImpl extends StateMachine implements ClientMode { if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { WifiConfiguration config = getConnectedWifiConfigurationInternal(); boolean shouldSetUserConnectChoice = config != null + && mIsUserSelected && isRecentlySelectedByTheUser(config) && (config.getNetworkSelectionStatus().hasEverConnected() - || config.isEphemeral()) - && mWifiPermissionsUtil.checkNetworkSettingsPermission(config.lastConnectUid); + || config.isEphemeral()); mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId, mIsUserSelected, shouldSetUserConnectChoice, mWifiInfo.getRssi()); // Notify PasspointManager of Passpoint network connected event. @@ -4612,7 +4693,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + ConnectableState.class.getSimpleName() + "." + getWhatToString(what); } @@ -4718,7 +4799,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { updateWifiConfigOnStartConnection(config, bssid); reportConnectionAttemptStart(config, mTargetBssid, - WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED); + WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED, uid); String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName); mWifiInfo.setMacAddress(currentMacAddress); @@ -4778,7 +4859,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { int netId = result.getNetworkId(); connectToUserSelectNetwork( netId, message.sendingUid, result.hasCredentialChanged(), - cnm.packageName); + cnm.packageName, cnm.attributionTag); mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CONNECT_NETWORK, mWifiConfigManager.getConfiguredNetwork(netId)); cnm.listener.sendSuccess(); @@ -5287,7 +5368,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { public boolean isAffiliatedLinkBssid(@NonNull MacAddress bssid) { List<MloLink> links = mWifiInfo.getAffiliatedMloLinks(); for (MloLink link: links) { - if (link.getApMacAddress().equals(bssid)) { + if (bssid.equals(link.getApMacAddress())) { return true; } } @@ -5556,7 +5637,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + ConnectingOrConnectedState.class.getSimpleName() + "." + getWhatToString( what); @@ -5749,8 +5830,10 @@ public class ClientModeImpl extends StateMachine implements ClientMode { mWifiInfo.setNetworkKey(config.getNetworkKeyFromSecurityType( mWifiInfo.getCurrentSecurityType())); if (mApplicationQosPolicyRequestHandler.isFeatureEnabled()) { - mApplicationQosPolicyRequestHandler.queueAllPoliciesOnIface(mInterfaceName); + mApplicationQosPolicyRequestHandler.queueAllPoliciesOnIface( + mInterfaceName, mostRecentConnectionSupports11ax()); } + mWifiNative.resendMscs(mInterfaceName); updateLayer2Information(); updateCurrentConnectionInfo(); transitionTo(mL3ProvisioningState); @@ -5979,7 +6062,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + L2ConnectingState.class.getSimpleName() + "." + getWhatToString(what); } @@ -6406,7 +6489,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + L2ConnectedState.class.getSimpleName() + "." + getWhatToString(what); } @@ -6544,7 +6627,8 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } checkIfNeedDisconnectSecondaryWifi(); if (mApplicationQosPolicyRequestHandler.isFeatureEnabled()) { - mApplicationQosPolicyRequestHandler.queueAllPoliciesOnIface(mInterfaceName); + mApplicationQosPolicyRequestHandler.queueAllPoliciesOnIface( + mInterfaceName, mostRecentConnectionSupports11ax()); } break; } @@ -6623,6 +6707,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } else { mRssiMonitor.setShortPollRssiInterval(); + removeMessages(CMD_RSSI_POLL); } break; } @@ -6905,7 +6990,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { Log.e(getTag(), "Fail to create an IpClient instance within " + IPCLIENT_STARTUP_TIMEOUT_MS + "ms"); handleNetworkDisconnect(false, - WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__TIMEOUT); + WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_CREATE_IP_CLIENT_TIMEOUT); transitionTo(mDisconnectedState); break; } @@ -6925,7 +7010,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + WaitBeforeL3ProvisioningState.class.getSimpleName() + "." + getWhatToString(what); @@ -6966,7 +7051,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + L3ProvisioningState.class.getSimpleName() + "." + getWhatToString(what); } @@ -7060,7 +7145,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + RoamingState.class.getSimpleName() + "." + getWhatToString(what); } @@ -7251,10 +7336,16 @@ public class ClientModeImpl extends StateMachine implements ClientMode { mWifiMetrics.noteFirstL3ConnectionAfterBoot(true); updateCurrentConnectionInfo(); sendConnectedState(); + // Set the roaming policy for the currently connected network + if (isPrimary() && getClientRoleForMetrics(config) + != WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_LOCAL_ONLY) { + mWifiInjector.getWifiRoamingModeManager().applyWifiRoamingMode( + mInterfaceName, mWifiInfo.getSSID()); + } } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + L3ConnectedState.class.getSimpleName() + "." + getWhatToString(what); } @@ -7291,6 +7382,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { config.networkId, DISABLED_UNWANTED_LOW_RSSI); } + mFrameworkDisconnectReasonOverride = WifiStatsLog.WIFI_DISCONNECT_REPORTED__FAILURE_CODE__DISCONNECT_UNWANTED_BY_CONNECTIVITY; mWifiNative.disconnect(mInterfaceName); } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN || message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) { @@ -7462,7 +7554,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { + " targetRoamBSSID " + mTargetBssid); reportConnectionAttemptStart(config, mTargetBssid, - WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE); + WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, Process.WIFI_UID); if (mWifiNative.roamToNetwork(mInterfaceName, config)) { mTargetWifiConfiguration = config; mIsAutoRoaming = true; @@ -7550,7 +7642,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ClientModeImpl.class.getSimpleName() + "." + DisconnectedState.class.getSimpleName() + "." + getWhatToString(what); } @@ -7826,21 +7918,23 @@ public class ClientModeImpl extends StateMachine implements ClientMode { public final NetworkUpdateResult result; public final ActionListenerWrapper listener; public final String packageName; + public final String attributionTag; ConnectNetworkMessage(NetworkUpdateResult result, ActionListenerWrapper listener, - String packageName) { + String packageName, @Nullable String attributionTag) { this.result = result; this.listener = listener; this.packageName = packageName; + this.attributionTag = attributionTag; } } /** Trigger network connection and provide status via the provided callback. */ public void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, - int callingUid, @NonNull String packageName) { + int callingUid, @NonNull String packageName, @Nullable String attributionTag) { Message message = obtainMessage(CMD_CONNECT_NETWORK, - new ConnectNetworkMessage(result, wrapper, packageName)); + new ConnectNetworkMessage(result, wrapper, packageName, attributionTag)); message.sendingUid = callingUid; sendMessage(message); } @@ -7850,7 +7944,7 @@ public class ClientModeImpl extends StateMachine implements ClientMode { int callingUid, @NonNull String packageName) { Message message = obtainMessage(CMD_SAVE_NETWORK, - new ConnectNetworkMessage(result, wrapper, packageName)); + new ConnectNetworkMessage(result, wrapper, packageName, null)); message.sendingUid = callingUid; sendMessage(message); } @@ -8120,9 +8214,43 @@ public class ClientModeImpl extends StateMachine implements ClientMode { ? mLastL2KeyAndGroupHint.second : null; final Layer2Information layer2Info = new Layer2Information(l2Key, groupHint, currentBssid); - final boolean mRemainConnectedAfterIpProvisionTimeout = mContext.getResources().getBoolean( - R.bool.config_wifiRemainConnectedAfterIpProvisionTimeout); + final ProvisioningConfiguration.Builder prov = + new ProvisioningConfiguration.Builder() + .withDisplayName(config.SSID) + .withCreatorUid(config.creatorUid) + .withLayer2Information(layer2Info) + .withDhcpOptions(convertToInternalDhcpOptions(options)); + if (isUsingMacRandomization) { + // Use EUI64 address generation for link-local IPv6 addresses. + prov.withRandomMacAddress(); + } + if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta) + || isPrimary()) { + // unclear if the native layer will return the correct non-capabilities if APF is + // not supported on secondary interfaces. + prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName)); + } + if (SdkLevel.isAtLeastV()) { + // Set the user dhcp hostname setting. + int hostnameSetting = config.isSendDhcpHostnameEnabled() + ? IIpClient.HOSTNAME_SETTING_SEND + : IIpClient.HOSTNAME_SETTING_DO_NOT_SEND; + int restrictions = mWifiGlobals.getSendDhcpHostnameRestriction(); + // Override the user setting the dhcp hostname restrictions. + if (config.isOpenNetwork()) { + if ((restrictions + & WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN) != 0) { + hostnameSetting = IIpClient.HOSTNAME_SETTING_DO_NOT_SEND; + } + } else { + if ((restrictions + & WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE) != 0) { + hostnameSetting = IIpClient.HOSTNAME_SETTING_DO_NOT_SEND; + } + } + prov.withHostnameSetting(hostnameSetting); + } if (isFilsConnection) { stopIpClient(); if (isUsingStaticIp) { @@ -8130,27 +8258,9 @@ public class ClientModeImpl extends StateMachine implements ClientMode { return false; } setConfigurationsPriorToIpClientProvisioning(config); - final ProvisioningConfiguration.Builder prov = - new ProvisioningConfiguration.Builder() - .withPreDhcpAction() - .withPreconnection() - .withDisplayName(config.SSID) - .withCreatorUid(config.creatorUid) - .withLayer2Information(layer2Info) - .withProvisioningTimeoutMs(mRemainConnectedAfterIpProvisionTimeout ? 0 : - PROVISIONING_TIMEOUT_FILS_CONNECTION_MS); - if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta) - || isPrimary()) { - // unclear if the native layer will return the correct non-capabilities if APF is - // not supported on secondary interfaces. - prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName)); - } - if (isUsingMacRandomization) { - // Use EUI64 address generation for link-local IPv6 addresses. - prov.withRandomMacAddress(); - } - prov.withDhcpOptions(convertToInternalDhcpOptions(options)); - mIpClient.startProvisioning(prov.build()); + prov.withPreconnection() + .withPreDhcpAction() + .withProvisioningTimeoutMs(PROVISIONING_TIMEOUT_FILS_CONNECTION_MS); } else { sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR); // We must clear the config BSSID, as the wifi chipset may decide to roam @@ -8168,56 +8278,36 @@ public class ClientModeImpl extends StateMachine implements ClientMode { // CONNECTED. stopDhcpSetup(); setConfigurationsPriorToIpClientProvisioning(config); - ScanResult scanResult = getScanResultInternal(config); - final ProvisioningConfiguration.Builder prov; - ProvisioningConfiguration.ScanResultInfo scanResultInfo = null; - if (scanResult != null) { - final List<ScanResultInfo.InformationElement> ies = - new ArrayList<ScanResultInfo.InformationElement>(); - for (ScanResult.InformationElement ie : scanResult.getInformationElements()) { - ScanResultInfo.InformationElement scanResultInfoIe = - new ScanResultInfo.InformationElement(ie.getId(), ie.getBytes()); - ies.add(scanResultInfoIe); - } - scanResultInfo = new ProvisioningConfiguration.ScanResultInfo(scanResult.SSID, - scanResult.BSSID, ies); - } final Network network = (mNetworkAgent != null) ? mNetworkAgent.getNetwork() : null; + prov.withNetwork(network); if (!isUsingStaticIp) { - prov = new ProvisioningConfiguration.Builder() - .withPreDhcpAction() - .withNetwork(network) - .withDisplayName(config.SSID) - .withScanResultInfo(scanResultInfo) - .withCreatorUid(config.creatorUid) - .withLayer2Information(layer2Info); + ProvisioningConfiguration.ScanResultInfo scanResultInfo = null; + ScanResult scanResult = getScanResultInternal(config); + if (scanResult != null) { + final List<ScanResultInfo.InformationElement> ies = + new ArrayList<ScanResultInfo.InformationElement>(); + for (ScanResult.InformationElement ie : scanResult.getInformationElements()) { + ScanResultInfo.InformationElement scanResultInfoIe = + new ScanResultInfo.InformationElement(ie.getId(), ie.getBytes()); + ies.add(scanResultInfoIe); + } + scanResultInfo = new ProvisioningConfiguration.ScanResultInfo(scanResult.SSID, + scanResult.BSSID, ies); + } + prov.withScanResultInfo(scanResultInfo) + .withPreDhcpAction(); } else { StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration(); - prov = new ProvisioningConfiguration.Builder() - .withStaticConfiguration(staticIpConfig) - .withNetwork(network) - .withDisplayName(config.SSID) - .withCreatorUid(config.creatorUid) - .withLayer2Information(layer2Info); - } - if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta) - || isPrimary()) { - // unclear if the native layer will return the correct non-capabilities if APF is - // not supported on secondary interfaces. - prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName)); - } - if (isUsingMacRandomization) { - // Use EUI64 address generation for link-local IPv6 addresses. - prov.withRandomMacAddress(); + prov.withStaticConfiguration(staticIpConfig) + .withoutIpReachabilityMonitor(); } - prov.withDhcpOptions(convertToInternalDhcpOptions(options)); - if (mRemainConnectedAfterIpProvisionTimeout) { - prov.withProvisioningTimeoutMs(0); - } - mIpClient.startProvisioning(prov.build()); } - + if (mContext.getResources().getBoolean( + R.bool.config_wifiRemainConnectedAfterIpProvisionTimeout)) { + prov.withProvisioningTimeoutMs(0); + } + mIpClient.startProvisioning(prov.build()); return true; } @@ -8372,7 +8462,8 @@ public class ClientModeImpl extends StateMachine implements ClientMode { Log.v(TAG, "Idle mode changed: iface " + mInterfaceName + " enabling roaming"); } - enableRoaming(true); + mWifiInjector.getWifiRoamingModeManager().applyWifiRoamingMode( + mInterfaceName, mWifiInfo.getSSID()); } @Override diff --git a/service/java/com/android/server/wifi/ConcreteClientModeManager.java b/service/java/com/android/server/wifi/ConcreteClientModeManager.java index 79ea6e825a..3864262b56 100644 --- a/service/java/com/android/server/wifi/ConcreteClientModeManager.java +++ b/service/java/com/android/server/wifi/ConcreteClientModeManager.java @@ -475,6 +475,10 @@ public class ConcreteClientModeManager implements ClientModeManager { * Get deferring time before turning off WiFi. */ private int getWifiOffDeferringTimeMs() { + if (mRole != ROLE_CLIENT_PRIMARY && !isSecondaryInternet()) { + Log.d(getTag(), "Do not defer stop for non-internet providing CMMs"); + return 0; + } SubscriptionManager subscriptionManager = mContext.getSystemService(SubscriptionManager.class); if (subscriptionManager == null) { @@ -965,7 +969,7 @@ public class ConcreteClientModeManager implements ClientModeManager { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ConcreteClientModeManager.class.getSimpleName() + "." + IdleState.class.getSimpleName() + "." + getWhatToString(what); @@ -1044,7 +1048,7 @@ public class ConcreteClientModeManager implements ClientModeManager { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ConcreteClientModeManager.class.getSimpleName() + "." + StartedState.class.getSimpleName() + "." + getWhatToString(what); @@ -1170,7 +1174,7 @@ public class ConcreteClientModeManager implements ClientModeManager { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ConcreteClientModeManager.class.getSimpleName() + "." + ScanOnlyModeState.class.getSimpleName() + "." + getWhatToString(what); @@ -1242,7 +1246,7 @@ public class ConcreteClientModeManager implements ClientModeManager { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return ConcreteClientModeManager.class.getSimpleName() + "." + ConnectModeState.class.getSimpleName() + "." + getWhatToString(what); @@ -1376,8 +1380,8 @@ public class ConcreteClientModeManager implements ClientModeManager { @Override public void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, - int callingUid, @NonNull String packageName) { - getClientMode().connectNetwork(result, wrapper, callingUid, packageName); + int callingUid, @NonNull String packageName, @Nullable String attributionTag) { + getClientMode().connectNetwork(result, wrapper, callingUid, packageName, attributionTag); } @Override diff --git a/service/java/com/android/server/wifi/ConnectHelper.java b/service/java/com/android/server/wifi/ConnectHelper.java index 50110a93bf..f9a2e09421 100644 --- a/service/java/com/android/server/wifi/ConnectHelper.java +++ b/service/java/com/android/server/wifi/ConnectHelper.java @@ -17,6 +17,7 @@ package com.android.server.wifi; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.wifi.WifiManager; import android.util.Log; @@ -46,10 +47,10 @@ public class ConnectHelper { public void connectToNetwork( @NonNull NetworkUpdateResult result, @NonNull ActionListenerWrapper wrapper, - int callingUid, @NonNull String packageName) { + int callingUid, @NonNull String packageName, @Nullable String attributionTag) { connectToNetwork( mActiveModeWarden.getPrimaryClientModeManager(), result, wrapper, callingUid, - packageName); + packageName, attributionTag); } /** @@ -60,14 +61,15 @@ public class ConnectHelper { @NonNull ClientModeManager clientModeManager, @NonNull NetworkUpdateResult result, @NonNull ActionListenerWrapper wrapper, - int callingUid, @NonNull String packageName) { + int callingUid, @NonNull String packageName, @Nullable String attributionTag) { int netId = result.getNetworkId(); if (mWifiConfigManager.getConfiguredNetwork(netId) == null) { Log.e(TAG, "connectToNetwork Invalid network Id=" + netId); wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR); return; } - mWifiConfigManager.updateBeforeConnect(netId, callingUid, packageName); - clientModeManager.connectNetwork(result, wrapper, callingUid, packageName); + mWifiConfigManager.updateBeforeConnect(netId, callingUid, packageName, + !ClientModeImpl.ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE.equals(attributionTag)); + clientModeManager.connectNetwork(result, wrapper, callingUid, packageName, attributionTag); } } diff --git a/service/java/com/android/server/wifi/DppManager.java b/service/java/com/android/server/wifi/DppManager.java index 8ef3ce19ef..76a8f63e54 100644 --- a/service/java/com/android/server/wifi/DppManager.java +++ b/service/java/com/android/server/wifi/DppManager.java @@ -1078,7 +1078,7 @@ public class DppManager { private void logd(String message) { if (mVerboseLoggingEnabled) { - Log.d(TAG, message); + Log.d(TAG, message, null); } } diff --git a/service/java/com/android/server/wifi/ExternalScoreUpdateObserverProxy.java b/service/java/com/android/server/wifi/ExternalScoreUpdateObserverProxy.java index 5aa44e48b2..9936bd0531 100644 --- a/service/java/com/android/server/wifi/ExternalScoreUpdateObserverProxy.java +++ b/service/java/com/android/server/wifi/ExternalScoreUpdateObserverProxy.java @@ -74,7 +74,7 @@ public class ExternalScoreUpdateObserverProxy extends IScoreUpdateObserver.Stub private void incrementAndMaybeLogWtf(String message) { mCountNullCallback++; if (mCountNullCallback >= MAX_NULL_CALLBACK_TRIGGER_WTF) { - Log.wtf(TAG, message); + Log.wtf(TAG, message, null); } } diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java index 3e950d9fea..b1b77813a8 100644 --- a/service/java/com/android/server/wifi/HalDeviceManager.java +++ b/service/java/com/android/server/wifi/HalDeviceManager.java @@ -181,6 +181,13 @@ public class HalDeviceManager { } /** + * Returns whether or not the concurrency combo is loaded from the driver. + */ + public boolean isConcurrencyComboLoadedFromDriver() { + return mIsConcurrencyComboLoadedFromDriver; + } + + /** * Enables verbose logging. */ public void enableVerboseLogging(boolean verboseEnabled) { diff --git a/service/java/com/android/server/wifi/HostapdHalAidlImp.java b/service/java/com/android/server/wifi/HostapdHalAidlImp.java index b4a95d5cea..ffca0c3526 100644 --- a/service/java/com/android/server/wifi/HostapdHalAidlImp.java +++ b/service/java/com/android/server/wifi/HostapdHalAidlImp.java @@ -33,6 +33,7 @@ import android.hardware.wifi.hostapd.Ieee80211ReasonCode; import android.hardware.wifi.hostapd.IfaceParams; import android.hardware.wifi.hostapd.NetworkParams; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration.BandType; @@ -397,10 +398,13 @@ public class HostapdHalAidlImp implements IHostapdHal { try { SoftApHalCallback callback = mSoftApHalCallbacks.get(info.ifaceName); if (callback != null) { + List<OuiKeyedData> vendorData = isServiceVersionAtLeast(2) + ? HalAidlUtil.halToFrameworkOuiKeyedDataList(info.vendorData) + : Collections.emptyList(); callback.onInfoChanged(info.apIfaceInstance, info.freqMhz, mapHalChannelBandwidthToSoftApInfo(info.channelBandwidth), mapHalGenerationToWifiStandard(info.generation), - MacAddress.fromBytes(info.apIfaceInstanceMacAddress)); + MacAddress.fromBytes(info.apIfaceInstanceMacAddress), vendorData); } mActiveInstances.add(info.apIfaceInstance); } catch (IllegalArgumentException iae) { diff --git a/service/java/com/android/server/wifi/HostapdHalHidlImp.java b/service/java/com/android/server/wifi/HostapdHalHidlImp.java index 48b513134c..1dc63f03dd 100644 --- a/service/java/com/android/server/wifi/HostapdHalHidlImp.java +++ b/service/java/com/android/server/wifi/HostapdHalHidlImp.java @@ -1278,7 +1278,8 @@ public class HostapdHalHidlImp implements IHostapdHal { callback.onInfoChanged(apIfaceInstance, frequency, mapHalBandwidthToSoftApInfo(bandwidth), mapHalGenerationToWifiStandard(generation), - MacAddress.fromBytes(apIfaceInstanceMacAddress)); + MacAddress.fromBytes(apIfaceInstanceMacAddress), + Collections.emptyList()); } } catch (IllegalArgumentException iae) { Log.e(TAG, " Invalid apIfaceInstanceMacAddress, " + iae); diff --git a/service/java/com/android/server/wifi/ISupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/ISupplicantStaIfaceHal.java index f4dc94a2b5..6796b2e904 100644 --- a/service/java/com/android/server/wifi/ISupplicantStaIfaceHal.java +++ b/service/java/com/android/server/wifi/ISupplicantStaIfaceHal.java @@ -19,6 +19,7 @@ package com.android.server.wifi; import android.annotation.NonNull; import android.net.MacAddress; +import android.net.wifi.MscsParams; import android.net.wifi.QosPolicyParams; import android.net.wifi.SecurityParams; import android.net.wifi.WifiConfiguration; @@ -729,7 +730,10 @@ interface ISupplicantStaIfaceHal { * @param isEnabled true if the feature is enabled, false otherwise. * @return true if operation is successful, false otherwise. */ - boolean setNetworkCentricQosPolicyFeatureEnabled(@NonNull String ifaceName, boolean isEnabled); + default boolean setNetworkCentricQosPolicyFeatureEnabled( + @NonNull String ifaceName, boolean isEnabled) { + return false; + } /** * Sends a QoS policy response. @@ -740,15 +744,20 @@ interface ISupplicantStaIfaceHal { * @param qosPolicyStatusList List of framework QosPolicyStatus objects. * @return true if response is sent successfully, false otherwise. */ - boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId, boolean morePolicies, - @NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList); + default boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId, + boolean morePolicies, + @NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList) { + return false; + } /** * Indicates the removal of all active QoS policies configured by the AP. * * @param ifaceName Name of the interface. */ - boolean removeAllQosPolicies(String ifaceName); + default boolean removeAllQosPolicies(String ifaceName) { + return false; + } /** * Send a set of QoS SCS policy add requests to the AP. @@ -763,8 +772,10 @@ interface ISupplicantStaIfaceHal { * Status code will be one of * {@link SupplicantStaIfaceHal.QosPolicyScsRequestStatusCode}. */ - List<SupplicantStaIfaceHal.QosPolicyStatus> addQosPolicyRequestForScs( - @NonNull String ifaceName, @NonNull List<QosPolicyParams> policies); + default List<SupplicantStaIfaceHal.QosPolicyStatus> addQosPolicyRequestForScs( + @NonNull String ifaceName, @NonNull List<QosPolicyParams> policies) { + return null; + } /** * Request the removal of specific QoS policies for SCS. @@ -779,8 +790,10 @@ interface ISupplicantStaIfaceHal { * Status code will be one of * {@link SupplicantStaIfaceHal.QosPolicyScsRequestStatusCode}. */ - List<SupplicantStaIfaceHal.QosPolicyStatus> removeQosPolicyForScs( - @NonNull String ifaceName, @NonNull List<Byte> policyIds); + default List<SupplicantStaIfaceHal.QosPolicyStatus> removeQosPolicyForScs( + @NonNull String ifaceName, @NonNull List<Byte> policyIds) { + return null; + } /** * Register a callback to receive notifications for QoS SCS transactions. @@ -788,7 +801,8 @@ interface ISupplicantStaIfaceHal { * * @param callback {@link SupplicantStaIfaceHal.QosScsResponseCallback} to register. */ - void registerQosScsResponseCallback(SupplicantStaIfaceHal.QosScsResponseCallback callback); + default void registerQosScsResponseCallback( + SupplicantStaIfaceHal.QosScsResponseCallback callback) {} /** * Generate DPP credential for network access @@ -798,8 +812,10 @@ interface ISupplicantStaIfaceHal { * @param privEcKey Private EC Key for DPP Configurator * Returns true when operation is successful. On error, false is returned. */ - boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid, - byte[] privEcKey); + default boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid, + byte[] privEcKey) { + return false; + } /** * Set the currently configured network's anonymous identity. @@ -809,6 +825,31 @@ interface ISupplicantStaIfaceHal { * @param updateToNativeService write the data to the native service. * @return true if succeeds, false otherwise. */ - boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity, - boolean updateToNativeService); + default boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity, + boolean updateToNativeService) { + return false; + } + + /** + * Enable Mirrored Stream Classification Service (MSCS) and configure using + * the provided configuration values. + * + * @param mscsParams {@link MscsParams} object containing the configuration parameters. + * @param ifaceName Name of the interface. + */ + default void enableMscs(@NonNull MscsParams mscsParams, String ifaceName) {} + + /** + * Resend the previously configured MSCS parameters on this interface, if any exist. + * + * @param ifaceName Name of the interface. + */ + default void resendMscs(String ifaceName) {}; + + /** + * Disable Mirrored Stream Classification Service (MSCS). + * + * @param ifaceName Name of the interface. + */ + default void disableMscs(String ifaceName) {} } diff --git a/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java b/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java index 38e5d34e7f..f80f0ae186 100644 --- a/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java +++ b/service/java/com/android/server/wifi/InsecureEapNetworkHandler.java @@ -383,6 +383,18 @@ public class InsecureEapNetworkHandler { Log.d(TAG, cert.getSubjectX500Principal().getName()); } + if (null == mPendingServerCertSubjectInfo) { + handleError(mCurrentTofuConfig.SSID); + Log.d(TAG, "No valid subject info in Server cert for TLS-based connection."); + return false; + } + + if (null == mPendingServerCertIssuerInfo) { + handleError(mCurrentTofuConfig.SSID); + Log.d(TAG, "No valid issuer info in Server cert for TLS-based connection."); + return false; + } + if (!configureServerValidationMethod()) { Log.e(TAG, "Server cert chain is invalid."); String ssid = mCurrentTofuConfig.SSID; @@ -987,7 +999,7 @@ public class InsecureEapNetworkHandler { } } catch (Exception e) { // Fall through - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } // The certificate is not in the trust store. return false; diff --git a/service/java/com/android/server/wifi/InterfaceConflictManager.java b/service/java/com/android/server/wifi/InterfaceConflictManager.java index dd23ac9569..21c0463d02 100644 --- a/service/java/com/android/server/wifi/InterfaceConflictManager.java +++ b/service/java/com/android/server/wifi/InterfaceConflictManager.java @@ -523,7 +523,7 @@ public class InterfaceConflictManager { private void localLog(String log) { mLocalLog.log(log); if (mVerboseLoggingEnabled) { - Log.d(TAG, log); + Log.d(TAG, log, null); } } diff --git a/service/java/com/android/server/wifi/LogcatLog.java b/service/java/com/android/server/wifi/LogcatLog.java index 32341ac854..a813ad65f4 100644 --- a/service/java/com/android/server/wifi/LogcatLog.java +++ b/service/java/com/android/server/wifi/LogcatLog.java @@ -92,48 +92,48 @@ class LogcatLog implements WifiLog { @Override public void eC(String msg) { - Log.e(mTag, msg); + Log.e(mTag, msg, null); } @Override public void wC(String msg) { - Log.w(mTag, msg); + Log.w(mTag, msg, null); } @Override public void iC(String msg) { - Log.i(mTag, msg); + Log.i(mTag, msg, null); } @Override public void tC(String msg) { - Log.d(mTag, msg); + Log.d(mTag, msg, null); } /* Legacy methods */ @Override public void e(String msg) { - Log.e(mTag, msg); + Log.e(mTag, msg, null); } @Override public void w(String msg) { - Log.w(mTag, msg); + Log.w(mTag, msg, null); } @Override public void i(String msg) { - Log.i(mTag, msg); + Log.i(mTag, msg, null); } @Override public void d(String msg) { - Log.d(mTag, msg); + Log.d(mTag, msg, null); } @Override public void v(String msg) { - Log.v(mTag, msg); + Log.v(mTag, msg, null); } /* Internal details */ diff --git a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java index 6a02b17476..bcee442fb9 100644 --- a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java +++ b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java @@ -20,6 +20,7 @@ import static com.android.server.wifi.WifiNetworkSelector.toNetworkString; import android.annotation.NonNull; import android.net.wifi.WifiConfiguration; +import android.os.Process; import android.telephony.TelephonyManager; import android.util.LocalLog; import android.util.Log; @@ -161,7 +162,8 @@ public class NetworkSuggestionNominator implements WifiNetworkSelector.NetworkNo if (!untrustedNetworkAllowed && !config.trusted) { return true; } - if (!restrictedNetworkAllowedUids.contains(config.creatorUid) && config.restricted) { + if (!(restrictedNetworkAllowedUids.contains(config.creatorUid) + || config.creatorUid == Process.SYSTEM_UID) && config.restricted) { return true; } // For suggestions with both oem paid & oem private set, ignore them If both oem paid diff --git a/service/java/com/android/server/wifi/PmkCacheManager.java b/service/java/com/android/server/wifi/PmkCacheManager.java index a952870604..adcd54948d 100644 --- a/service/java/com/android/server/wifi/PmkCacheManager.java +++ b/service/java/com/android/server/wifi/PmkCacheManager.java @@ -22,6 +22,7 @@ import android.os.Handler; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; @@ -39,6 +40,10 @@ public class PmkCacheManager { private final Handler mEventHandler; private boolean mVerboseLoggingEnabled = false; + + private final Object mLock = new Object(); + + @GuardedBy("mLock") private SparseArray<List<PmkCacheStoreData>> mPmkCacheEntries = new SparseArray<>(); public PmkCacheManager(Clock clock, Handler eventHandler) { @@ -58,63 +63,71 @@ public class PmkCacheManager { */ public boolean add(MacAddress macAddress, int networkId, MacAddress bssid, long expirationTimeInSec, ArrayList<Byte> serializedEntry) { - if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return false; - if (macAddress == null) { - Log.w(TAG, "Omit PMK cache due to no valid MAC address"); - return false; - } - if (null == serializedEntry) { - Log.w(TAG, "Omit PMK cache due to null entry."); - return false; - } - final long elapseTimeInSecond = mClock.getElapsedSinceBootMillis() / 1000; - if (elapseTimeInSecond >= expirationTimeInSec) { - Log.w(TAG, "Omit expired PMK cache."); - return false; - } + synchronized (mLock) { + if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return false; + if (macAddress == null) { + Log.w(TAG, "Omit PMK cache due to no valid MAC address"); + return false; + } + if (null == serializedEntry) { + Log.w(TAG, "Omit PMK cache due to null entry."); + return false; + } + final long elapseTimeInSecond = mClock.getElapsedSinceBootMillis() / 1000; + if (elapseTimeInSecond >= expirationTimeInSec) { + Log.w(TAG, "Omit expired PMK cache."); + return false; + } - PmkCacheStoreData newStoreData = - new PmkCacheStoreData(macAddress, bssid, serializedEntry, expirationTimeInSec); - List<PmkCacheStoreData> pmkDataList = mPmkCacheEntries.get(networkId); - if (pmkDataList == null) { - pmkDataList = new ArrayList<>(); - mPmkCacheEntries.put(networkId, pmkDataList); - } else { - if (bssid != null) { - // Remove the stored PMK cache if the PMK cache is changed for an existing BSSID. - PmkCacheStoreData existStoreData = pmkDataList.stream() - .filter(storeData -> Objects.equals(storeData.bssid, bssid)) - .findAny() - .orElse(null); - if (null != existStoreData) { - if (Objects.equals(existStoreData, newStoreData)) { + PmkCacheStoreData newStoreData = + new PmkCacheStoreData(macAddress, bssid, serializedEntry, expirationTimeInSec); + List<PmkCacheStoreData> pmkDataList = mPmkCacheEntries.get(networkId); + if (pmkDataList == null) { + pmkDataList = new ArrayList<>(); + mPmkCacheEntries.put(networkId, pmkDataList); + } else { + PmkCacheStoreData existStoreData = null; + if (bssid != null) { + // Remove the stored PMK cache if the PMK cache is changed for an existing + // BSSID. + for (PmkCacheStoreData storeData : pmkDataList) { + if (Objects.equals(storeData.bssid, bssid)) { + existStoreData = storeData; + break; + } + } + if (null != existStoreData) { + if (Objects.equals(existStoreData, newStoreData)) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "PMK entry exists for the BSSID, skip it."); + } + return true; + } + pmkDataList.remove(existStoreData); + } + } else { + for (PmkCacheStoreData storeData : pmkDataList) { + if (Objects.equals(storeData, newStoreData)) { + existStoreData = storeData; + break; + } + } + if (null != existStoreData) { if (mVerboseLoggingEnabled) { - Log.d(TAG, "PMK entry exists for the BSSID, skip it."); + Log.d(TAG, "PMK entry exists, skip it."); } return true; } - pmkDataList.remove(existStoreData); - } - } else { - PmkCacheStoreData existStoreData = pmkDataList.stream() - .filter(storeData -> Objects.equals(storeData, newStoreData)) - .findAny() - .orElse(null); - if (null != existStoreData) { - if (mVerboseLoggingEnabled) { - Log.d(TAG, "PMK entry exists, skip it."); - } - return true; } } - } - pmkDataList.add(newStoreData); - if (mVerboseLoggingEnabled) { - Log.d(TAG, "Network " + networkId + " PmkCache Count: " + pmkDataList.size()); + pmkDataList.add(newStoreData); + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Network " + networkId + " PmkCache Count: " + pmkDataList.size()); + } + updatePmkCacheExpiration(); + return true; } - updatePmkCacheExpiration(); - return true; } /** @@ -124,12 +137,14 @@ public class PmkCacheManager { * @return true when PMK caches are removed; otherwise, false. */ public boolean remove(int networkId) { - if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return false; - if (!mPmkCacheEntries.contains(networkId)) return false; + synchronized (mLock) { + if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return false; + if (!mPmkCacheEntries.contains(networkId)) return false; - mPmkCacheEntries.remove(networkId); - updatePmkCacheExpiration(); - return true; + mPmkCacheEntries.remove(networkId); + updatePmkCacheExpiration(); + return true; + } } /** @@ -142,16 +157,18 @@ public class PmkCacheManager { */ public boolean remove(int networkId, MacAddress curMacAddress) { - if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return false; - List<PmkCacheStoreData> pmkDataList = mPmkCacheEntries.get(networkId); - if (null == pmkDataList) return false; + synchronized (mLock) { + if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return false; + List<PmkCacheStoreData> pmkDataList = mPmkCacheEntries.get(networkId); + if (null == pmkDataList) return false; - pmkDataList.removeIf(pmkData -> !Objects.equals(curMacAddress, pmkData.macAddress)); + pmkDataList.removeIf(pmkData -> !Objects.equals(curMacAddress, pmkData.macAddress)); - if (pmkDataList.size() == 0) { - remove(networkId); + if (pmkDataList.size() == 0) { + remove(networkId); + } + return true; } - return true; } /** @@ -162,18 +179,20 @@ public class PmkCacheManager { * If none of PMK cache is associated with the network ID, return null. */ public List<ArrayList<Byte>> get(int networkId) { - List<PmkCacheStoreData> pmkDataList = mPmkCacheEntries.get(networkId); - if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return null; - if (null == pmkDataList) return null; - - final long elapseTimeInSecond = mClock.getElapsedSinceBootMillis() / 1000; - List<ArrayList<Byte>> dataList = new ArrayList<>(); - for (PmkCacheStoreData pmkData: pmkDataList) { - if (pmkData.isValid(elapseTimeInSecond)) { - dataList.add(pmkData.data); + synchronized (mLock) { + List<PmkCacheStoreData> pmkDataList = mPmkCacheEntries.get(networkId); + if (WifiConfiguration.INVALID_NETWORK_ID == networkId) return null; + if (null == pmkDataList) return null; + + final long elapseTimeInSecond = mClock.getElapsedSinceBootMillis() / 1000; + List<ArrayList<Byte>> dataList = new ArrayList<>(); + for (PmkCacheStoreData pmkData : pmkDataList) { + if (pmkData.isValid(elapseTimeInSecond)) { + dataList.add(pmkData.data); + } } + return dataList; } - return dataList; } /** @@ -185,46 +204,48 @@ public class PmkCacheManager { @VisibleForTesting void updatePmkCacheExpiration() { - mEventHandler.removeCallbacksAndMessages(PMK_CACHE_EXPIRATION_ALARM_TAG); - - long elapseTimeInSecond = mClock.getElapsedSinceBootMillis() / 1000; - long nextUpdateTimeInSecond = Long.MAX_VALUE; - if (mVerboseLoggingEnabled) { - Log.d(TAG, "Update PMK cache expiration at " + elapseTimeInSecond); - } + synchronized (mLock) { + mEventHandler.removeCallbacksAndMessages(PMK_CACHE_EXPIRATION_ALARM_TAG); - List<Integer> emptyStoreDataList = new ArrayList<>(); - for (int i = 0; i < mPmkCacheEntries.size(); i++) { - int networkId = mPmkCacheEntries.keyAt(i); - List<PmkCacheStoreData> list = mPmkCacheEntries.get(networkId); - list.removeIf(pmkData -> !pmkData.isValid(elapseTimeInSecond)); - if (list.size() == 0) { - emptyStoreDataList.add(networkId); - continue; + long elapseTimeInSecond = mClock.getElapsedSinceBootMillis() / 1000; + long nextUpdateTimeInSecond = Long.MAX_VALUE; + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Update PMK cache expiration at " + elapseTimeInSecond); } - for (PmkCacheStoreData pmkData: list) { - if (nextUpdateTimeInSecond > pmkData.expirationTimeInSec) { - nextUpdateTimeInSecond = pmkData.expirationTimeInSec; + + List<Integer> emptyStoreDataList = new ArrayList<>(); + for (int i = 0; i < mPmkCacheEntries.size(); i++) { + int networkId = mPmkCacheEntries.keyAt(i); + List<PmkCacheStoreData> list = mPmkCacheEntries.get(networkId); + list.removeIf(pmkData -> !pmkData.isValid(elapseTimeInSecond)); + if (list.size() == 0) { + emptyStoreDataList.add(networkId); + continue; + } + for (PmkCacheStoreData pmkData : list) { + if (nextUpdateTimeInSecond > pmkData.expirationTimeInSec) { + nextUpdateTimeInSecond = pmkData.expirationTimeInSec; + } } } - } - emptyStoreDataList.forEach(networkId -> mPmkCacheEntries.remove(networkId)); + emptyStoreDataList.forEach(networkId -> mPmkCacheEntries.remove(networkId)); - // No need to arrange next update since there is no valid PMK in the cache. - if (nextUpdateTimeInSecond == Long.MAX_VALUE) { - return; - } + // No need to arrange next update since there is no valid PMK in the cache. + if (nextUpdateTimeInSecond == Long.MAX_VALUE) { + return; + } - if (mVerboseLoggingEnabled) { - Log.d(TAG, "PMK cache next expiration time: " + nextUpdateTimeInSecond); + if (mVerboseLoggingEnabled) { + Log.d(TAG, "PMK cache next expiration time: " + nextUpdateTimeInSecond); + } + long delayedTimeInMs = (nextUpdateTimeInSecond - elapseTimeInSecond) * 1000; + mEventHandler.postDelayed( + () -> { + updatePmkCacheExpiration(); + }, + PMK_CACHE_EXPIRATION_ALARM_TAG, + (delayedTimeInMs > 0) ? delayedTimeInMs : 0); } - long delayedTimeInMs = (nextUpdateTimeInSecond - elapseTimeInSecond) * 1000; - mEventHandler.postDelayed( - () -> { - updatePmkCacheExpiration(); - }, - PMK_CACHE_EXPIRATION_ALARM_TAG, - (delayedTimeInMs > 0) ? delayedTimeInMs : 0); } private static class PmkCacheStoreData { diff --git a/service/java/com/android/server/wifi/RestrictedWifiNetworkFactory.java b/service/java/com/android/server/wifi/RestrictedWifiNetworkFactory.java index 8ef248e03c..2dda1471a6 100644 --- a/service/java/com/android/server/wifi/RestrictedWifiNetworkFactory.java +++ b/service/java/com/android/server/wifi/RestrictedWifiNetworkFactory.java @@ -16,14 +16,18 @@ package com.android.server.wifi; +import android.annotation.TargetApi; import android.content.Context; import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; +import android.os.Build; import android.os.Looper; import android.util.ArraySet; import android.util.Log; +import com.android.modules.utils.build.SdkLevel; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Set; @@ -38,15 +42,27 @@ public class RestrictedWifiNetworkFactory extends NetworkFactory { private final WifiConnectivityManager mWifiConnectivityManager; private Set<Integer> mRequestUids = new ArraySet<>(); + private final NetworkCapabilities mCapabilitiesFilter; public RestrictedWifiNetworkFactory(Looper l, Context c, NetworkCapabilities f, WifiConnectivityManager connectivityManager) { super(l, c, TAG, f); mWifiConnectivityManager = connectivityManager; - + mCapabilitiesFilter = f; setScoreFilter(SCORE_FILTER); } + // package-private + @TargetApi(Build.VERSION_CODES.S) + void updateSubIdsInCapabilitiesFilter(Set<Integer> subIds) { + if (SdkLevel.isAtLeastS()) { + NetworkCapabilities newFilter = + new NetworkCapabilities.Builder(mCapabilitiesFilter) + .setSubscriptionIds(subIds).build(); + setCapabilityFilter(newFilter); + } + } + @Override protected void needNetworkFor(NetworkRequest networkRequest) { if (!networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { diff --git a/service/java/com/android/server/wifi/RunnerHandler.java b/service/java/com/android/server/wifi/RunnerHandler.java index 2456cf1986..78b7b12a4f 100644 --- a/service/java/com/android/server/wifi/RunnerHandler.java +++ b/service/java/com/android/server/wifi/RunnerHandler.java @@ -42,7 +42,7 @@ import java.util.Set; public class RunnerHandler extends Handler { private static final String TAG = "WifiThreadRunner"; - private static final String KEY_SIGNATURE = "KEY_RUNNER_HANDLER_SIGNATURE"; + public static final String KEY_SIGNATURE = "KEY_RUNNER_HANDLER_SIGNATURE"; private static final String KEY_WHEN = "KEY_RUNNER_HANDLER_WHEN"; private static final int METRICS_THRESHOLD_MILLIS = 100; @@ -101,10 +101,12 @@ public class RunnerHandler extends Handler { @Override public boolean sendMessageAtTime(Message msg, long uptimeMillis) { - String signature = getSignature(new Throwable("RunnerHandler:").getStackTrace(), - msg.getCallback()); Bundle bundle = msg.getData(); - bundle.putString(KEY_SIGNATURE, signature); + if (bundle.getString(KEY_SIGNATURE) == null) { + String signature = getSignature(new Throwable("RunnerHandler:").getStackTrace(), + msg.getCallback()); + bundle.putString(KEY_SIGNATURE, signature); + } return super.sendMessageAtTime(msg, uptimeMillis); } diff --git a/service/java/com/android/server/wifi/RunnerState.java b/service/java/com/android/server/wifi/RunnerState.java index 39f842428b..5dbe65c493 100644 --- a/service/java/com/android/server/wifi/RunnerState.java +++ b/service/java/com/android/server/wifi/RunnerState.java @@ -53,7 +53,7 @@ public abstract class RunnerState extends State { * The Runner state Constructor * @param threshold the running time threshold in milliseconds */ - RunnerState(int threshold, @NonNull LocalLog localLog) { + public RunnerState(int threshold, @NonNull LocalLog localLog) { mRunningTimeThresholdInMilliseconds = threshold; mLocalLog = localLog; } @@ -111,22 +111,22 @@ public abstract class RunnerState extends State { /** * Implement this method for State enter process, instead of enter() */ - abstract void enterImpl(); + public abstract void enterImpl(); /** * Implement this method for State exit process, instead of exit() */ - abstract void exitImpl(); + public abstract void exitImpl(); /** - * Implement this method for State message processing, instead of processMessage() + * Implement this method for process message, instead of processMessage() */ - abstract boolean processMessageImpl(Message message); + public abstract boolean processMessageImpl(Message msg); /** * Implement this to translate a message `what` into a readable String * @param what message 'what' field * @return Readable string */ - abstract String getMessageLogRec(int what); + public abstract String getMessageLogRec(int what); } diff --git a/service/java/com/android/server/wifi/ScanDetail.java b/service/java/com/android/server/wifi/ScanDetail.java index fec34ed136..59eb16af85 100644 --- a/service/java/com/android/server/wifi/ScanDetail.java +++ b/service/java/com/android/server/wifi/ScanDetail.java @@ -42,6 +42,7 @@ public class ScanDetail { private volatile NetworkDetail mNetworkDetail; private long mSeen = 0; private byte[] mInformationElementRawData; + private static final ScanResult.Builder sBuilder = new ScanResult.Builder(); /** * Main constructor used when converting from NativeScanResult @@ -59,6 +60,8 @@ public class ScanDetail { int centerFreq1 = ScanResult.UNSPECIFIED; boolean isPasspoint = false; boolean is80211McResponder = false; + boolean isTwtResponder = false; + boolean is11azNtbResponder = false; if (networkDetail != null) { hessid = networkDetail.getHESSID(); anqpDomainId = networkDetail.getAnqpDomainID(); @@ -72,9 +75,23 @@ public class ScanDetail { && networkDetail.isInterworking() && networkDetail.getHSRelease() != null; is80211McResponder = networkDetail.is80211McResponderSupport(); + isTwtResponder = networkDetail.isIndividualTwtSupported(); + is11azNtbResponder = networkDetail.is80211azNtbResponder(); } - mScanResult = new ScanResult(wifiSsid, bssid, hessid, anqpDomainId, osuProviders, caps, - level, frequency, tsf); + sBuilder.clear(); + mScanResult = sBuilder + .setWifiSsid(wifiSsid) + .setBssid(bssid) + .setHessid(hessid) + .setAnqpDomainId(anqpDomainId) + .setOsuProviders(osuProviders) + .setCaps(caps) + .setRssi(level) + .setFrequency(frequency) + .setTsf(tsf) + .setIsTwtResponder(isTwtResponder) + .setIs80211azNtbRTTResponder(is11azNtbResponder) + .build(); mSeen = System.currentTimeMillis(); mScanResult.seen = mSeen; mScanResult.channelWidth = channelWidth; diff --git a/service/java/com/android/server/wifi/ScanRequestProxy.java b/service/java/com/android/server/wifi/ScanRequestProxy.java index 651f487273..c5af30effe 100644 --- a/service/java/com/android/server/wifi/ScanRequestProxy.java +++ b/service/java/com/android/server/wifi/ScanRequestProxy.java @@ -579,7 +579,8 @@ public class ScanRequestProxy { * @param bssid BSSID as string {@link ScanResult#BSSID}. * @return ScanResult for the corresponding bssid if found, null otherwise. */ - public @Nullable ScanResult getScanResult(@NonNull String bssid) { + public @Nullable ScanResult getScanResult(@Nullable String bssid) { + if (bssid == null) return null; ScanResult scanResult = mFullScanCache.get(bssid); if (scanResult == null) { scanResult = mPartialScanCache.get(bssid); diff --git a/service/java/com/android/server/wifi/SelfRecovery.java b/service/java/com/android/server/wifi/SelfRecovery.java index c50ff43240..e7a182e49d 100644 --- a/service/java/com/android/server/wifi/SelfRecovery.java +++ b/service/java/com/android/server/wifi/SelfRecovery.java @@ -138,21 +138,30 @@ public class SelfRecovery { private class SubsystemRestartListenerInternal implements HalDeviceManager.SubsystemRestartListener{ - public void onSubsystemRestart(@RecoveryReason int reason) { + private void onSubsystemRestart(@RecoveryReason int reason, long timeElapsedFromLastTrigger, + int resultForLogging) { Log.e(TAG, "Restarting wifi for reason: " + getRecoveryReasonAsString(reason)); + WifiStatsLog.write(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED, + convertSelfRecoveryReason(reason), + resultForLogging, + timeElapsedFromLastTrigger); mActiveModeWarden.recoveryRestartWifi(reason, reason != REASON_LAST_RESORT_WATCHDOG && reason != REASON_API_CALL); } @Override public void onSubsystemRestart() { + long timeElapsedFromLastTrigger = getTimeElapsedFromLastTrigger(); + mLastSelfRecoveryTimeStampMillis = mClock.getWallClockMillis(); if (mRecoveryState == STATE_RESTART_WIFI) { // If the wifi restart recovery is triggered then proceed - onSubsystemRestart(mSelfRecoveryReason); + onSubsystemRestart(mSelfRecoveryReason, timeElapsedFromLastTrigger, + WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__RESULT__RES_RESTART_STARTED_INTERNAL_RECOVERY_BY_NATIVE_CALLBACK); } else { // We did not trigger recovery, but looks like the firmware crashed? mRecoveryState = STATE_RESTART_WIFI; - onSubsystemRestart(REASON_SUBSYSTEM_RESTART); + onSubsystemRestart(REASON_SUBSYSTEM_RESTART, timeElapsedFromLastTrigger, + WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__RESULT__RES_RESTART_STARTED_INTERNAL_RECOVERY_BY_NATIVE_CALLBACK); } } } @@ -248,11 +257,8 @@ public class SelfRecovery { mRecoveryState = STATE_RESTART_WIFI; if (!mWifiNative.startSubsystemRestart()) { // HAL call failed, fallback to internal flow. - mSubsystemRestartListener.onSubsystemRestart(reason); - WifiStatsLog.write(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED, - convertSelfRecoveryReason(reason), - WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__RESULT__RES_RESTART_FAILURE, - timeElapsedFromLastTrigger); + mSubsystemRestartListener.onSubsystemRestart(reason, timeElapsedFromLastTrigger, + WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__RESULT__RES_RESTART_STARTED_INTERNAL_RECOVERY); return; } WifiStatsLog.write(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED, diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java index c2e89688e5..1d8ab5117a 100644 --- a/service/java/com/android/server/wifi/SoftApManager.java +++ b/service/java/com/android/server/wifi/SoftApManager.java @@ -31,6 +31,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApInfo; +import android.net.wifi.SoftApState; import android.net.wifi.WifiAnnotations; import android.net.wifi.WifiClient; import android.net.wifi.WifiContext; @@ -38,6 +39,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; import android.net.wifi.WifiSsid; +import android.net.wifi.nl80211.DeviceWiphyCapabilities; import android.os.BatteryManager; import android.os.Handler; import android.os.Looper; @@ -314,7 +316,8 @@ public class SoftApManager implements ActiveModeManager { public void onInfoChanged(String apIfaceInstance, int frequency, @WifiAnnotations.Bandwidth int bandwidth, @WifiAnnotations.WifiStandard int generation, - MacAddress apIfaceInstanceMacAddress) { + MacAddress apIfaceInstanceMacAddress, + @NonNull List<OuiKeyedData> vendorData) { SoftApInfo apInfo = new SoftApInfo(); apInfo.setFrequency(frequency); apInfo.setBandwidth(bandwidth); @@ -324,6 +327,9 @@ public class SoftApManager implements ActiveModeManager { } apInfo.setApInstanceIdentifier(apIfaceInstance != null ? apIfaceInstance : mApInterfaceName); + if (SdkLevel.isAtLeastV() && vendorData != null && !vendorData.isEmpty()) { + apInfo.setVendorData(vendorData); + } mStateMachine.sendMessage( SoftApStateMachine.CMD_AP_INFO_CHANGED, 0, 0, apInfo); } @@ -473,7 +479,8 @@ public class SoftApManager implements ActiveModeManager { apConfig.getTargetMode(), mCurrentSoftApConfiguration, mCurrentSoftApCapability, - mCountryCode); + mCountryCode, + apConfig.getTetheringRequest()); if (mCurrentSoftApConfiguration != null) { mIsUnsetBssid = mCurrentSoftApConfiguration.getBssid() == null; if (mCurrentSoftApCapability.areFeaturesSupported( @@ -632,7 +639,8 @@ public class SoftApManager implements ActiveModeManager { mSpecifiedModeConfiguration.getTargetMode(), mSpecifiedModeConfiguration.getSoftApConfiguration(), mCurrentSoftApCapability, - mCountryCode); + mCountryCode, + mSpecifiedModeConfiguration.getTetheringRequest()); } /** @@ -701,7 +709,7 @@ public class SoftApManager implements ActiveModeManager { private void onL2Connected(@NonNull ConcreteClientModeManager clientModeManager) { Log.d(getTag(), "onL2Connected called"); mStateMachine.sendMessage(SoftApStateMachine.CMD_HANDLE_WIFI_CONNECTED, - clientModeManager.getConnectionInfo()); + clientModeManager); } @@ -724,7 +732,11 @@ public class SoftApManager implements ActiveModeManager { */ private void updateApState(int newState, int currentState, int reason) { mCurrentApState = newState; - mSoftApCallback.onStateChanged(newState, reason); + mSoftApCallback.onStateChanged(new SoftApState( + newState, + reason, + mSpecifiedModeConfiguration.getTetheringRequest(), + mApInterfaceName)); //send the AP state change broadcast final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); @@ -739,6 +751,7 @@ public class SoftApManager implements ActiveModeManager { intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, mApInterfaceName); intent.putExtra( WifiManager.EXTRA_WIFI_AP_MODE, mSpecifiedModeConfiguration.getTargetMode()); + if (SdkLevel.isAtLeastSv2()) { mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.ACCESS_WIFI_STATE); @@ -1144,7 +1157,7 @@ public class SoftApManager implements ActiveModeManager { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return SoftApManager.class.getSimpleName() + "." + IdleState.class.getSimpleName() + "." + getWhatToString(what); } @@ -1292,31 +1305,35 @@ public class SoftApManager implements ActiveModeManager { break; } - // Only check if it's possible to create single AP, since a DBS request - // already falls back to single AP if we can't create DBS. - if (!mWifiNative.isItPossibleToCreateApIface(mRequestorWs)) { - handleStartSoftApFailure(START_RESULT_FAILURE_INTERFACE_CONFLICT); - break; - } - if (SdkLevel.isAtLeastT() - && mCurrentSoftApConfiguration.isIeee80211beEnabled() - && !mCurrentSoftApCapability.areFeaturesSupported( - SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE)) { - Log.d(getTag(), "11BE is not supported, removing from configuration"); - mCurrentSoftApConfiguration = new SoftApConfiguration - .Builder(mCurrentSoftApConfiguration) - .setIeee80211beEnabled(false) - .build(); - } mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode( mWifiNativeInterfaceCallback, mRequestorWs, mCurrentSoftApConfiguration.getBand(), isBridgeRequired(), SoftApManager.this, getVendorData()); if (TextUtils.isEmpty(mApInterfaceName)) { Log.e(getTag(), "setup failure when creating ap interface."); - handleStartSoftApFailure(START_RESULT_FAILURE_CREATE_INTERFACE); + // Only check if it's possible to create single AP, since a DBS request + // already falls back to single AP if we can't create DBS. + if (!mWifiNative.isItPossibleToCreateApIface(mRequestorWs)) { + handleStartSoftApFailure(START_RESULT_FAILURE_INTERFACE_CONFLICT); + } else { + handleStartSoftApFailure(START_RESULT_FAILURE_CREATE_INTERFACE); + } break; } + + DeviceWiphyCapabilities capa = + mWifiNative.getDeviceWiphyCapabilities( + mApInterfaceName, isBridgeRequired()); + if (SdkLevel.isAtLeastT() + && mCurrentSoftApConfiguration.isIeee80211beEnabled() + && (capa == null || !capa.isWifiStandardSupported( + ScanResult.WIFI_STANDARD_11BE))) { + Log.d(getTag(), "11BE is not supported, removing from configuration"); + mCurrentSoftApConfiguration = new SoftApConfiguration.Builder( + mCurrentSoftApConfiguration).setIeee80211beEnabled( + false).build(); + } + mSoftApNotifier.dismissSoftApShutdownTimeoutExpiredNotification(); updateApState(WifiManager.WIFI_AP_STATE_ENABLING, WifiManager.WIFI_AP_STATE_DISABLED, 0); @@ -1350,7 +1367,8 @@ public class SoftApManager implements ActiveModeManager { mSpecifiedModeConfiguration.getTargetMode(), newConfig, mCurrentSoftApCapability, - mCountryCode); + mCountryCode, + mSpecifiedModeConfiguration.getTetheringRequest()); Log.d(getTag(), "Configuration changed to " + newConfig); // Idle mode, update all configurations. mCurrentSoftApConfiguration = newConfig; @@ -1383,19 +1401,19 @@ public class SoftApManager implements ActiveModeManager { } @Override - void enterImpl() { + public void enterImpl() { mWifiInjector.getWifiCountryCode().registerListener(mCountryCodeChangeListener); sendMessageDelayed(CMD_DRIVER_COUNTRY_CODE_CHANGE_TIMED_OUT, TIMEOUT_MS); } @Override - void exitImpl() { + public void exitImpl() { mWifiInjector.getWifiCountryCode().unregisterListener(mCountryCodeChangeListener); removeMessages(CMD_DRIVER_COUNTRY_CODE_CHANGE_TIMED_OUT); } @Override - boolean processMessageImpl(Message message) { + public boolean processMessageImpl(Message message) { if (message.what == CMD_DRIVER_COUNTRY_CODE_CHANGED) { if (!TextUtils.equals(mCountryCode, (String) message.obj)) { Log.i(getTag(), "Ignore country code changed: " + message.obj); @@ -1406,7 +1424,7 @@ public class SoftApManager implements ActiveModeManager { mCurrentSoftApCapability.setCountryCode(mCountryCode); mCurrentSoftApCapability = ApConfigUtil.updateSoftApCapabilityWithAvailableChannelList( - mCurrentSoftApCapability, mContext, mWifiNative); + mCurrentSoftApCapability, mContext, mWifiNative, null); updateSafeChannelFrequencyList(); if (isBridgedMode()) { SoftApConfiguration tempConfig = @@ -1455,7 +1473,7 @@ public class SoftApManager implements ActiveModeManager { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return SoftApManager.class.getSimpleName() + "." + RunnerState.class.getSimpleName() + "." + getWhatToString(what); } @@ -1915,7 +1933,7 @@ public class SoftApManager implements ActiveModeManager { } @Override - String getMessageLogRec(int what) { + public String getMessageLogRec(int what) { return SoftApManager.class.getSimpleName() + "." + RunnerState.class.getSimpleName() + "." + getWhatToString(what); } @@ -2070,7 +2088,8 @@ public class SoftApManager implements ActiveModeManager { mSpecifiedModeConfiguration.getTargetMode(), newConfig, mCurrentSoftApCapability, - mCountryCode); + mCountryCode, + mSpecifiedModeConfiguration.getTetheringRequest()); Log.d(getTag(), "Configuration changed to " + newConfig); if (mCurrentSoftApConfiguration.getMaxNumberOfClients() != newConfig.getMaxNumberOfClients()) { @@ -2157,30 +2176,44 @@ public class SoftApManager implements ActiveModeManager { Log.d(getTag(), "Ignore wifi connected in single AP state"); break; } - WifiInfo wifiInfo = (WifiInfo) message.obj; + ConcreteClientModeManager cmm = (ConcreteClientModeManager) message.obj; + String wifiInterface = cmm.getInterfaceName(); + WifiInfo wifiInfo = cmm.getConnectionInfo(); int wifiFreq = wifiInfo.getFrequency(); + int wifiBand = ApConfigUtil.convertFrequencyToBand(wifiFreq); + List<Integer> bands = new ArrayList<Integer>(); + bands.add(wifiBand); String targetShutDownInstance = ""; if (wifiFreq > 0 && !mSafeChannelFrequencyList.contains(wifiFreq)) { Log.i(getTag(), "Wifi connected to freq:" + wifiFreq + " which is unavailable for SAP"); for (SoftApInfo sapInfo : mCurrentSoftApInfoMap.values()) { - if (ApConfigUtil.convertFrequencyToBand(sapInfo.getFrequency()) - == ApConfigUtil.convertFrequencyToBand(wifiFreq)) { + int sapBand = + ApConfigUtil.convertFrequencyToBand(sapInfo.getFrequency()); + if (sapBand == wifiBand) { targetShutDownInstance = sapInfo.getApInstanceIdentifier(); Log.d(getTag(), "Remove the " + targetShutDownInstance + " instance which is running on the same band as " + "the wifi connection on an unsafe channel"); - break; + } else { + bands.add(sapBand); } } // Wifi may connect to different band as the SAP. For instances: // Wifi connect to 6Ghz but bridged AP is running on 2.4Ghz + 5Ghz. - // In this case, targetShutDownInstance will be empty, shutdown the - // highest frequency instance. - removeIfaceInstanceFromBridgedApIface( - TextUtils.isEmpty(targetShutDownInstance) - ? getHighestFrequencyInstance(mCurrentSoftApInfoMap.keySet()) - : targetShutDownInstance); + // In this case, targetShutDownInstance will be empty, check whether + // the chip supports this combination. If not, shutdown the highest + // frequency instance. + if (TextUtils.isEmpty(targetShutDownInstance)) { + // We have to use STA ifacename to query band combinations. + if (!mWifiNative.isBandCombinationSupported(wifiInterface, bands)) { + removeIfaceInstanceFromBridgedApIface( + getHighestFrequencyInstance( + mCurrentSoftApInfoMap.keySet())); + } + } else { + removeIfaceInstanceFromBridgedApIface(targetShutDownInstance); + } } break; case CMD_PLUGGED_STATE_CHANGED: diff --git a/service/java/com/android/server/wifi/SoftApModeConfiguration.java b/service/java/com/android/server/wifi/SoftApModeConfiguration.java index 8cef93eac6..ad279a7ea6 100644 --- a/service/java/com/android/server/wifi/SoftApModeConfiguration.java +++ b/service/java/com/android/server/wifi/SoftApModeConfiguration.java @@ -16,6 +16,7 @@ package com.android.server.wifi; +import android.net.TetheringManager; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiManager; @@ -41,8 +42,14 @@ class SoftApModeConfiguration { */ private final @Nullable SoftApConfiguration mSoftApConfig; + /** + * TetheringRequest for internal use, or null if none was passed in. + */ + private final @Nullable TetheringManager.TetheringRequest mTetheringRequest; + SoftApModeConfiguration(int targetMode, @Nullable SoftApConfiguration config, - SoftApCapability capability, @Nullable String countryCode) { + SoftApCapability capability, @Nullable String countryCode, + @Nullable TetheringManager.TetheringRequest request) { Preconditions.checkArgument( targetMode == WifiManager.IFACE_IP_MODE_TETHERED || targetMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY); @@ -51,6 +58,7 @@ class SoftApModeConfiguration { mSoftApConfig = config; mCapability = capability; mCountryCode = countryCode; + mTetheringRequest = request; } public int getTargetMode() { @@ -68,4 +76,8 @@ class SoftApModeConfiguration { public String getCountryCode() { return mCountryCode; } + + public TetheringManager.TetheringRequest getTetheringRequest() { + return mTetheringRequest; + } } diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java index af82aa0ba6..5f377894cb 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java @@ -329,11 +329,17 @@ class SupplicantStaIfaceCallbackAidlImpl extends ISupplicantStaIfaceCallback.Stu WifiConfiguration curConfiguration = mStaIfaceHal.getCurrentNetworkLocalConfig(mIfaceName); if (curConfiguration != null) { + // In case of PSK networks the disconnection event in the middle of key exchange + // happens due to PSK mismatch. But filter out the de-authentication/disassociation + // frame from AP with known reason codes which are not related to PSK mismatch from + // reporting wrong password error. if (mStateBeforeDisconnect == StaIfaceCallbackState.FOURWAY_HANDSHAKE && (WifiConfigurationUtil.isConfigForPskNetwork(curConfiguration) - || WifiConfigurationUtil.isConfigForWapiPskNetwork(curConfiguration)) - && (!locallyGenerated || reasonCode - != StaIfaceReasonCode.IE_IN_4WAY_DIFFERS)) { + || WifiConfigurationUtil.isConfigForWapiPskNetwork( + curConfiguration)) + && (!locallyGenerated + || (reasonCode != StaIfaceReasonCode.IE_IN_4WAY_DIFFERS + && reasonCode != StaIfaceReasonCode.DISASSOC_AP_BUSY))) { mWifiMonitor.broadcastAuthenticationFailureEvent( mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1, mCurrentSsid, MacAddress.fromBytes(bssid)); @@ -353,35 +359,39 @@ class SupplicantStaIfaceCallbackAidlImpl extends ISupplicantStaIfaceCallback.Stu private void handleAssocRejectEvent(AssocRejectEventInfo assocRejectInfo) { boolean isWrongPwd = false; WifiConfiguration curConfiguration = mStaIfaceHal.getCurrentNetworkLocalConfig(mIfaceName); - if (curConfiguration != null) { - if (!assocRejectInfo.timedOut) { - Log.d(TAG, "flush PMK cache due to association rejection for config id " - + curConfiguration.networkId + "."); - mStaIfaceHal.removePmkCacheEntry(curConfiguration.networkId); - } - if (assocRejectInfo.statusCode - == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL - && WifiConfigurationUtil.isConfigForWepNetwork(curConfiguration)) { - mStaIfaceHal.logCallback("WEP incorrect password"); - isWrongPwd = true; - } else if (assocRejectInfo.statusCode - == SupplicantStaIfaceHal.StaIfaceStatusCode.UNSPECIFIED_FAILURE - || assocRejectInfo.statusCode - == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL) { - // Special handling for WPA3-Personal networks. If the password is - // incorrect, the AP will send association rejection, with status code 1 - // (unspecified failure) or 15 (challenge fail). In SAE networks, the password - // authentication is not related to the 4-way handshake. In this case, we will - // send an authentication failure event up. - // Network Selection status is guaranteed to be initialized - SecurityParams params = curConfiguration.getNetworkSelectionStatus() - .getCandidateSecurityParams(); - if (params != null - && params.getSecurityType() == WifiConfiguration.SECURITY_TYPE_SAE) { - // If this is ever connected, the password should be correct. - isWrongPwd = !curConfiguration.getNetworkSelectionStatus().hasEverConnected(); - if (isWrongPwd) { + if (curConfiguration != null && !assocRejectInfo.timedOut) { + int statusCode = assocRejectInfo.statusCode; + Log.d(TAG, "flush PMK cache due to association rejection for config id " + + curConfiguration.networkId + "."); + mStaIfaceHal.removePmkCacheEntry(curConfiguration.networkId); + // Network Selection status is guaranteed to be initialized. + SecurityParams params = curConfiguration.getNetworkSelectionStatus() + .getCandidateSecurityParams(); + if (params != null) { + if (params.getSecurityType() == WifiConfiguration.SECURITY_TYPE_WEP + && statusCode == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL) { + mStaIfaceHal.logCallback("WEP incorrect password"); + isWrongPwd = true; + } else if (params.getSecurityType() == WifiConfiguration.SECURITY_TYPE_SAE) { + // Special handling for WPA3-Personal networks. In SAE networks, the password + // authentication is not related to the 4-way handshake. If the password is + // incorrect, the HAL will send association rejection, with status code 1 + // (unspecified failure) or 15 (challenge fail). + // As per IEEE80211-2020 specification section - 12.4.7.6, an SAE message that + // was not successfully verified is indicated with a status code of 15. This + // typically happens when the entered password is wrong. So treat status code + // of 15 as incorrect password. + // Some implementations also send status code of 1 for incorrect password. But + // this is a generic status code and can't be treated as incorrect password all + // the time. So treat status code of 1 as incorrect password only if the STA + // was not connected to this network before. In this case, we will + // send an authentication failure event up. + if (statusCode == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL + || (statusCode + == SupplicantStaIfaceHal.StaIfaceStatusCode.UNSPECIFIED_FAILURE + && !curConfiguration.getNetworkSelectionStatus().hasEverConnected())) { mStaIfaceHal.logCallback("SAE incorrect password"); + isWrongPwd = true; } else { mStaIfaceHal.logCallback("SAE association rejection"); } diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackHidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackHidlImpl.java index 3673d7bdcf..da8a38b9e3 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackHidlImpl.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackHidlImpl.java @@ -287,10 +287,17 @@ abstract class SupplicantStaIfaceCallbackHidlImpl extends ISupplicantStaIfaceCal WifiConfiguration curConfiguration = mStaIfaceHal.getCurrentNetworkLocalConfig(mIfaceName); if (curConfiguration != null) { + // In case of PSK networks the disconnection event in the middle of key exchange + // happens due to PSK mismatch. But filter out the de-authentication/disassociation + // frame from AP with known reason codes which are not related to PSK mismatch from + // reporting wrong password error. if (mStateBeforeDisconnect == State.FOURWAY_HANDSHAKE && (WifiConfigurationUtil.isConfigForPskNetwork(curConfiguration) - || WifiConfigurationUtil.isConfigForWapiPskNetwork(curConfiguration)) - && (!locallyGenerated || reasonCode != ReasonCode.IE_IN_4WAY_DIFFERS)) { + || WifiConfigurationUtil.isConfigForWapiPskNetwork( + curConfiguration)) + && (!locallyGenerated + || (reasonCode != ReasonCode.IE_IN_4WAY_DIFFERS + && reasonCode != ReasonCode.DISASSOC_AP_BUSY))) { mWifiMonitor.broadcastAuthenticationFailureEvent( mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1, mCurrentSsid, MacAddress.fromBytes(bssid)); @@ -311,35 +318,39 @@ abstract class SupplicantStaIfaceCallbackHidlImpl extends ISupplicantStaIfaceCal boolean isWrongPwd = false; WifiConfiguration curConfiguration = mStaIfaceHal.getCurrentNetworkLocalConfig(mIfaceName); - if (curConfiguration != null) { - if (!assocRejectInfo.timedOut) { - Log.d(TAG, "flush PMK cache due to association rejection for config id " - + curConfiguration.networkId + "."); - mStaIfaceHal.removePmkCacheEntry(curConfiguration.networkId); - } - if (assocRejectInfo.statusCode - == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL - && WifiConfigurationUtil.isConfigForWepNetwork(curConfiguration)) { - mStaIfaceHal.logCallback("WEP incorrect password"); - isWrongPwd = true; - } else if (assocRejectInfo.statusCode - == SupplicantStaIfaceHal.StaIfaceStatusCode.UNSPECIFIED_FAILURE - || assocRejectInfo.statusCode - == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL) { - // Special handling for WPA3-Personal networks. If the password is - // incorrect, the AP will send association rejection, with status code 1 - // (unspecified failure) or 15 (challenge fail). In SAE networks, the password - // authentication is not related to the 4-way handshake. In this case, we will - // send an authentication failure event up. - // Network Selection status is guaranteed to be initialized - SecurityParams params = curConfiguration.getNetworkSelectionStatus() - .getCandidateSecurityParams(); - if (params != null - && params.getSecurityType() == WifiConfiguration.SECURITY_TYPE_SAE) { - // If this is ever connected, the password should be correct. - isWrongPwd = !curConfiguration.getNetworkSelectionStatus().hasEverConnected(); - if (isWrongPwd) { + if (curConfiguration != null && !assocRejectInfo.timedOut) { + int statusCode = assocRejectInfo.statusCode; + Log.d(TAG, "flush PMK cache due to association rejection for config id " + + curConfiguration.networkId + "."); + mStaIfaceHal.removePmkCacheEntry(curConfiguration.networkId); + // Network Selection status is guaranteed to be initialized. + SecurityParams params = curConfiguration.getNetworkSelectionStatus() + .getCandidateSecurityParams(); + if (params != null) { + if (params.getSecurityType() == WifiConfiguration.SECURITY_TYPE_WEP + && statusCode == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL) { + mStaIfaceHal.logCallback("WEP incorrect password"); + isWrongPwd = true; + } else if (params.getSecurityType() == WifiConfiguration.SECURITY_TYPE_SAE) { + // Special handling for WPA3-Personal networks. In SAE networks, the password + // authentication is not related to the 4-way handshake. If the password is + // incorrect, the HAL will send association rejection, with status code 1 + // (unspecified failure) or 15 (challenge fail). + // As per IEEE80211-2020 specification section - 12.4.7.6, an SAE message that + // was not successfully verified is indicated with a status code of 15. This + // typically happens when the entered password is wrong. So treat status code + // of 15 as incorrect password. + // Some implementations also send status code of 1 for incorrect password. But + // this is a generic status code and can't be treated as incorrect password all + // the time. So treat status code of 1 as incorrect password only if the STA + // was not connected to this network before. In this case, we will + // send an authentication failure event up. + if (statusCode == SupplicantStaIfaceHal.StaIfaceStatusCode.CHALLENGE_FAIL + || (statusCode + == SupplicantStaIfaceHal.StaIfaceStatusCode.UNSPECIFIED_FAILURE + && !curConfiguration.getNetworkSelectionStatus().hasEverConnected())) { mStaIfaceHal.logCallback("SAE incorrect password"); + isWrongPwd = true; } else { mStaIfaceHal.logCallback("SAE association rejection"); } diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java index 8671ecbce5..eb6f4609df 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java @@ -19,6 +19,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.content.Context; import android.net.MacAddress; +import android.net.wifi.MscsParams; import android.net.wifi.QosPolicyParams; import android.net.wifi.SecurityParams; import android.net.wifi.WifiConfiguration; @@ -842,16 +843,22 @@ public class SupplicantStaIfaceHal { } /** + * Check whether the HAL service is using AIDL. + * + * @return true if the AIDL service is being used, false otherwise. + */ + public boolean isAidlService() { + return mStaIfaceHal != null && mStaIfaceHal instanceof SupplicantStaIfaceHalAidlImpl; + } + + /** * Check whether the AIDL service is running at least the expected version. * * @param expectedVersion Version number to check. * @return true if the AIDL service is available and >= the expected version, false otherwise. */ public boolean isAidlServiceVersionAtLeast(int expectedVersion) { - if (mStaIfaceHal == null || mStaIfaceHal instanceof SupplicantStaIfaceHalHidlImpl) { - return false; - } - return ((SupplicantStaIfaceHalAidlImpl) mStaIfaceHal) + return isAidlService() && ((SupplicantStaIfaceHalAidlImpl) mStaIfaceHal) .isServiceVersionAtLeast(expectedVersion); } @@ -2363,6 +2370,42 @@ public class SupplicantStaIfaceHal { updateToNativeService); } + /** + * See comments for {@link ISupplicantStaIfaceHal#enableMscs(MscsParams, String)} + */ + public void enableMscs(@NonNull MscsParams mscsParams, String ifaceName) { + String methodStr = "enableMscs"; + if (mStaIfaceHal == null) { + handleNullHal(methodStr); + return; + } + mStaIfaceHal.enableMscs(mscsParams, ifaceName); + } + + /** + * See comments for {@link ISupplicantStaIfaceHal#resendMscs(String)} + */ + public void resendMscs(String ifaceName) { + String methodStr = "resendMscs"; + if (mStaIfaceHal == null) { + handleNullHal(methodStr); + return; + } + mStaIfaceHal.resendMscs(ifaceName); + } + + /** + * See comments for {@link ISupplicantStaIfaceHal#disableMscs(String)} + */ + public void disableMscs(String ifaceName) { + String methodStr = "disableMscs"; + if (mStaIfaceHal == null) { + handleNullHal(methodStr); + return; + } + mStaIfaceHal.disableMscs(ifaceName); + } + private boolean handleNullHal(String methodStr) { Log.e(TAG, "Cannot call " + methodStr + " because HAL object is null."); return false; diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java index b7050efc2f..ec9a942bda 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java @@ -36,7 +36,7 @@ import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B; import android.annotation.NonNull; import android.content.Context; -import android.hardware.wifi.V1_6.WifiChannelWidthInMhz; +import android.hardware.wifi.WifiChannelWidthInMhz; import android.hardware.wifi.supplicant.BtCoexistenceMode; import android.hardware.wifi.supplicant.ConnectionCapabilities; import android.hardware.wifi.supplicant.DebugLevel; @@ -55,12 +55,18 @@ import android.hardware.wifi.supplicant.IpVersion; import android.hardware.wifi.supplicant.KeyMgmtMask; import android.hardware.wifi.supplicant.LegacyMode; import android.hardware.wifi.supplicant.MloLinksInfo; +import android.hardware.wifi.supplicant.MscsParams.FrameClassifierFields; +import android.hardware.wifi.supplicant.MsduDeliveryInfo; +import android.hardware.wifi.supplicant.MsduDeliveryInfo.DeliveryRatio; import android.hardware.wifi.supplicant.PortRange; +import android.hardware.wifi.supplicant.QosCharacteristics; +import android.hardware.wifi.supplicant.QosCharacteristics.QosCharacteristicsMask; import android.hardware.wifi.supplicant.QosPolicyClassifierParams; import android.hardware.wifi.supplicant.QosPolicyClassifierParamsMask; import android.hardware.wifi.supplicant.QosPolicyData; import android.hardware.wifi.supplicant.QosPolicyRequestType; import android.hardware.wifi.supplicant.QosPolicyScsData; +import android.hardware.wifi.supplicant.QosPolicyScsData.LinkDirection; import android.hardware.wifi.supplicant.QosPolicyScsRequestStatus; import android.hardware.wifi.supplicant.QosPolicyScsRequestStatusCode; import android.hardware.wifi.supplicant.QosPolicyStatus; @@ -74,6 +80,7 @@ import android.hardware.wifi.supplicant.WpsConfigMethods; import android.net.DscpPolicy; import android.net.MacAddress; import android.net.NetworkAgent; +import android.net.wifi.MscsParams; import android.net.wifi.QosPolicyParams; import android.net.wifi.ScanResult; import android.net.wifi.SecurityParams; @@ -94,6 +101,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.mockwifi.MockWifiServiceUtil; +import com.android.server.wifi.util.HalAidlUtil; import com.android.server.wifi.util.NativeUtil; import java.nio.ByteBuffer; @@ -163,6 +171,7 @@ public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal { private CountDownLatch mWaitForDeathLatch; private INonStandardCertCallback mNonStandardCertCallback; private SupplicantStaIfaceHal.QosScsResponseCallback mQosScsResponseCallback; + private MscsParams mLastMscsParams; private class SupplicantDeathRecipient implements DeathRecipient { @Override @@ -2892,11 +2901,107 @@ public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal { hasSrcIp, srcIp, hasDstIp, dstIp, srcPort, dstPortRange, protocol)); } + @VisibleForTesting + protected static byte frameworkToHalDeliveryRatio( + @android.net.wifi.QosCharacteristics.DeliveryRatio int frameworkRatio) { + switch (frameworkRatio) { + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_95: + return DeliveryRatio.RATIO_95; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_96: + return DeliveryRatio.RATIO_96; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_97: + return DeliveryRatio.RATIO_97; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_98: + return DeliveryRatio.RATIO_98; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99: + return DeliveryRatio.RATIO_99; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_9: + return DeliveryRatio.RATIO_99_9; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_99: + return DeliveryRatio.RATIO_99_99; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_999: + return DeliveryRatio.RATIO_99_999; + case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_9999: + return DeliveryRatio.RATIO_99_9999; + default: + Log.e(TAG, "Invalid delivery ratio received: " + frameworkRatio); + return DeliveryRatio.RATIO_95; + } + } + + @VisibleForTesting + protected static byte frameworkToHalPolicyDirection( + @QosPolicyParams.Direction int frameworkDirection) { + switch (frameworkDirection) { + case QosPolicyParams.DIRECTION_UPLINK: + return LinkDirection.UPLINK; + case QosPolicyParams.DIRECTION_DOWNLINK: + return LinkDirection.DOWNLINK; + default: + Log.e(TAG, "Invalid direction received: " + frameworkDirection); + return LinkDirection.DOWNLINK; + } + } + + /** + * Convert from a framework QosCharacteristics to its HAL equivalent. + */ + @VisibleForTesting + protected static QosCharacteristics frameworkToHalQosCharacteristics( + android.net.wifi.QosCharacteristics frameworkChars) { + QosCharacteristics halChars = new QosCharacteristics(); + halChars.minServiceIntervalUs = frameworkChars.getMinServiceIntervalMicros(); + halChars.maxServiceIntervalUs = frameworkChars.getMaxServiceIntervalMicros(); + halChars.minDataRateKbps = frameworkChars.getMinDataRateKbps(); + halChars.delayBoundUs = frameworkChars.getDelayBoundMicros(); + + int optionalFieldMask = 0; + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MAX_MSDU_SIZE)) { + optionalFieldMask |= QosCharacteristicsMask.MAX_MSDU_SIZE; + halChars.maxMsduSizeOctets = (char) frameworkChars.getMaxMsduSizeOctets(); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.SERVICE_START_TIME)) { + optionalFieldMask |= QosCharacteristicsMask.SERVICE_START_TIME; + optionalFieldMask |= QosCharacteristicsMask.SERVICE_START_TIME_LINK_ID; + halChars.serviceStartTimeUs = frameworkChars.getServiceStartTimeMicros(); + halChars.serviceStartTimeLinkId = (byte) frameworkChars.getServiceStartTimeLinkId(); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MEAN_DATA_RATE)) { + optionalFieldMask |= QosCharacteristicsMask.MEAN_DATA_RATE; + halChars.meanDataRateKbps = frameworkChars.getMeanDataRateKbps(); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.BURST_SIZE)) { + optionalFieldMask |= QosCharacteristicsMask.BURST_SIZE; + halChars.burstSizeOctets = frameworkChars.getBurstSizeOctets(); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MSDU_LIFETIME)) { + optionalFieldMask |= QosCharacteristicsMask.MSDU_LIFETIME; + halChars.msduLifetimeMs = (char) frameworkChars.getMsduLifetimeMillis(); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MSDU_DELIVERY_INFO)) { + optionalFieldMask |= QosCharacteristicsMask.MSDU_DELIVERY_INFO; + MsduDeliveryInfo deliveryInfo = new MsduDeliveryInfo(); + deliveryInfo.deliveryRatio = + frameworkToHalDeliveryRatio(frameworkChars.getDeliveryRatio()); + deliveryInfo.countExponent = (byte) frameworkChars.getCountExponent(); + halChars.msduDeliveryInfo = deliveryInfo; + } + + halChars.optionalFieldMask = optionalFieldMask; + return halChars; + } + /** * Convert from a framework {@link QosPolicyParams} to a HAL QosPolicyScsData object. */ @VisibleForTesting - protected static QosPolicyScsData frameworkToHalQosPolicyScsData(QosPolicyParams params) { + protected QosPolicyScsData frameworkToHalQosPolicyScsData(QosPolicyParams params) { QosPolicyScsData halData = new QosPolicyScsData(); halData.policyId = (byte) params.getTranslatedPolicyId(); halData.userPriority = (byte) params.getUserPriority(); @@ -2940,13 +3045,20 @@ public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal { paramsMask |= QosPolicyClassifierParamsMask.FLOW_LABEL; classifierParams.flowLabelIpv6 = params.getFlowLabel(); } + if (SdkLevel.isAtLeastV() && isServiceVersionAtLeast(3)) { + halData.direction = frameworkToHalPolicyDirection(params.getDirection()); + if (params.getQosCharacteristics() != null) { + halData.QosCharacteristics = + frameworkToHalQosCharacteristics(params.getQosCharacteristics()); + } + } classifierParams.classifierParamMask = paramsMask; halData.classifierParams = classifierParams; return halData; } - private static QosPolicyScsData[] frameworkToHalQosPolicyScsDataList( + private QosPolicyScsData[] frameworkToHalQosPolicyScsDataList( List<QosPolicyParams> frameworkPolicies) { QosPolicyScsData[] halDataList = new QosPolicyScsData[frameworkPolicies.size()]; int index = 0; @@ -3008,6 +3120,9 @@ public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal { capOut.maxNumberTxSpatialStreams = cap.maxNumberTxSpatialStreams; capOut.maxNumberRxSpatialStreams = cap.maxNumberRxSpatialStreams; capOut.apTidToLinkMapNegotiationSupported = cap.apTidToLinkMapNegotiationSupported; + if (isServiceVersionAtLeast(3) && cap.vendorData != null) { + capOut.vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList(cap.vendorData); + } return capOut; } catch (RemoteException e) { handleRemoteException(e, methodStr); @@ -3755,6 +3870,121 @@ public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal { } } + private static byte frameworkToHalFrameClassifierMask(int frameworkBitmap) { + byte halBitmap = 0; + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_IP_VERSION) != 0) { + halBitmap |= FrameClassifierFields.IP_VERSION; + } + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_SRC_IP_ADDR) != 0) { + halBitmap |= FrameClassifierFields.SRC_IP_ADDR; + } + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_DST_IP_ADDR) != 0) { + halBitmap |= FrameClassifierFields.DST_IP_ADDR; + } + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_SRC_PORT) != 0) { + halBitmap |= FrameClassifierFields.SRC_PORT; + } + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_DST_PORT) != 0) { + halBitmap |= FrameClassifierFields.DST_PORT; + } + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_DSCP) != 0) { + halBitmap |= FrameClassifierFields.DSCP; + } + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_PROTOCOL_NEXT_HDR) != 0) { + halBitmap |= FrameClassifierFields.PROTOCOL_NEXT_HDR; + } + if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_FLOW_LABEL) != 0) { + halBitmap |= FrameClassifierFields.FLOW_LABEL; + } + return halBitmap; + } + + private static android.hardware.wifi.supplicant.MscsParams frameworkToHalMscsParams( + MscsParams frameworkParams) { + android.hardware.wifi.supplicant.MscsParams halParams = + new android.hardware.wifi.supplicant.MscsParams(); + halParams.upBitmap = (byte) frameworkParams.getUserPriorityBitmap(); + halParams.upLimit = (byte) frameworkParams.getUserPriorityLimit(); + halParams.streamTimeoutUs = frameworkParams.getStreamTimeoutUs(); + halParams.frameClassifierMask = + frameworkToHalFrameClassifierMask(frameworkParams.getFrameClassifierFields()); + return halParams; + } + + /** + * See comments for {@link ISupplicantStaIfaceHal#enableMscs(MscsParams, String)} + */ + @Override + public void enableMscs(@NonNull MscsParams mscsParams, String ifaceName) { + synchronized (mLock) { + if (!isServiceVersionAtLeast(3)) { + return; + } + configureMscsInternal(mscsParams, ifaceName); + mLastMscsParams = mscsParams; + } + } + + /** + * See comments for {@link ISupplicantStaIfaceHal#resendMscs(String)} + */ + public void resendMscs(String ifaceName) { + synchronized (mLock) { + if (!isServiceVersionAtLeast(3)) { + return; + } + if (mLastMscsParams == null) { + return; + } + configureMscsInternal(mLastMscsParams, ifaceName); + } + } + + private void configureMscsInternal(@NonNull MscsParams mscsParams, String ifaceName) { + synchronized (mLock) { + if (!isServiceVersionAtLeast(3)) { + return; + } + String methodStr = "configureMscsInternal"; + ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr); + if (iface == null) { + return; + } + try { + android.hardware.wifi.supplicant.MscsParams halParams = + frameworkToHalMscsParams(mscsParams); + iface.configureMscs(halParams); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + } + } + + /** + * See comments for {@link ISupplicantStaIface#disableMscs()} + */ + @Override + public void disableMscs(String ifaceName) { + if (!isServiceVersionAtLeast(3)) { + return; + } + String methodStr = "disableMscs"; + mLastMscsParams = null; + ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr); + if (iface == null) { + return; + } + try { + iface.disableMscs(); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + } + private class NonStandardCertCallback extends INonStandardCertCallback.Stub { @Override public byte[] getBlob(String alias) { diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHalHidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHalHidlImpl.java index 0bf1b1dd20..5a431b7e38 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceHalHidlImpl.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHalHidlImpl.java @@ -53,7 +53,6 @@ import android.hardware.wifi.supplicant.V1_4.LegacyMode; import android.hidl.manager.V1_0.IServiceManager; import android.hidl.manager.V1_0.IServiceNotification; import android.net.MacAddress; -import android.net.wifi.QosPolicyParams; import android.net.wifi.ScanResult; import android.net.wifi.SecurityParams; import android.net.wifi.WifiAnnotations.WifiStandard; @@ -3945,98 +3944,4 @@ public class SupplicantStaIfaceHalHidlImpl implements ISupplicantStaIfaceHal { return currentConfig.getNetworkSelectionStatus().getCandidateSecurityParams(); } - - /** - * Set whether the network-centric QoS policy feature is enabled or not for this interface. - * - * @param ifaceName name of the interface. - * @param isEnabled true if feature is enabled, false otherwise. - * @return true without action since this is not a supported feature. - */ - public boolean setNetworkCentricQosPolicyFeatureEnabled(@NonNull String ifaceName, - boolean isEnabled) { - throw new UnsupportedOperationException( - "setNetworkCentricQosPolicyFeatureEnabled is not supported by the HIDL HAL"); - } - - /** - * Sends a QoS policy response. - * - * @param ifaceName Name of the interface. - * @param qosPolicyRequestId Dialog token to identify the request. - * @param morePolicies Flag to indicate more QoS policies can be accommodated. - * @param qosPolicyStatusList List of framework QosPolicyStatus objects. - * @return true if response is sent successfully, false otherwise. - */ - public boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId, - boolean morePolicies, - @NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList) { - throw new UnsupportedOperationException( - "sendQosPolicyResponse is not supported by the HIDL HAL"); - } - - /** - * Indicates the removal of all active QoS policies configured by the AP. - * - * @param ifaceName Name of the interface. - */ - public boolean removeAllQosPolicies(String ifaceName) { - throw new UnsupportedOperationException( - "removeAllQosPolicies is not supported by the HIDL HAL"); - } - - /** - * See comments for {@link ISupplicantStaIfaceHal#addQosPolicyRequestForScs(String, List)} - */ - public List<SupplicantStaIfaceHal.QosPolicyStatus> addQosPolicyRequestForScs( - @NonNull String ifaceName, @NonNull List<QosPolicyParams> policies) { - Log.e(TAG, "addQosPolicyRequestForScs is not supported by the HIDL HAL"); - return null; - } - - /** - * See comments for {@link ISupplicantStaIfaceHal#removeQosPolicyForScs(String, List)} - */ - public List<SupplicantStaIfaceHal.QosPolicyStatus> removeQosPolicyForScs( - @NonNull String ifaceName, @NonNull List<Byte> policyIds) { - Log.e(TAG, "removeQosPolicyForScs is not supported by the HIDL HAL"); - return null; - } - - /** - * See comments for {@link ISupplicantStaIfaceHal#registerQosScsResponseCallback( - * SupplicantStaIfaceHal.QosScsResponseCallback)} - */ - public void registerQosScsResponseCallback( - @NonNull SupplicantStaIfaceHal.QosScsResponseCallback callback) { - Log.e(TAG, "registerQosScsResponseCallback is not supported by the HIDL HAL"); - } - - /** - * Generate DPP credential for network access - * - * @param ifaceName Name of the interface. - * @param ssid ssid of the network - * @param privEcKey Private EC Key for DPP Configurator - * Returns false. Not Supported throuh HIDL - */ - public boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid, - byte[] privEcKey) { - Log.d(TAG, "generateSelfDppConfiguration is not supported"); - return false; - } - - /** - * Set the currently configured network's anonymous identity. - * - * @param ifaceName Name of the interface. - * @param anonymousIdentity the anonymouns identity. - * @param updateToNativeService write the data to the native service. - * @return true if succeeds, false otherwise. - */ - public boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity, - boolean updateToNativeService) { - Log.d(TAG, "setEapAnonymousIdentity is ignored for HIDL"); - return false; - } } diff --git a/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java index 21d3426f56..219c716a22 100644 --- a/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java +++ b/service/java/com/android/server/wifi/SupplicantStaNetworkCallbackAidlImpl.java @@ -177,7 +177,7 @@ class SupplicantStaNetworkCallbackAidlImpl extends ISupplicantStaNetworkCallback return; } String certHash = byteArrayToString(certHashBytes); - if (null == subject) { + if (null == certHash) { mNetworkHal.logCallback( "onServerCertificateAvailable: cannot convert cert hash bytes to string."); return; diff --git a/service/java/com/android/server/wifi/SupplicantStaNetworkHalAidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaNetworkHalAidlImpl.java index 634ba3f856..3c1a8b4993 100644 --- a/service/java/com/android/server/wifi/SupplicantStaNetworkHalAidlImpl.java +++ b/service/java/com/android/server/wifi/SupplicantStaNetworkHalAidlImpl.java @@ -16,6 +16,7 @@ package com.android.server.wifi; +import android.annotation.NonNull; import android.content.Context; import android.hardware.wifi.supplicant.AuthAlgMask; import android.hardware.wifi.supplicant.DppConnectionKeys; @@ -33,6 +34,7 @@ import android.hardware.wifi.supplicant.PairwiseCipherMask; import android.hardware.wifi.supplicant.ProtoMask; import android.hardware.wifi.supplicant.SaeH2eMode; import android.hardware.wifi.supplicant.TlsVersion; +import android.net.wifi.OuiKeyedData; import android.net.wifi.SecurityParams; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; @@ -44,6 +46,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.util.ArrayUtils; import com.android.server.wifi.util.HalAidlUtil; import com.android.server.wifi.util.NativeUtil; @@ -59,6 +62,7 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -309,7 +313,14 @@ public class SupplicantStaNetworkHalAidlImpl { if (config == null) { return false; } - /** SSID */ + // ieee80211be + if (!config.isWifi7Enabled() && isServiceVersionIsAtLeast(3)) { + if (!disableEht()) { + Log.e(TAG, "failed to disable EHT (Wi-Fi 7)"); + return false; + } + } + // SSID if (config.SSID != null) { WifiSsid wifiSsid = WifiSsid.fromString(config.SSID); if (!setSsid(wifiSsid.getBytes())) { @@ -317,7 +328,7 @@ public class SupplicantStaNetworkHalAidlImpl { return false; } } - /** BSSID */ + // BSSID String bssidStr = config.getNetworkSelectionStatus().getNetworkSelectionBSSID(); if (bssidStr != null) { byte[] bssid = NativeUtil.macAddressToByteArray(bssidStr); @@ -326,7 +337,7 @@ public class SupplicantStaNetworkHalAidlImpl { return false; } } - /** HiddenSSID */ + // HiddenSSID if (!setScanSsid(config.hiddenSSID)) { Log.e(TAG, config.SSID + ": failed to set hiddenSSID: " + config.hiddenSSID); return false; @@ -342,12 +353,12 @@ public class SupplicantStaNetworkHalAidlImpl { boolean isRequirePmf = NativeUtil.getOptimalPmfSettingForConfig(config, securityParams.isRequirePmf(), mWifiGlobals); - /** RequirePMF */ + // RequirePMF if (!setRequirePmf(isRequirePmf)) { Log.e(TAG, config.SSID + ": failed to set requirePMF: " + config.requirePmf); return false; } - /** Key Management Scheme */ + // Key Management Scheme BitSet allowedKeyManagement = securityParams.getAllowedKeyManagement(); if (allowedKeyManagement.cardinality() != 0) { // Add upgradable type key management flags for PSK/SAE. @@ -374,7 +385,7 @@ public class SupplicantStaNetworkHalAidlImpl { return false; } } - /** Security Protocol */ + // Security Protocol BitSet allowedProtocols = securityParams.getAllowedProtocols(); if (allowedProtocols.cardinality() != 0 && !setProto( wifiConfigurationToSupplicantProtoMask(allowedProtocols, mWifiGlobals, @@ -382,7 +393,7 @@ public class SupplicantStaNetworkHalAidlImpl { Log.e(TAG, "failed to set Security Protocol"); return false; } - /** Auth Algorithm */ + // Auth Algorithm BitSet allowedAuthAlgorithms = securityParams.getAllowedAuthAlgorithms(); if (allowedAuthAlgorithms.cardinality() != 0 && !setAuthAlg(wifiConfigurationToSupplicantAuthAlgMask( @@ -390,7 +401,7 @@ public class SupplicantStaNetworkHalAidlImpl { Log.e(TAG, "failed to set AuthAlgorithm"); return false; } - /** Group Cipher */ + // Group Cipher BitSet allowedGroupCiphers = NativeUtil.getOptimalGroupCiphersForConfig( config, securityParams.getAllowedGroupCiphers(), mWifiGlobals); if (allowedGroupCiphers.cardinality() != 0 @@ -399,7 +410,7 @@ public class SupplicantStaNetworkHalAidlImpl { Log.e(TAG, "failed to set Group Cipher"); return false; } - /** Pairwise Cipher*/ + // Pairwise Cipher BitSet allowedPairwiseCiphers = NativeUtil.getOptimalPairwiseCiphersForConfig( config, securityParams.getAllowedPairwiseCiphers(), mWifiGlobals); if (allowedPairwiseCiphers.cardinality() != 0 @@ -408,7 +419,7 @@ public class SupplicantStaNetworkHalAidlImpl { Log.e(TAG, "failed to set PairwiseCipher"); return false; } - /** Pre Shared Key */ + // Pre Shared Key // For PSK, this can either be quoted ASCII passphrase or hex string for raw psk. // For SAE, password must be a quoted ASCII string if (config.preSharedKey != null) { @@ -419,7 +430,7 @@ public class SupplicantStaNetworkHalAidlImpl { } } else if (config.preSharedKey.startsWith("\"")) { if (allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) { - /* WPA3 case, field is SAE Password */ + // WPA3 case, field is SAE Password if (!setSaePassword( NativeUtil.removeEnclosingQuotes(config.preSharedKey))) { Log.e(TAG, "failed to set sae password"); @@ -444,7 +455,7 @@ public class SupplicantStaNetworkHalAidlImpl { } } } - /** Wep Keys */ + // Wep Keys boolean hasSetKey = false; if (config.wepKeys != null) { for (int i = 0; i < config.wepKeys.length; i++) { @@ -458,18 +469,18 @@ public class SupplicantStaNetworkHalAidlImpl { } } } - /** Wep Tx Key Idx */ + // Wep Tx Key Idx if (hasSetKey) { if (!setWepTxKeyIdx(config.wepTxKeyIndex)) { Log.e(TAG, "failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); return false; } } - /** metadata: FQDN + ConfigKey + CreatorUid */ + // metadata: FQDN + ConfigKey + CreatorUid final Map<String, String> metadata = new HashMap<String, String>(); if (config.isPasspoint()) { metadata.put(ID_STRING_KEY_FQDN, config.FQDN); - /** Selected RCOI */ + // Selected RCOI if (!setSelectedRcoi(config.enterpriseConfig.getSelectedRcoi())) { Log.e(TAG, "failed to set selected RCOI"); return false; @@ -481,13 +492,13 @@ public class SupplicantStaNetworkHalAidlImpl { Log.e(TAG, "failed to set id string"); return false; } - /** UpdateIdentifier */ + // UpdateIdentifier if (config.updateIdentifier != null && !setUpdateIdentifier(Integer.parseInt(config.updateIdentifier))) { Log.e(TAG, "failed to set update identifier"); return false; } - /** SAE configuration */ + // SAE configuration if (allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) { /** * Hash-to-Element preference. @@ -512,11 +523,19 @@ public class SupplicantStaNetworkHalAidlImpl { return false; } } + // Vendor data + if (SdkLevel.isAtLeastV() && isServiceVersionIsAtLeast(3) + && config.getVendorData() != null + && !config.getVendorData().isEmpty() + && !setVendorData(config.getVendorData())) { + Log.e(TAG, "Failed to set vendor data."); + return false; + } // Finish here if no EAP config to set if (config.enterpriseConfig != null && config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { if (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.WAPI_CERT) { - /** WAPI certificate suite name*/ + // WAPI certificate suite name String param = config.enterpriseConfig .getFieldValue(WifiEnterpriseConfig.WAPI_CERT_SUITE_KEY); if (!TextUtils.isEmpty(param) && !setWapiCertSuite(param)) { @@ -1304,6 +1323,33 @@ public class SupplicantStaNetworkHalAidlImpl { } /** + * Disable EHT for this network. + * + * @return true if successful, false otherwise + */ + private boolean disableEht() { + synchronized (mLock) { + final String methodStr = "disableEht"; + if (!checkStaNetworkAndLogFailure(methodStr)) { + return false; + } + try { + if (!isServiceVersionIsAtLeast(3)) { + return false; + } + mISupplicantStaNetwork.disableEht(); + Log.i(TAG, "Successfully disabled EHT"); + return true; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return false; + } + } + + /** * Set the BSSID for this network. * * @param bssidStr MAC address in "XX:XX:XX:XX:XX:XX" form or "any" to reset the mac address. @@ -3745,4 +3791,29 @@ public class SupplicantStaNetworkHalAidlImpl { return false; } } + + private boolean setVendorData(@NonNull List<OuiKeyedData> vendorData) { + synchronized (mLock) { + final String methodStr = "setVendorData"; + if (!checkStaNetworkAndLogFailure(methodStr)) { + return false; + } + try { + if (!isServiceVersionIsAtLeast(3)) { + return false; + } + if (vendorData == null || vendorData.isEmpty()) { + return false; + } + mISupplicantStaNetwork.setVendorData( + HalAidlUtil.frameworkToHalOuiKeyedDataList(vendorData)); + return true; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return false; + } + } } diff --git a/service/java/com/android/server/wifi/TwtManager.java b/service/java/com/android/server/wifi/TwtManager.java new file mode 100644 index 0000000000..077cd1505a --- /dev/null +++ b/service/java/com/android/server/wifi/TwtManager.java @@ -0,0 +1,651 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.wifi; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AlarmManager; +import android.net.MacAddress; +import android.net.wifi.ITwtCallback; +import android.net.wifi.ITwtCapabilitiesListener; +import android.net.wifi.ITwtStatsListener; +import android.net.wifi.WifiManager; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSession; +import android.net.wifi.twt.TwtSessionCallback; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.IInterface; +import android.os.RemoteException; +import android.util.ArraySet; +import android.util.Log; +import android.util.SparseArray; + +import com.android.wifi.resources.R; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; + +/** + * This class acts as a manager for TWT sessions and callbacks. It establishes a link between unique + * callback IDs and their corresponding callbacks, ensuring the correct responses are triggered. To + * manage incoming TWT events, the class registers TWT sessions with the appropriate callbacks. + * Additionally, it implements a garbage collection task to remove expired callbacks. + * + * If a registered callback's process goes away, this class will take care of automatically + * removing it from the callback list. Twt manager allows simultaneous requests limited by + * {@link #MAXIMUM_CALLBACKS}. + * + * Note: All contexts in TwtManager are in WifiThread. So no locks are used. + */ + +class TwtManager { + public static final String TAG = "TwtManager"; + private static final int TWT_CALLBACK_TIMEOUT_MILLIS = 2000; + private static final String TWT_MANAGER_ALARM_TAG = "twtManagerAlarm"; + private static final int MAXIMUM_CALLBACKS = 8; + + private class Callback implements IBinder.DeathRecipient { + public IInterface mCallback; + public final int mOwner; + public int mSessionId = -1; + public final int mId; + public final CallbackType mType; + public final long mTimestamp; + + Callback(int id, IInterface callback, CallbackType type, int owner) { + mId = id; + mCallback = callback; + mType = type; + mOwner = owner; + mTimestamp = mClock.getElapsedSinceBootMillis(); + } + + @Override + public void binderDied() { + mHandler.post(() -> { + unregisterSession(mSessionId); + unregisterCallback(mId); + }); + } + } + + private enum CallbackType {SETUP, STATS, TEARDOWN} + private final SparseArray<Callback> mCommandCallbacks = new SparseArray<>(); + private final SparseArray<Callback> mTwtSessionCallbacks = new SparseArray<>(); + private final BitSet mIdBitSet; + private final int mStartOffset; + private final int mMaxSessions; + private String mInterfaceName; + private final Clock mClock; + private final AlarmManager mAlarmManager; + private final Handler mHandler; + ArraySet<Integer> mBlockedOuiSet = new ArraySet<>(); + + private final WifiNative mWifiNative; + private final WifiNativeTwtEvents mWifiNativeTwtEvents; + private final AlarmManager.OnAlarmListener mTimeoutListener = () -> { + startGarbageCollector(); + }; + + /** + * Whenever primary clientModeManager identified by the interface name gets disconnected, reset + * the TwtManager. + */ + private class ClientModeImplListenerInternal implements ClientModeImplListener { + @Override + public void onConnectionEnd(@NonNull ConcreteClientModeManager clientModeManager) { + if (clientModeManager.getInterfaceName() != null + && clientModeManager.getInterfaceName().equals(mInterfaceName)) { + reset(); + } + } + } + + TwtManager(@NonNull WifiInjector wifiInjector, @NonNull ClientModeImplMonitor cmiMonitor, + @NonNull WifiNative wifiNative, @NonNull Handler handler, @NonNull Clock clock, + int maxSessions, int startOffset) { + mAlarmManager = wifiInjector.getAlarmManager(); + mHandler = handler; + mClock = clock; + mMaxSessions = maxSessions; + mIdBitSet = new BitSet(MAXIMUM_CALLBACKS); + mStartOffset = startOffset; + mWifiNative = wifiNative; + mWifiNativeTwtEvents = new WifiNativeTwtEvents(); + cmiMonitor.registerListener(new ClientModeImplListenerInternal()); + int[] ouis = wifiInjector.getContext().getResources().getIntArray( + R.array.config_wifiTwtBlockedOuiList); + if (ouis != null) { + for (int oui : ouis) { + mBlockedOuiSet.add(oui); + } + } + } + + /** + * Notify teardown to the registered caller + */ + private void notifyTeardown(ITwtCallback iTwtCallback, + @TwtSessionCallback.TwtReasonCode int reasonCode) { + if (iTwtCallback == null) { + Log.e(TAG, "notifyTeardown: null interface. Reason code " + reasonCode); + return; + } + try { + iTwtCallback.onTeardown(reasonCode); + } catch (RemoteException e) { + Log.e(TAG, "notifyTeardown: " + e); + } + } + + private Bundle getDefaultTwtCapabilities() { + Bundle twtCapabilities = new Bundle(); + twtCapabilities.putBoolean(WifiManager.TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER, false); + twtCapabilities.putInt(WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS, -1); + twtCapabilities.putInt(WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS, -1); + twtCapabilities.putLong(WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS, -1); + twtCapabilities.putLong(WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS, -1); + return twtCapabilities; + } + + private static Bundle getDefaultTwtStats() { + Bundle twtStats = new Bundle(); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_EOSP_COUNT, -1); + return twtStats; + } + + /** + * Notify failure to the registered caller + */ + private void notifyFailure(IInterface iInterface, CallbackType type, + @TwtSessionCallback.TwtErrorCode int errorCode) { + if (iInterface == null) { + Log.e(TAG, "notifyFailure: null interface. Error code " + errorCode); + return; + } + try { + if (type == CallbackType.STATS) { + ((ITwtStatsListener) iInterface).onResult(getDefaultTwtStats()); + } else { + ((ITwtCallback) iInterface).onFailure(errorCode); + } + } catch (RemoteException e) { + Log.e(TAG, "notifyFailure: " + e); + } + } + + /** + * Expire callbacks and fetch next oldest callback's schedule for timeout + * + * @param now Current reference time + * @return Timeout of the oldest callback with respect to current time. A value 0 means no more + * callbacks to expire. + */ + private long handleExpirationsAndGetNextTimeout(long now) { + long oldest = Long.MAX_VALUE; + List<Integer> expiredIds = new ArrayList<>(); + for (int i = 0; i < mCommandCallbacks.size(); ++i) { + Callback callback = mCommandCallbacks.valueAt(i); + if (now - callback.mTimestamp >= TWT_CALLBACK_TIMEOUT_MILLIS) { + notifyFailure(callback.mCallback, callback.mType, + TwtSessionCallback.TWT_ERROR_CODE_TIMEOUT); + // Unregister session now + if (callback.mType == CallbackType.TEARDOWN) { + unregisterSession(callback.mSessionId); + } + expiredIds.add(callback.mId); + } else { + oldest = Math.min(callback.mTimestamp, oldest); + } + } + for (int id : expiredIds) { + unregisterCallback(id); + } + + if (oldest > now) return 0; + // Callbacks which has (age >= TWT_COMMAND_TIMEOUT_MILLIS) is cleaned up already + return TWT_CALLBACK_TIMEOUT_MILLIS - (now - oldest); + } + + private void startGarbageCollector() { + long timeout = handleExpirationsAndGetNextTimeout(mClock.getElapsedSinceBootMillis()); + if (timeout <= 0) return; + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, + mClock.getElapsedSinceBootMillis() + timeout, TWT_MANAGER_ALARM_TAG, + mTimeoutListener, mHandler); + } + + private void stopGarbageCollector() { + mAlarmManager.cancel(mTimeoutListener); + } + + /** + * Register a callback + * + * @param callback A remote interface performing callback + * @param type Type of the callback as {@link CallbackType} + * @param owner Owner of the callback + * @return Returns an unique id. -1 if registration fails. + */ + private int registerCallback(IInterface callback, CallbackType type, int owner) { + if (callback == null) { + Log.e(TAG, "registerCallback: Null callback"); + return -1; + } + if ((type == CallbackType.SETUP) && (mTwtSessionCallbacks.size() >= mMaxSessions)) { + Log.e(TAG, "registerCallback: Maximum sessions reached. Setup not allowed."); + notifyFailure(callback, CallbackType.SETUP, + TwtSessionCallback.TWT_ERROR_CODE_MAX_SESSIONS_REACHED); + return -1; + } + int id = mIdBitSet.nextClearBit(0); + if (id >= MAXIMUM_CALLBACKS) { + Log.e(TAG, "registerCallback: No more simultaneous requests possible"); + notifyFailure(callback, CallbackType.SETUP, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + return -1; + } + mIdBitSet.set(id); + id += mStartOffset; + try { + Callback cb = new Callback(id, callback, type, owner); + callback.asBinder().linkToDeath(cb, 0); + mCommandCallbacks.put(id, cb); + } catch (RemoteException e) { + Log.e(TAG, "registerCallback: Error on linkToDeath - " + e); + notifyFailure(callback, CallbackType.SETUP, TwtSessionCallback.TWT_ERROR_CODE_FAIL); + return -1; + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "registerCallback: " + e); + notifyFailure(callback, CallbackType.SETUP, TwtSessionCallback.TWT_ERROR_CODE_FAIL); + return -1; + } + // First register triggers GC + if (mCommandCallbacks.size() == 1) startGarbageCollector(); + return id; + } + + /** + * Unregister a previously registered callback + * + * @param id Unique callback id returned by + * {@link #registerCallback(IInterface, CallbackType, int)} + */ + private void unregisterCallback(int id) { + try { + if (!mCommandCallbacks.contains(id)) return; + // Last unregister stops GC + if (mCommandCallbacks.size() == 1) stopGarbageCollector(); + Callback cb = mCommandCallbacks.get(id); + if (!mTwtSessionCallbacks.contains(cb.mSessionId)) { + // Note: unregisterSession() will call Binder#unlinktoDeath() + cb.mCallback.asBinder().unlinkToDeath(cb, 0); + } + mCommandCallbacks.delete(id); + mIdBitSet.clear(id - mStartOffset); + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "unregisterCallback: invalid id " + id + " " + e); + } + } + + /** + * Register a TWT session + * + * @param id Unique callback id returned by + * {@link #registerCallback(IInterface, CallbackType, int)} + * @param sessionId TWT session id + * @return true if successful, otherwise false. + */ + private boolean registerSession(int id, int sessionId) { + Callback callback = mCommandCallbacks.get(id); + if (callback == null) { + Log.e(TAG, "registerSession failed. Invalid id " + id); + return false; + } + if (mTwtSessionCallbacks.contains(sessionId)) { + Log.e(TAG, "registerSession failed. Session already exists"); + return false; + } + callback.mSessionId = sessionId; + mTwtSessionCallbacks.put(sessionId, callback); + return true; + } + + /** + * Unregister a TWT session + * + * @param sessionId TWT session id + */ + private void unregisterSession(int sessionId) { + if (!mTwtSessionCallbacks.contains(sessionId)) { + Log.e(TAG, "unregisterSession failed. Session does not exist"); + return; + } + Callback callback = mTwtSessionCallbacks.get(sessionId); + callback.mCallback.asBinder().unlinkToDeath(callback, 0); + mTwtSessionCallbacks.delete(sessionId); + } + + private boolean isSessionRegistered(int sessionId) { + return mTwtSessionCallbacks.get(sessionId) != null; + } + + /** + * Get callback from TWT session id + * + * @param sessionId TWT session id + * @return Callback registered, otherwise null + */ + private IInterface getCallbackFromSession(int sessionId) { + if (mTwtSessionCallbacks.get(sessionId) == null) return null; + return mTwtSessionCallbacks.get(sessionId).mCallback; + } + + /** + * Get owner uid + * + * @param id unique id returned by {@link #registerCallback(IInterface, CallbackType, int)} + * @return Owner UID if registered, otherwise -1 + */ + private int getOwnerUid(int id) { + try { + return mCommandCallbacks.get(id).mOwner; + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "getOwner: invalid id " + id + " " + e); + return -1; + } + } + + /** + * Get callback + * + * @param id unique id returned by {@link #registerCallback(IInterface, CallbackType, int)} + * @return Callback if registered, otherwise null + */ + private IInterface getCallback(int id) { + try { + Callback callback = mCommandCallbacks.get(id); + if (callback == null) return null; + return callback.mCallback; + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "getCallback: invalid id " + id + " " + e); + return null; + } + } + + /** + * Implementation of TWT events from WifiNative. see {@link #registerWifiNativeTwtEvents()} + */ + public class WifiNativeTwtEvents implements WifiNative.WifiTwtEvents { + @Override + public void onTwtFailure(int cmdId, int twtErrorCode) { + ITwtCallback iTwtCallback = (ITwtCallback) getCallback(cmdId); + if (iTwtCallback == null) { + Log.e(TAG, "onTwtFailure: Command Id is not registered " + cmdId); + return; + } + try { + iTwtCallback.onFailure(twtErrorCode); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + unregisterCallback(cmdId); + } + + @Override + public void onTwtSessionCreate(int cmdId, int wakeDurationUs, long wakeIntervalUs, + int linkId, int sessionId) { + ITwtCallback iTwtCallback = (ITwtCallback) getCallback(cmdId); + if (iTwtCallback == null) { + Log.e(TAG, "onTwtSessionCreate failed. No callback registered for " + cmdId); + return; + } + if (!registerSession(cmdId, sessionId)) { + Log.e(TAG, "onTwtSessionCreate failed for session " + sessionId); + return; + } + try { + iTwtCallback.onCreate(wakeDurationUs, wakeIntervalUs, linkId, getOwnerUid(cmdId), + sessionId); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + unregisterCallback(cmdId); + } + + @Override + public void onTwtSessionTeardown(int cmdId, int twtSessionId, int twtReasonCode) { + ITwtCallback iTwtCallback = (ITwtCallback) getCallback(cmdId); + if (iTwtCallback == null) { + // Unsolicited teardown. So get callback from session. + iTwtCallback = (ITwtCallback) getCallbackFromSession(twtSessionId); + if (iTwtCallback == null) return; + } + try { + iTwtCallback.onTeardown(twtReasonCode); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + unregisterCallback(cmdId); + unregisterSession(twtSessionId); + } + + @Override + public void onTwtSessionStats(int cmdId, int twtSessionId, Bundle twtStats) { + ITwtStatsListener iTwtStatsListener = (ITwtStatsListener) getCallback(cmdId); + if (iTwtStatsListener == null) { + return; + } + try { + iTwtStatsListener.onResult(twtStats); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + unregisterCallback(cmdId); + } + } + + /** + * Register for TWT events from WifiNative + */ + public void registerWifiNativeTwtEvents() { + mWifiNative.registerTwtCallbacks(mWifiNativeTwtEvents); + } + + /** + * Get TWT capabilities for the interface + * + * @param interfaceName Interface name + * @param listener listener for TWT capabilities + */ + public void getTwtCapabilities(@Nullable String interfaceName, + @NonNull ITwtCapabilitiesListener listener) { + try { + if (interfaceName == null) { + listener.onResult(getDefaultTwtCapabilities()); + return; + } + Bundle twtCapabilities = mWifiNative.getTwtCapabilities(interfaceName); + if (twtCapabilities == null) twtCapabilities = getDefaultTwtCapabilities(); + listener.onResult(twtCapabilities); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + } + + /** + * Sets up a TWT session for the interface + * + * @param interfaceName Interface name + * @param twtRequest TWT request parameters + * @param iTwtCallback Callback for the TWT setup command + * @param callingUid Caller UID + * @param bssid BSSID + */ + public void setupTwtSession(@Nullable String interfaceName, @NonNull TwtRequest twtRequest, + @NonNull ITwtCallback iTwtCallback, int callingUid, @NonNull String bssid) { + if (isOuiBlockListed(bssid)) { + notifyFailure(iTwtCallback, CallbackType.SETUP, + TwtSessionCallback.TWT_ERROR_CODE_AP_OUI_BLOCKLISTED); + return; + } + if (!registerInterface(interfaceName)) { + notifyFailure(iTwtCallback, CallbackType.SETUP, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + return; + } + int id = registerCallback(iTwtCallback, TwtManager.CallbackType.SETUP, callingUid); + if (id < 0) { + return; + } + if (!mWifiNative.setupTwtSession(id, interfaceName, twtRequest)) { + unregisterCallback(id); + notifyFailure(iTwtCallback, CallbackType.SETUP, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + } + } + + private boolean isOuiBlockListed(@NonNull String bssid) { + if (mBlockedOuiSet.isEmpty()) return false; + byte[] macBytes = MacAddress.fromString(bssid).toByteArray(); + int oui = (macBytes[0] & 0xFF) << 16 | (macBytes[1] & 0xFF) << 8 | (macBytes[2] & 0xFF); + return mBlockedOuiSet.contains(oui); + } + + /** + * Teardown the TWT session + * + * @param interfaceName Interface name + * @param sessionId TWT session id + */ + public void tearDownTwtSession(@Nullable String interfaceName, int sessionId) { + ITwtCallback iTwtCallback = (ITwtCallback) getCallbackFromSession(sessionId); + if (iTwtCallback == null) { + return; + } + if (!isRegisteredInterface(interfaceName)) { + notifyFailure(iTwtCallback, CallbackType.TEARDOWN, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + return; + } + int id = registerCallback(iTwtCallback, TwtManager.CallbackType.TEARDOWN, + Binder.getCallingUid()); + if (id < 0) { + return; + } + if (!mWifiNative.tearDownTwtSession(id, interfaceName, sessionId)) { + unregisterCallback(id); + notifyFailure(iTwtCallback, CallbackType.TEARDOWN, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + } + } + + /** + * Gets stats of the TWT session + * + * @param interfaceName Interface name + * @param iTwtStatsListener Listener for TWT stats + * @param sessionId TWT session id + */ + public void getStatsTwtSession(@Nullable String interfaceName, + ITwtStatsListener iTwtStatsListener, int sessionId) { + if (!isRegisteredInterface(interfaceName)) { + notifyFailure(iTwtStatsListener, CallbackType.STATS, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + return; + } + + if (!isSessionRegistered(sessionId)) { + notifyFailure(iTwtStatsListener, CallbackType.STATS, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + return; + } + + int id = registerCallback(iTwtStatsListener, TwtManager.CallbackType.STATS, + Binder.getCallingUid()); + if (id < 0) { + notifyFailure(iTwtStatsListener, CallbackType.STATS, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + return; + } + if (!mWifiNative.getStatsTwtSession(id, interfaceName, sessionId)) { + unregisterCallback(id); + notifyFailure(iTwtStatsListener, CallbackType.STATS, + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + } + } + + private boolean isEmpty() { + return (mCommandCallbacks.size() == 0 && mTwtSessionCallbacks.size() == 0); + } + + private void reset() { + if (isEmpty()) return; + stopGarbageCollector(); + // Notify failure for all pending callbacks + for (int i = 0; i < mCommandCallbacks.size(); ++i) { + Callback callback = mCommandCallbacks.valueAt(i); + if (!mTwtSessionCallbacks.contains(callback.mSessionId)) { + // Session cleanup will call Binder#unlinktoDeath() + callback.mCallback.asBinder().unlinkToDeath(callback, 0); + } + notifyFailure(callback.mCallback, callback.mType, + TwtSessionCallback.TWT_ERROR_CODE_FAIL); + } + // Teardown all active sessions + for (int i = 0; i < mTwtSessionCallbacks.size(); ++i) { + Callback callback = mTwtSessionCallbacks.valueAt(i); + callback.mCallback.asBinder().unlinkToDeath(callback, 0); + notifyTeardown((ITwtCallback) callback.mCallback, + TwtSessionCallback.TWT_REASON_CODE_INTERNALLY_INITIATED); + } + mCommandCallbacks.clear(); + mTwtSessionCallbacks.clear(); + mIdBitSet.clear(); + unregisterInterface(); + } + + private void unregisterInterface() { + mInterfaceName = null; + } + + private boolean registerInterface(String interfaceName) { + if (interfaceName == null) return false; + if (mInterfaceName == null) { + mInterfaceName = interfaceName; + return true; + } + // Check if already registered to the same interface + if (interfaceName.equals(mInterfaceName)) { + return true; + } + Log.e(TAG, "Already registered to another interface " + mInterfaceName); + return false; + } + + private boolean isRegisteredInterface(String interfaceName) { + return (interfaceName != null && interfaceName.equals(mInterfaceName)); + } +} diff --git a/service/java/com/android/server/wifi/UntrustedWifiNetworkFactory.java b/service/java/com/android/server/wifi/UntrustedWifiNetworkFactory.java index d7dda70fd0..85b33aac8f 100644 --- a/service/java/com/android/server/wifi/UntrustedWifiNetworkFactory.java +++ b/service/java/com/android/server/wifi/UntrustedWifiNetworkFactory.java @@ -16,15 +16,20 @@ package com.android.server.wifi; +import android.annotation.TargetApi; import android.content.Context; import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; +import android.os.Build; import android.os.Looper; import android.util.Log; +import com.android.modules.utils.build.SdkLevel; + import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Set; /** * Network factory to handle untrusted wifi network requests. @@ -35,15 +40,27 @@ public class UntrustedWifiNetworkFactory extends NetworkFactory { private final WifiConnectivityManager mWifiConnectivityManager; private int mConnectionReqCount = 0; + private final NetworkCapabilities mCapabilitiesFilter; public UntrustedWifiNetworkFactory(Looper l, Context c, NetworkCapabilities f, WifiConnectivityManager connectivityManager) { super(l, c, TAG, f); mWifiConnectivityManager = connectivityManager; - + mCapabilitiesFilter = f; setScoreFilter(SCORE_FILTER); } + // package-private + @TargetApi(Build.VERSION_CODES.S) + void updateSubIdsInCapabilitiesFilter(Set<Integer> subIds) { + if (SdkLevel.isAtLeastS()) { + NetworkCapabilities newFilter = + new NetworkCapabilities.Builder(mCapabilitiesFilter) + .setSubscriptionIds(subIds).build(); + setCapabilityFilter(newFilter); + } + } + @Override protected void needNetworkFor(NetworkRequest networkRequest) { if (!networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java index b5546a234c..23e8455dbc 100644 --- a/service/java/com/android/server/wifi/WifiApConfigStore.java +++ b/service/java/com/android/server/wifi/WifiApConfigStore.java @@ -21,6 +21,8 @@ import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_OWE_TRANSI import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE; import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STATIC_CHIP_INFO; + import android.annotation.NonNull; import android.app.compat.CompatChanges; import android.content.Context; @@ -85,6 +87,8 @@ public class WifiApConfigStore { private final WifiConfigManager mWifiConfigManager; private final ActiveModeWarden mActiveModeWarden; private final WifiNative mWifiNative; + private final HalDeviceManager mHalDeviceManager; + private final WifiSettingsConfigStore mWifiSettingsConfigStore; private boolean mHasNewDataToSerialize = false; private boolean mForceApChannel = false; private int mForcedApBand; @@ -145,6 +149,24 @@ public class WifiApConfigStore { mMacAddressUtil = wifiInjector.getMacAddressUtil(); mIsAutoAppendLowerBandEnabled = mContext.getResources().getBoolean( R.bool.config_wifiSoftapAutoAppendLowerBandsToBandConfigurationEnabled); + mHalDeviceManager = wifiInjector.getHalDeviceManager(); + mWifiSettingsConfigStore = wifiInjector.getSettingsConfigStore(); + mWifiSettingsConfigStore.registerChangeListener(WIFI_STATIC_CHIP_INFO, + (key, value) -> { + if (mPersistentWifiApConfig != null) { + Log.i(TAG, "Chip capability is updated, reset unsupported config"); + SoftApConfiguration.Builder configBuilder = + new SoftApConfiguration.Builder(mPersistentWifiApConfig); + if (SdkLevel.isAtLeastS() + && mPersistentWifiApConfig.getBands().length > 1) { + // Current band setting is dual band, check if device supports it. + if (!ApConfigUtil.isBridgedModeSupported(mContext, mWifiNative)) { + configBuilder.setBand(generateDefaultBand(mContext)); + persistConfigAndTriggerBackupManagerProxy(configBuilder.build()); + } + } + } + }, mHandler); } /** @@ -418,8 +440,11 @@ public class WifiApConfigStore { // It is new overlay configuration, it should always false in R. Add SdkLevel.isAtLeastS for // lint check - if (ApConfigUtil.isBridgedModeSupported(mContext, mWifiNative)) { - if (SdkLevel.isAtLeastS()) { + if (SdkLevel.isAtLeastS()) { + boolean isBridgedModeSupported = mHalDeviceManager.isConcurrencyComboLoadedFromDriver() + ? ApConfigUtil.isBridgedModeSupported(mContext, mWifiNative) + : ApConfigUtil.isBridgedModeSupportedInConfig(mContext); + if (isBridgedModeSupported) { int[] dual_bands = new int[] { SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ}; diff --git a/service/java/com/android/server/wifi/WifiBackupDataV1Parser.java b/service/java/com/android/server/wifi/WifiBackupDataV1Parser.java index 2d9f91e43d..0eb585fc96 100644 --- a/service/java/com/android/server/wifi/WifiBackupDataV1Parser.java +++ b/service/java/com/android/server/wifi/WifiBackupDataV1Parser.java @@ -93,7 +93,7 @@ class WifiBackupDataV1Parser implements WifiBackupDataParser { private static final String TAG = "WifiBackupDataV1Parser"; - private static final int HIGHEST_SUPPORTED_MINOR_VERSION = 3; + private static final int HIGHEST_SUPPORTED_MINOR_VERSION = 4; // List of tags supported for <WifiConfiguration> section in minor version 0 private static final Set<String> WIFI_CONFIGURATION_MINOR_V0_SUPPORTED_TAGS = Set.of( @@ -155,8 +155,23 @@ class WifiBackupDataV1Parser implements WifiBackupDataParser { WifiConfigurationXmlUtil.XML_TAG_NUM_REBOOTS_SINCE_LAST_USE); } - // List of tags supported for <IpConfiguration> section in minor version 0 to 3 - private static final Set<String> IP_CONFIGURATION_MINOR_V0_V1_V2_V3_SUPPORTED_TAGS = Set.of( + // List of tags supported for <WifiConfiguration> section in minor version 4 + private static final Set<String> WIFI_CONFIGURATION_MINOR_V4_SUPPORTED_TAGS = + new HashSet<String>(); + static { + WIFI_CONFIGURATION_MINOR_V4_SUPPORTED_TAGS.addAll( + WIFI_CONFIGURATION_MINOR_V3_SUPPORTED_TAGS); + WIFI_CONFIGURATION_MINOR_V4_SUPPORTED_TAGS.add( + WifiConfigurationXmlUtil.XML_TAG_ENABLE_WIFI7); + WIFI_CONFIGURATION_MINOR_V4_SUPPORTED_TAGS.add( + WifiConfigurationXmlUtil.XML_TAG_IS_REPEATER_ENABLED); + WIFI_CONFIGURATION_MINOR_V4_SUPPORTED_TAGS.add( + WifiConfigurationXmlUtil.XML_TAG_SEND_DHCP_HOSTNAME); + } + + // List of tags supported for <IpConfiguration> section in last minor version, i.e. version: 4 + // Note: Update the getSupportedIpConfigurationTags when the minor version is increased. + private static final Set<String> IP_CONFIGURATION_LAST_MINOR_SUPPORTED_TAGS = Set.of( IpConfigurationXmlUtil.XML_TAG_IP_ASSIGNMENT, IpConfigurationXmlUtil.XML_TAG_LINK_ADDRESS, IpConfigurationXmlUtil.XML_TAG_LINK_PREFIX_LENGTH, @@ -315,7 +330,7 @@ class WifiBackupDataV1Parser implements WifiBackupDataParser { WifiConfiguration configuration = new WifiConfiguration(); String configKeyInData = null; Set<String> supportedTags = getSupportedWifiConfigurationTags(minorVersion); - + boolean sendDhcpHostnameExists = false; // Loop through and parse out all the elements from the stream within this section. while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { String tagName = null; @@ -340,7 +355,6 @@ class WifiBackupDataV1Parser implements WifiBackupDataParser { + " section, ignoring."); continue; } - // note: the below switch case list should contain all tags supported up until the // highest minor version supported by this parser switch (tagName) { @@ -404,12 +418,29 @@ class WifiBackupDataV1Parser implements WifiBackupDataParser { case WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS_LIST: parseSecurityParamsListFromXml(in, outerTagDepth + 1, configuration); break; + // V4 + case WifiConfigurationXmlUtil.XML_TAG_IS_REPEATER_ENABLED: + configuration.setRepeaterEnabled((boolean) value); + break; + case WifiConfigurationXmlUtil.XML_TAG_ENABLE_WIFI7: + configuration.setWifi7Enabled((boolean) value); + break; + case WifiConfigurationXmlUtil.XML_TAG_SEND_DHCP_HOSTNAME: + configuration.setSendDhcpHostnameEnabled((boolean) value); + sendDhcpHostnameExists = true; + break; default: // should never happen, since other tags are filtered out earlier throw new XmlPullParserException( "Unknown value name found: " + tagName); } } + if (!sendDhcpHostnameExists) { + // Update legacy configs to send the DHCP hostname for secure networks only. + configuration.setSendDhcpHostnameEnabled( + !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN) + && !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE)); + } clearAnyKnownIssuesInParsedConfiguration(configuration); return Pair.create(configKeyInData, configuration); } @@ -432,6 +463,8 @@ class WifiBackupDataV1Parser implements WifiBackupDataParser { return WIFI_CONFIGURATION_MINOR_V2_SUPPORTED_TAGS; case 3: return WIFI_CONFIGURATION_MINOR_V3_SUPPORTED_TAGS; + case 4: + return WIFI_CONFIGURATION_MINOR_V4_SUPPORTED_TAGS; default: Log.e(TAG, "Invalid minorVersion: " + minorVersion); return Collections.<String>emptySet(); @@ -717,7 +750,8 @@ class WifiBackupDataV1Parser implements WifiBackupDataParser { case 1: case 2: case 3: - return IP_CONFIGURATION_MINOR_V0_V1_V2_V3_SUPPORTED_TAGS; + case 4: + return IP_CONFIGURATION_LAST_MINOR_SUPPORTED_TAGS; default: Log.e(TAG, "Invalid minorVersion: " + minorVersion); return Collections.<String>emptySet(); diff --git a/service/java/com/android/server/wifi/WifiBlocklistMonitor.java b/service/java/com/android/server/wifi/WifiBlocklistMonitor.java index adf313da24..c701caba64 100644 --- a/service/java/com/android/server/wifi/WifiBlocklistMonitor.java +++ b/service/java/com/android/server/wifi/WifiBlocklistMonitor.java @@ -279,12 +279,14 @@ public class WifiBlocklistMonitor { */ private long getBlocklistDurationWithExponentialBackoff(int failureStreak, int baseBlocklistDurationMs) { + long disableDurationMs = baseBlocklistDurationMs; failureStreak = Math.min(failureStreak, mContext.getResources().getInteger( R.integer.config_wifiBssidBlocklistMonitorFailureStreakCap)); - if (failureStreak < 1) { - return baseBlocklistDurationMs; + if (failureStreak >= 1) { + disableDurationMs = + (long) (Math.pow(2.0, (double) failureStreak) * baseBlocklistDurationMs); } - return (long) (Math.pow(2.0, (double) failureStreak) * baseBlocklistDurationMs); + return Math.min(disableDurationMs, mWifiGlobals.getWifiConfigMaxDisableDurationMs()); } /** @@ -1391,7 +1393,8 @@ public class WifiBlocklistMonitor { break; } } - return mClock.getElapsedSinceBootMillis() + disableDurationMs; + return mClock.getElapsedSinceBootMillis() + Math.min( + disableDurationMs, mWifiGlobals.getWifiConfigMaxDisableDurationMs()); } /** diff --git a/service/java/com/android/server/wifi/WifiCarrierInfoManager.java b/service/java/com/android/server/wifi/WifiCarrierInfoManager.java index b83896d826..e770ae23a9 100644 --- a/service/java/com/android/server/wifi/WifiCarrierInfoManager.java +++ b/service/java/com/android/server/wifi/WifiCarrierInfoManager.java @@ -55,6 +55,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Base64; import android.util.Log; import android.util.Pair; @@ -499,11 +500,33 @@ public class WifiCarrierInfoManager { ACTION_USER_DISALLOWED_CARRIER, mIsLastUserApprovalUiDialog); } + private void updateSubIdsInNetworkFactoryFilters(List<SubscriptionInfo> activeSubInfos) { + if (activeSubInfos == null || activeSubInfos.isEmpty()) { + return; + } + Set<Integer> subIds = new ArraySet<>(); + for (SubscriptionInfo subInfo : activeSubInfos) { + if (subInfo.getSubscriptionId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + subIds.add(subInfo.getSubscriptionId()); + } + } + if (mWifiInjector.getWifiNetworkFactory() != null) { + mWifiInjector.getWifiNetworkFactory().updateSubIdsInCapabilitiesFilter(subIds); + } + if (mWifiInjector.getUntrustedWifiNetworkFactory() != null) { + mWifiInjector.getUntrustedWifiNetworkFactory().updateSubIdsInCapabilitiesFilter(subIds); + } + if (mWifiInjector.getRestrictedWifiNetworkFactory() != null) { + mWifiInjector.getRestrictedWifiNetworkFactory() + .updateSubIdsInCapabilitiesFilter(subIds); + } + } private class SubscriptionChangeListener extends SubscriptionManager.OnSubscriptionsChangedListener { @Override public void onSubscriptionsChanged() { mActiveSubInfos = mSubscriptionManager.getCompleteActiveSubscriptionInfoList(); + updateSubIdsInNetworkFactoryFilters(mActiveSubInfos); mSubIdToSimInfoSparseArray.clear(); mSubscriptionGroupMap.clear(); if (mVerboseLogEnabled) { @@ -1522,22 +1545,26 @@ public class WifiCarrierInfoManager { Log.v(TAG, "Raw Response - " + tmResponse); } - boolean goodReponse = false; + boolean goodResponse = false; if (tmResponse != null && tmResponse.length() > 4) { byte[] result = Base64.decode(tmResponse, Base64.DEFAULT); Log.e(TAG, "Hex Response - " + makeHex(result)); byte tag = result[0]; if (tag == (byte) 0xdb) { Log.v(TAG, "successful 3G authentication "); - int resLen = result[1]; - String res = makeHex(result, 2, resLen); - int ckLen = result[resLen + 2]; - String ck = makeHex(result, resLen + 3, ckLen); - int ikLen = result[resLen + ckLen + 3]; - String ik = makeHex(result, resLen + ckLen + 4, ikLen); - sb.append(":" + ik + ":" + ck + ":" + res); - Log.v(TAG, "ik:" + ik + "ck:" + ck + " res:" + res); - goodReponse = true; + try { + int resLen = result[1]; + String res = makeHex(result, 2, resLen); + int ckLen = result[resLen + 2]; + String ck = makeHex(result, resLen + 3, ckLen); + int ikLen = result[resLen + ckLen + 3]; + String ik = makeHex(result, resLen + ckLen + 4, ikLen); + sb.append(":" + ik + ":" + ck + ":" + res); + Log.v(TAG, "ik:" + ik + "ck:" + ck + " res:" + res); + goodResponse = true; + } catch (ArrayIndexOutOfBoundsException e) { + Log.e(TAG, "ArrayIndexOutOfBoundsException in get3GAuthResponse: " + e); + } } else if (tag == (byte) 0xdc) { Log.e(TAG, "synchronisation failure"); int autsLen = result[1]; @@ -1545,7 +1572,7 @@ public class WifiCarrierInfoManager { resType = WifiNative.SIM_AUTH_RESP_TYPE_UMTS_AUTS; sb.append(":" + auts); Log.v(TAG, "auts:" + auts); - goodReponse = true; + goodResponse = true; } else { Log.e(TAG, "bad response - unknown tag = " + tag); } @@ -1553,7 +1580,7 @@ public class WifiCarrierInfoManager { Log.e(TAG, "bad response - " + tmResponse); } - if (goodReponse) { + if (goodResponse) { String response = sb.toString(); Log.v(TAG, "Supplicant Response -" + response); return new SimAuthResponseData(resType, response); @@ -1768,7 +1795,7 @@ public class WifiCarrierInfoManager { return; } - Log.d(TAG, msg); + Log.d(TAG, msg, null); } /** Dump state. */ diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index ec6359f900..d2f26183c3 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -61,6 +61,7 @@ import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.MacAddressUtils; import com.android.server.wifi.hotspot2.PasspointManager; import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; @@ -810,6 +811,20 @@ public class WifiConfigManager { } /** + * Check Wi-Fi 7 is enabled for this network. + * + * @param networkId networkId of the requested network. + * @return true if Wi-Fi 7 is enabled for this network, false otherwise. + */ + public boolean isWifi7Enabled(int networkId) { + WifiConfiguration config = getInternalConfiguredNetwork(networkId); + if (config == null) { + return false; + } + return config.isWifi7Enabled(); + } + + /** * Retrieves the configured network corresponding to the provided networkId with password * masked. * @@ -1272,6 +1287,8 @@ public class WifiConfigManager { externalConfig.getNetworkSelectionStatus().getConnectChoiceRssi()); internalConfig.setBssidAllowlist(externalConfig.getBssidAllowlistInternal()); internalConfig.setRepeaterEnabled(externalConfig.isRepeaterEnabled()); + internalConfig.setSendDhcpHostnameEnabled(externalConfig.isSendDhcpHostnameEnabled()); + internalConfig.setWifi7Enabled(externalConfig.isWifi7Enabled()); } /** @@ -1514,6 +1531,17 @@ public class WifiConfigManager { existingInternalConfig); } + if (WifiConfigurationUtil.hasSendDhcpHostnameEnabledChanged(existingInternalConfig, + newInternalConfig) && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) + && !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) { + Log.e(TAG, "UID " + uid + " does not have permission to modify send DHCP hostname " + + "setting " + config.getProfileKey() + ". Must have " + + "NETWORK_SETTINGS or NETWORK_SETUP_WIZARD."); + return new Pair<>( + new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID), + existingInternalConfig); + } + if (config.isEnterprise() && config.enterpriseConfig.isEapMethodServerCertUsed() && !config.enterpriseConfig.isMandatoryParameterSetForServerCertValidation() @@ -1662,6 +1690,12 @@ public class WifiConfigManager { Log.e(TAG, "Cannot add/update network with null config"); return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); } + if (SdkLevel.isAtLeastV() && config.getVendorData() != null + && !config.getVendorData().isEmpty() + && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { + Log.e(TAG, "UID " + uid + " does not have permission to include vendor data"); + return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); + } if (mPendingStoreRead) { Log.e(TAG, "Cannot add/update network before store is read!"); return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); @@ -4083,9 +4117,10 @@ public class WifiConfigManager { } /** Update WifiConfigManager before connecting to a network. */ - public void updateBeforeConnect(int networkId, int callingUid, @NonNull String packageName) { + public void updateBeforeConnect(int networkId, int callingUid, @NonNull String packageName, + boolean disableOthers) { userEnabledNetwork(networkId); - if (!enableNetwork(networkId, true, callingUid, null) + if (!enableNetwork(networkId, disableOthers, callingUid, null) || !updateLastConnectUid(networkId, callingUid)) { Log.i(TAG, "connect Allowing uid " + callingUid + " packageName " + packageName + " with insufficient permissions to connect=" + networkId); @@ -4397,12 +4432,11 @@ public class WifiConfigManager { Log.d(TAG, "Set altSubjectMatch to " + altSubjectNames); } newConfig.enterpriseConfig.setAltSubjectMatch(altSubjectNames); - } else { - if (mVerboseLoggingEnabled) { - Log.d(TAG, "Set domainSuffixMatch to " + serverCertInfo.commonName); - } - newConfig.enterpriseConfig.setDomainSuffixMatch(serverCertInfo.commonName); } + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Set domainSuffixMatch to " + serverCertInfo.commonName); + } + newConfig.enterpriseConfig.setDomainSuffixMatch(serverCertInfo.commonName); newConfig.enterpriseConfig.setUserApproveNoCaCert(false); // Trigger an update to install CA certificate and the corresponding configuration. NetworkUpdateResult result = addOrUpdateNetwork(newConfig, internalConfig.creatorUid); diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java index a1bfb7a9cb..3d14b8a002 100644 --- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java +++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java @@ -259,7 +259,7 @@ public class WifiConfigurationUtil { * MAC randomization setting has changed or not. * @param existingConfig Existing WifiConfiguration object corresponding to the network. * @param newConfig New WifiConfiguration object corresponding to the network. - * @return true if MAC randomization setting setting changed or the existing confiuration is + * @return true if MAC randomization setting changed or the existing configuration is * null and the newConfig is setting macRandomizationSetting to the default value. */ public static boolean hasMacRandomizationSettingsChanged(WifiConfiguration existingConfig, @@ -271,6 +271,22 @@ public class WifiConfigurationUtil { } /** + * Compare existing and new WifiConfiguration objects after a network update and return if + * DHCP hostname setting has changed or not. + * @param existingConfig Existing WifiConfiguration object corresponding to the network. + * @param newConfig New WifiConfiguration object corresponding to the network. + * @return true if DHCP hostname setting changed or the existing configuration is + * null and the newConfig is setting the DHCP hostname setting to the default value. + */ + public static boolean hasSendDhcpHostnameEnabledChanged(WifiConfiguration existingConfig, + WifiConfiguration newConfig) { + if (existingConfig == null) { + return !newConfig.isSendDhcpHostnameEnabled(); + } + return newConfig.isSendDhcpHostnameEnabled() != existingConfig.isSendDhcpHostnameEnabled(); + } + + /** * Compare existing and new WifiEnterpriseConfig objects after a network update and return if * credential parameters have changed or not. * @@ -957,6 +973,9 @@ public class WifiConfigurationUtil { if (WifiConfigurationUtil.hasCredentialChanged(config, config1)) { return false; } + if (config.isWifi7Enabled() != config1.isWifi7Enabled()) { + return false; + } return true; } diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java index 574b0b08b6..86483bdfbf 100644 --- a/service/java/com/android/server/wifi/WifiConnectivityManager.java +++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java @@ -268,7 +268,7 @@ public class WifiConnectivityManager { // be retrieved in bugreport. private void localLog(String log) { mLocalLog.log(log); - if (mVerboseLoggingEnabled) Log.v(TAG, log); + if (mVerboseLoggingEnabled) Log.v(TAG, log, null); } /** @@ -402,7 +402,8 @@ public class WifiConnectivityManager { // a different band with the primary. return false; } - if (WifiInjector.getInstance().getHalDeviceManager() + if (mActiveModeWarden.getClientModeManagerInRole(ROLE_CLIENT_SECONDARY_LONG_LIVED) + == null && WifiInjector.getInstance().getHalDeviceManager() .creatingIfaceWillDeletePrivilegedIface(HalDeviceManager.HDM_CREATE_IFACE_STA, mMultiInternetConnectionRequestorWs)) { localLog(listenerName + ": No secondary cmm candidate"); @@ -543,6 +544,47 @@ public class WifiConnectivityManager { return true; } + private boolean shouldSkipSufficiencyCheck(boolean hasExistingSecondaryCmm) { + if (hasExistingSecondaryCmm) { + // Secondary CMM already exists. NetworkSelector will evaluate if network selection + // should proceed + return false; + } + + // Otherwise check the various secondary use-cases. Network selection should be triggered + // if any secondary use-case is available. + if (mOemPaidConnectionAllowed || mOemPrivateConnectionAllowed) { + // prefer OEM PAID requestor if it exists. + WorkSource oemPaidOrOemPrivateRequestorWs = + mOemPaidConnectionRequestorWs != null + ? mOemPaidConnectionRequestorWs + : mOemPrivateConnectionRequestorWs; + if (oemPaidOrOemPrivateRequestorWs == null) { + Log.e(TAG, "Both mOemPaidConnectionRequestorWs & mOemPrivateConnectionRequestorWs " + + "are null!"); + } + if (oemPaidOrOemPrivateRequestorWs != null + && mActiveModeWarden.canRequestMoreClientModeManagersInRole( + oemPaidOrOemPrivateRequestorWs, + ROLE_CLIENT_SECONDARY_LONG_LIVED, false)) { + return true; + } + } + if (isMultiInternetConnectionRequested()) { + if (mMultiInternetConnectionRequestorWs == null) { + Log.e(TAG, "mMultiInternetConnectionRequestorWs is null!"); + } else if (mActiveModeWarden.canRequestMoreClientModeManagersInRole( + mMultiInternetConnectionRequestorWs, ROLE_CLIENT_SECONDARY_LONG_LIVED, false)) { + return true; + } + } + if (mActiveModeWarden.canRequestMoreClientModeManagersInRole( + ActiveModeWarden.INTERNAL_REQUESTOR_WS, ROLE_CLIENT_SECONDARY_TRANSIENT, false)) { + return true; + } + return false; + } + /** * Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener. * Executes selection of potential network candidates, initiation of connection attempt to that @@ -582,40 +624,7 @@ public class WifiConnectivityManager { } cmmStates.add(cmmState); } - // We don't have any existing secondary CMM, but are we allowed to create a secondary CMM - // and do we have a request for OEM_PAID/OEM_PRIVATE request? If yes, we need to perform - // network selection to check if we have any potential candidate for the secondary CMM - // creation. - if (!hasExistingSecondaryCmm - && (mOemPaidConnectionAllowed || mOemPrivateConnectionAllowed)) { - // prefer OEM PAID requestor if it exists. - WorkSource oemPaidOrOemPrivateRequestorWs = - mOemPaidConnectionRequestorWs != null - ? mOemPaidConnectionRequestorWs - : mOemPrivateConnectionRequestorWs; - if (oemPaidOrOemPrivateRequestorWs == null) { - Log.e(TAG, "Both mOemPaidConnectionRequestorWs & mOemPrivateConnectionRequestorWs " - + "are null!"); - } - if (oemPaidOrOemPrivateRequestorWs != null - && mActiveModeWarden.canRequestMoreClientModeManagersInRole( - oemPaidOrOemPrivateRequestorWs, - ROLE_CLIENT_SECONDARY_LONG_LIVED, false)) { - // Add a placeholder CMM state to ensure network selection is performed for a - // potential second STA creation. - cmmStates.add(new WifiNetworkSelector.ClientModeManagerState()); - hasExistingSecondaryCmm = true; - } - } - // If secondary cmm has not been created and need to connect secondary internet - if (!hasExistingSecondaryCmm && isMultiInternetConnectionRequested()) { - if (mMultiInternetConnectionRequestorWs == null) { - Log.e(TAG, "mMultiInternetConnectionRequestorWs is null!"); - } else if (mActiveModeWarden.canRequestMoreClientModeManagersInRole( - mMultiInternetConnectionRequestorWs, ROLE_CLIENT_SECONDARY_LONG_LIVED, false)) { - cmmStates.add(new WifiNetworkSelector.ClientModeManagerState()); - } - } + boolean skipSufficiencyCheck = shouldSkipSufficiencyCheck(hasExistingSecondaryCmm); // Check if any blocklisted BSSIDs can be freed. List<ScanDetail> enabledDetails = @@ -638,7 +647,7 @@ public class WifiConnectivityManager { List<WifiCandidates.Candidate> candidates = mNetworkSelector.getCandidatesFromScan( scanDetails, bssidBlocklist, cmmStates, mUntrustedConnectionAllowed, mOemPaidConnectionAllowed, mOemPrivateConnectionAllowed, - mRestrictedConnectionAllowedUids, isMultiInternetConnectionRequested()); + mRestrictedConnectionAllowedUids, skipSufficiencyCheck); mLatestCandidates = candidates; mLatestCandidatesTimestampMs = mClock.getElapsedSinceBootMillis(); diff --git a/service/java/com/android/server/wifi/WifiCountryCode.java b/service/java/com/android/server/wifi/WifiCountryCode.java index cad634aa67..46c23937c9 100644 --- a/service/java/com/android/server/wifi/WifiCountryCode.java +++ b/service/java/com/android/server/wifi/WifiCountryCode.java @@ -61,6 +61,9 @@ public class WifiCountryCode { private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode"; private static final int PKT_COUNT_HIGH_PKT_PER_SEC = 16; private static final int DISCONNECT_WIFI_COUNT_MAX = 1; + /* TODO: replace with PackageManager.FEATURE_TELEPHONY_CALLING once + * wifi-module-sdk-version-defaults min_sdk_version bumps to API 33. */ + private static final String FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling"; static final int MIN_COUNTRY_CODE_COUNT_US = 3; static final int MIN_COUNTRY_CODE_COUNT_OTHER = 2; static final String COUNTRY_CODE_US = "US"; @@ -77,6 +80,7 @@ public class WifiCountryCode { private final WifiPermissionsUtil mWifiPermissionsUtil; private List<ChangeListener> mListeners = new ArrayList<>(); private boolean mVerboseLoggingEnabled = false; + private boolean mIsCountryCodePendingToUpdateToCmm = true; // default to true for first update. /** * Map of active ClientModeManager instance to whether it is ready for country code change. * @@ -301,6 +305,15 @@ public class WifiCountryCode { mVerboseLoggingEnabled = verbose; } + private boolean hasCalling() { + return mContext.getPackageManager().hasSystemFeature(FEATURE_TELEPHONY_CALLING); + } + + /** + * Check if Wi-Fi calling is available. + * + * This method can only be called if device has calling feature (see hasCalling()). + */ private boolean isWifiCallingAvailable() { SubscriptionManager subscriptionManager = mContext.getSystemService(SubscriptionManager.class); @@ -364,7 +377,7 @@ public class WifiCountryCode { */ private void evaluateAllCmmStateAndApplyIfAllReady() { Log.d(TAG, "evaluateAllCmmStateAndApplyIfAllReady: " + mAmmToReadyForChangeMap); - if (isAllCmmReady()) { + if (isAllCmmReady() && mIsCountryCodePendingToUpdateToCmm) { mAllCmmReadyTimestamp = FORMATTER.format(new Date(mClock.getWallClockMillis())); // We are ready to set country code now. // We need to post pending country code request. @@ -534,7 +547,7 @@ public class WifiCountryCode { } private boolean shouldDisconnectWifiToForceUpdate() { - if (isWifiCallingAvailable()) { + if (!hasCalling() || isWifiCallingAvailable()) { return false; } @@ -699,8 +712,12 @@ public class WifiCountryCode { Log.d(TAG, "setCountryCodeNative: " + country + ", isClientModeOnly: " + isClientModeOnly + " mDriverCountryCode: " + mDriverCountryCode); for (ActiveModeManager am : amms) { - if (isNeedToUpdateCCToSta && !isConcreteClientModeManagerUpdated + if (!isConcreteClientModeManagerUpdated && am instanceof ConcreteClientModeManager) { + mIsCountryCodePendingToUpdateToCmm = !isNeedToUpdateCCToSta; + if (!isNeedToUpdateCCToSta) { + continue; + } // Set the country code using one of the active mode managers. Since // country code is a chip level global setting, it can be set as long // as there is at least one active interface to communicate to Wifi chip @@ -731,7 +748,7 @@ public class WifiCountryCode { SoftApModeConfiguration modeConfig = sm.getSoftApModeConfiguration(); SoftApModeConfiguration newModeConfig = new SoftApModeConfiguration( modeConfig.getTargetMode(), modeConfig.getSoftApConfiguration(), - modeConfig.getCapability(), country); + modeConfig.getCapability(), country, modeConfig.getTetheringRequest()); mActiveModeWarden.stopSoftAp(modeConfig.getTargetMode()); mActiveModeWarden.startSoftAp(newModeConfig, sm.getRequestorWs()); } else { @@ -768,6 +785,9 @@ public class WifiCountryCode { mDriverCountryCode = country; mWifiP2pMetrics.setIsCountryCodeWorldMode(isDriverCountryCodeWorldMode()); notifyListener(country); + if (country == null) { + mIsCountryCodePendingToUpdateToCmm = true; + } } /** diff --git a/service/java/com/android/server/wifi/WifiDataStall.java b/service/java/com/android/server/wifi/WifiDataStall.java index 85d40760c2..64e370bd9e 100644 --- a/service/java/com/android/server/wifi/WifiDataStall.java +++ b/service/java/com/android/server/wifi/WifiDataStall.java @@ -595,7 +595,7 @@ public class WifiDataStall { private void logd(String string) { if (mVerboseLoggingEnabled) { - Log.d(TAG, string); + Log.d(TAG, string, null); } } } diff --git a/service/java/com/android/server/wifi/WifiDialogManager.java b/service/java/com/android/server/wifi/WifiDialogManager.java index b7a0c40a48..c189590ef6 100644 --- a/service/java/com/android/server/wifi/WifiDialogManager.java +++ b/service/java/com/android/server/wifi/WifiDialogManager.java @@ -90,17 +90,7 @@ public class WifiDialogManager { if (mVerboseLoggingEnabled) { Log.v(TAG, "Received action: " + action); } - if (Intent.ACTION_SCREEN_OFF.equals(action)) { - // Change all window types to TYPE_APPLICATION_OVERLAY to - // prevent the dialogs from appearing over the lock screen when - // the screen turns on again. - for (LegacySimpleDialogHandle dialogHandle : - mActiveLegacySimpleDialogs) { - dialogHandle.changeWindowType( - WindowManager.LayoutParams - .TYPE_APPLICATION_OVERLAY); - } - } else if (Intent.ACTION_USER_PRESENT.equals(action)) { + if (Intent.ACTION_USER_PRESENT.equals(action)) { // Change all window types to TYPE_KEYGUARD_DIALOG to show the // dialogs over the QuickSettings after the screen is unlocked. for (LegacySimpleDialogHandle dialogHandle : @@ -139,12 +129,11 @@ public class WifiDialogManager { public WifiDialogManager( @NonNull WifiContext context, @NonNull WifiThreadRunner wifiThreadRunner, - @NonNull FrameworkFacade frameworkFacade) { + @NonNull FrameworkFacade frameworkFacade, WifiInjector wifiInjector) { mContext = context; mWifiThreadRunner = wifiThreadRunner; mFrameworkFacade = frameworkFacade; IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_USER_PRESENT); intentFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); int flags = 0; @@ -152,6 +141,34 @@ public class WifiDialogManager { flags = Context.RECEIVER_EXPORTED; } mContext.registerReceiver(mBroadcastReceiver, intentFilter, flags); + wifiInjector.getWifiDeviceStateChangeManager() + .registerStateChangeCallback( + new WifiDeviceStateChangeManager.StateChangeCallback() { + @Override + public void onScreenStateChanged(boolean screenOn) { + handleScreenStateChanged(screenOn); + } + }); + } + + private void handleScreenStateChanged(boolean screenOn) { + // Change all window types to TYPE_APPLICATION_OVERLAY to + // prevent the dialogs from appearing over the lock screen when + // the screen turns on again. + if (!screenOn) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "onScreenStateChanged: screen off"); + } + // Change all window types to TYPE_APPLICATION_OVERLAY to + // prevent the dialogs from appearing over the lock screen when + // the screen turns on again. + for (LegacySimpleDialogHandle dialogHandle : + mActiveLegacySimpleDialogs) { + dialogHandle.changeWindowType( + WindowManager.LayoutParams + .TYPE_APPLICATION_OVERLAY); + } + } } /** diff --git a/service/java/com/android/server/wifi/WifiGlobals.java b/service/java/com/android/server/wifi/WifiGlobals.java index b6cc4153e6..454d8c25c7 100644 --- a/service/java/com/android/server/wifi/WifiGlobals.java +++ b/service/java/com/android/server/wifi/WifiGlobals.java @@ -55,10 +55,12 @@ public class WifiGlobals { private final AtomicBoolean mIsBluetoothConnected = new AtomicBoolean(false); // Set default to false to check if the value will be overridden by WifiSettingConfigStore. private final AtomicBoolean mIsWepAllowed = new AtomicBoolean(false); + private final AtomicBoolean mIsD2dStaConcurrencySupported = new AtomicBoolean(false); + private final AtomicInteger mSendDhcpHostnameRestriction = new AtomicInteger(); // These are read from the overlay, cache them after boot up. private final boolean mIsWpa3SaeUpgradeEnabled; - private final boolean mIsWpa3SaeUpgradeOffloadEnabled; + private boolean mIsWpa3SaeUpgradeOffloadEnabled; private final boolean mIsOweUpgradeEnabled; private final boolean mFlushAnqpCacheOnWifiToggleOffEvent; private final boolean mIsWpa3SaeH2eSupported; @@ -76,10 +78,13 @@ public class WifiGlobals { private final int mClientRssiMonitorHysteresisDb; private boolean mDisableFirmwareRoamingInIdleMode = false; private final boolean mIsSupportMultiInternetDual5G; + private final int mRepeatedNudFailuresThreshold; + private final int mRepeatedNudFailuresWindowMs; private final boolean mAdjustPollRssiIntervalEnabled; private final boolean mWifiInterfaceAddedSelfRecoveryEnabled; private final int mNetworkNotFoundEventThreshold; private boolean mIsBackgroundScanSupported; + private boolean mIsSwPnoEnabled; private final boolean mIsWepDeprecated; private final boolean mIsWpaPersonalDeprecated; private final Map<String, List<String>> mCountryCodeToAfcServers; @@ -90,6 +95,7 @@ public class WifiGlobals { private boolean mDisableUnwantedNetworkOnLowRssi = false; private final boolean mIsAfcSupportedOnDevice; private boolean mDisableNudDisconnectsForWapiInSpecificCc = false; + private boolean mD2dAllowedControlSupportedWhenInfraStaDisabled = false; private Set<String> mMacRandomizationUnsupportedSsidPrefixes = new ArraySet<>(); private Map<String, BiFunction<String, Boolean, Boolean>> mOverrideMethods = new HashMap<>(); @@ -142,6 +148,10 @@ public class WifiGlobals { .getBoolean(R.bool.config_wifiDisableFirmwareRoamingInIdleMode); mIsSupportMultiInternetDual5G = mContext.getResources().getBoolean( R.bool.config_wifiAllowMultiInternetConnectDual5GFrequency); + mRepeatedNudFailuresThreshold = mContext.getResources() + .getInteger(R.integer.config_wifiDisableReasonRepeatedNudFailuresThreshold); + mRepeatedNudFailuresWindowMs = mContext.getResources() + .getInteger(R.integer.config_wifiDisableReasonRepeatedNudFailuresWindowMs); mWifiInterfaceAddedSelfRecoveryEnabled = mContext.getResources().getBoolean( R.bool.config_wifiInterfaceAddedSelfRecoveryEnabled); mDisableUnwantedNetworkOnLowRssi = mContext.getResources().getBoolean( @@ -152,6 +162,8 @@ public class WifiGlobals { R.integer.config_wifiNetworkNotFoundEventThreshold); mIsBackgroundScanSupported = mContext.getResources() .getBoolean(R.bool.config_wifi_background_scan_support); + mIsSwPnoEnabled = mContext.getResources() + .getBoolean(R.bool.config_wifiSwPnoEnabled); mIsWepDeprecated = mContext.getResources() .getBoolean(R.bool.config_wifiWepDeprecated); mIsWpaPersonalDeprecated = mContext.getResources() @@ -161,6 +173,8 @@ public class WifiGlobals { && mContext.getResources().getBoolean(R.bool.config_wifi6ghzSupport); mWifiConfigMaxDisableDurationMs = mContext.getResources() .getInteger(R.integer.config_wifiDisableTemporaryMaximumDurationMs); + mD2dAllowedControlSupportedWhenInfraStaDisabled = mContext.getResources() + .getBoolean(R.bool.config_wifiD2dAllowedControlSupportedWhenInfraStaDisabled); Set<String> unsupportedSsidPrefixes = new ArraySet<>(mContext.getResources().getStringArray( R.array.config_wifiForceDisableMacRandomizationSsidPrefixList)); mCountryCodeToAfcServers = getCountryCodeToAfcServersMap(); @@ -389,6 +403,20 @@ public class WifiGlobals { } /** + * Get number of repeated NUD failures needed to disable a network. + */ + public int getRepeatedNudFailuresThreshold() { + return mRepeatedNudFailuresThreshold; + } + + /** + * Get the time window in millis to count for repeated NUD failures. + */ + public int getRepeatedNudFailuresWindowMs() { + return mRepeatedNudFailuresWindowMs; + } + + /** * Helper method to check if the device may not connect to the configuration * due to deprecated security type */ @@ -424,6 +452,16 @@ public class WifiGlobals { } /** + * Helper method to enable WPA3 SAE auto-upgrade offload based on the device capability for + * CROSS-AKM support. + */ + public void setWpa3SaeUpgradeOffloadEnabled() { + Log.d(TAG, "Device supports CROSS-AKM feature - Enable WPA3 SAE auto-upgrade offload"); + mIsWpa3SaeUpgradeOffloadEnabled = true; + } + + + /** * Help method to check if OWE auto-upgrade is enabled. * * @return boolean true if auto-upgrade is enabled, false otherwise. @@ -573,6 +611,13 @@ public class WifiGlobals { }; /** + * Get whether software pno is enabled. + */ + public boolean isSwPnoEnabled() { + return mIsSwPnoEnabled; + }; + + /** * Get whether to temporarily disable a unwanted network that has low RSSI. */ public boolean disableUnwantedNetworkOnLowRssi() { @@ -608,6 +653,37 @@ public class WifiGlobals { } /** + * Set whether the device supports device-to-device + STA concurrency. + */ + public void setD2dStaConcurrencySupported(boolean isSupported) { + mIsD2dStaConcurrencySupported.set(isSupported); + } + + /** + * Returns whether the device supports device-to-device when infra STA is disabled. + */ + public boolean isD2dSupportedWhenInfraStaDisabled() { + return mD2dAllowedControlSupportedWhenInfraStaDisabled + && !mIsD2dStaConcurrencySupported.get(); + } + + /** + * Set the global dhcp hostname restriction. + */ + public void setSendDhcpHostnameRestriction( + @WifiManager.SendDhcpHostnameRestriction int restriction) { + mSendDhcpHostnameRestriction.set(restriction); + } + + /** + * Get the global dhcp hostname restriction. + */ + @WifiManager.SendDhcpHostnameRestriction + public int getSendDhcpHostnameRestriction() { + return mSendDhcpHostnameRestriction.get(); + } + + /** * Get the maximum Wifi temporary disable duration. */ public long getWifiConfigMaxDisableDurationMs() { @@ -654,12 +730,19 @@ public class WifiGlobals { pw.println("mDisableUnwantedNetworkOnLowRssi=" + mDisableUnwantedNetworkOnLowRssi); pw.println("mNetworkNotFoundEventThreshold=" + mNetworkNotFoundEventThreshold); pw.println("mIsBackgroundScanSupported=" + mIsBackgroundScanSupported); + pw.println("mIsSwPnoEnabled=" + mIsSwPnoEnabled); pw.println("mIsWepDeprecated=" + mIsWepDeprecated); pw.println("mIsWpaPersonalDeprecated=" + mIsWpaPersonalDeprecated); pw.println("mIsWepAllowed=" + mIsWepAllowed.get()); pw.println("mDisableFirmwareRoamingInIdleMode=" + mDisableFirmwareRoamingInIdleMode); + pw.println("mRepeatedNudFailuresThreshold=" + mRepeatedNudFailuresThreshold); + pw.println("mRepeatedNudFailuresWindowMs=" + mRepeatedNudFailuresWindowMs); pw.println("mCarrierSpecificEapFailureConfigMapPerCarrierId mapping below:"); pw.println("mWifiConfigMaxDisableDurationMs=" + mWifiConfigMaxDisableDurationMs); + pw.println("mD2dAllowedControlSupportedWhenInfraStaDisabled=" + + mD2dAllowedControlSupportedWhenInfraStaDisabled); + pw.println("IsD2dSupportedWhenInfraStaDisabled=" + + isD2dSupportedWhenInfraStaDisabled()); for (int i = 0; i < mCarrierSpecificEapFailureConfigMapPerCarrierId.size(); i++) { int carrierId = mCarrierSpecificEapFailureConfigMapPerCarrierId.keyAt(i); SparseArray<CarrierSpecificEapFailureConfig> perFailureMap = @@ -674,5 +757,6 @@ public class WifiGlobals { } } pw.println("mIsSupportMultiInternetDual5G=" + mIsSupportMultiInternetDual5G); + pw.println("mSendDhcpHostnameRestriction=" + mSendDhcpHostnameRestriction.get()); } } diff --git a/service/java/com/android/server/wifi/WifiHealthMonitor.java b/service/java/com/android/server/wifi/WifiHealthMonitor.java index 7c26902f00..9ed1491f83 100644 --- a/service/java/com/android/server/wifi/WifiHealthMonitor.java +++ b/service/java/com/android/server/wifi/WifiHealthMonitor.java @@ -319,7 +319,7 @@ public class WifiHealthMonitor { } private void setPostBootDetectionAlarm() { - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, mClock.getElapsedSinceBootMillis() + POST_BOOT_DETECTION_WAIT_TIME_MS, POST_BOOT_DETECTION_TIMER_TAG, mPostBootDetectionListener, mHandler); @@ -1026,7 +1026,7 @@ public class WifiHealthMonitor { private void logd(String string) { if (mVerboseLoggingEnabled) { - Log.d(TAG, string); + Log.d(TAG, string, null); } } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 889c935f06..ff699bbc57 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -33,6 +33,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.wifi.WifiContext; import android.net.wifi.WifiScanner; +import android.net.wifi.WifiTwtSession; import android.net.wifi.nl80211.WifiNl80211Manager; import android.os.BatteryManager; import android.os.BatteryStatsManager; @@ -54,6 +55,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.BackgroundThread; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.aware.WifiAwareMetrics; +import com.android.server.wifi.b2b.WifiRoamingModeManager; import com.android.server.wifi.coex.CoexManager; import com.android.server.wifi.hotspot2.PasspointManager; import com.android.server.wifi.hotspot2.PasspointNetworkNominateHelper; @@ -183,9 +185,11 @@ public class WifiInjector { private final PropertyService mPropertyService = new SystemPropertyService(); private final BuildProperties mBuildProperties = new SystemBuildProperties(); private final WifiBackupRestore mWifiBackupRestore; + private final BackupRestoreController mBackupRestoreController; // This will only be null if SdkLevel is not at least S @Nullable private final CoexManager mCoexManager; private final SoftApBackupRestore mSoftApBackupRestore; + private final WifiSettingsBackupRestore mWifiSettingsBackupRestore; private final WifiMulticastLockManager mWifiMulticastLockManager; private final WifiConfigStore mWifiConfigStore; private final WifiKeyStore mWifiKeyStore; @@ -266,6 +270,8 @@ public class WifiInjector { @NonNull private final WifiDialogManager mWifiDialogManager; @NonNull private final SsidTranslator mSsidTranslator; @NonNull private final ApplicationQosPolicyRequestHandler mApplicationQosPolicyRequestHandler; + private final WifiRoamingModeManager mWifiRoamingModeManager; + private final TwtManager mTwtManager; public WifiInjector(WifiContext context) { if (context == null) { @@ -322,7 +328,8 @@ public class WifiInjector { mSoftApBackupRestore = new SoftApBackupRestore(mContext, mSettingsMigrationDataHolder); mWifiStateTracker = new WifiStateTracker(mBatteryStats); mWifiThreadRunner = new WifiThreadRunner(wifiHandler); - mWifiDialogManager = new WifiDialogManager(mContext, mWifiThreadRunner, mFrameworkFacade); + mWifiDialogManager = new WifiDialogManager(mContext, mWifiThreadRunner, mFrameworkFacade, + this); mSsidTranslator = new SsidTranslator(mContext, wifiHandler); mWifiP2pServiceHandlerThread = new HandlerThread("WifiP2pService"); mWifiP2pServiceHandlerThread.start(); @@ -354,7 +361,7 @@ public class WifiInjector { mWifiP2pMonitor = new WifiP2pMonitor(); mSupplicantP2pIfaceHal = new SupplicantP2pIfaceHal(mWifiP2pMonitor, mWifiGlobals, this); mWifiP2pNative = new WifiP2pNative(mWifiCondManager, mWifiNative, mWifiMetrics, - mWifiVendorHal, mSupplicantP2pIfaceHal, mHalDeviceManager, mPropertyService); + mWifiVendorHal, mSupplicantP2pIfaceHal, mHalDeviceManager, mPropertyService, this); SubscriptionManager subscriptionManager = mContext.getSystemService(SubscriptionManager.class); if (SdkLevel.isAtLeastS()) { @@ -439,6 +446,7 @@ public class WifiInjector { wifiHandler); mSettingsConfigStore = new WifiSettingsConfigStore(context, wifiHandler, mSettingsMigrationDataHolder, mWifiConfigManager, mWifiConfigStore); + mWifiSettingsBackupRestore = new WifiSettingsBackupRestore(mSettingsConfigStore); mSettingsStore = new WifiSettingsStore(mContext, mSettingsConfigStore, mWifiThreadRunner, mFrameworkFacade, mWifiNotificationManager, mDeviceConfigFacade, mWifiMetrics, mClock); @@ -614,6 +622,13 @@ public class WifiInjector { // {@link LocationManager#getCurrentLocation}, so we need to pass mContextWithAttributionTag // instead of mContext to the AfcManager. mAfcManager = new AfcManager(mContextWithAttributionTag, this); + mWifiRoamingModeManager = new WifiRoamingModeManager(mWifiNative, + mActiveModeWarden, new WifiRoamingConfigStore(mWifiConfigManager, + mWifiConfigStore)); + + mTwtManager = new TwtManager(this, mCmiMonitor, mWifiNative, wifiHandler, mClock, + WifiTwtSession.MAX_TWT_SESSIONS, 1); + mBackupRestoreController = new BackupRestoreController(mWifiSettingsBackupRestore, mClock); } /** @@ -673,6 +688,7 @@ public class WifiInjector { mWifiDialogManager.enableVerboseLogging(verboseEnabled); mExternalPnoScanRequestManager.enableVerboseLogging(verboseEnabled); mMultiInternetWifiNetworkFactory.enableVerboseLogging(verboseEnabled); + mWifiRoamingModeManager.enableVerboseLogging(verboseEnabled); } public UserManager getUserManager() { @@ -1128,6 +1144,11 @@ public class WifiInjector { return mSettingsConfigStore; } + @NonNull + public WifiSettingsBackupRestore getWifiSettingsBackupRestore() { + return mWifiSettingsBackupRestore; + } + public WifiScanAlwaysAvailableSettingsCompatibility getWifiScanAlwaysAvailableSettingsCompatibility() { return mWifiScanAlwaysAvailableSettingsCompatibility; @@ -1307,4 +1328,17 @@ public class WifiInjector { public AlarmManager getAlarmManager() { return mAlarmManager; } + + public WifiRoamingModeManager getWifiRoamingModeManager() { + return mWifiRoamingModeManager; + } + + public TwtManager getTwtManager() { + return mTwtManager; + } + + @NonNull + public BackupRestoreController getBackupRestoreController() { + return mBackupRestoreController; + } } diff --git a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java index 86228edded..462e2b92ef 100644 --- a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java +++ b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java @@ -850,13 +850,13 @@ public class WifiLastResortWatchdog { private void logv(String s) { mLocalLog.log(s); if (mVerboseLoggingEnabled) { - Log.v(TAG, s); + Log.v(TAG, s, null); } } private void loge(String s) { mLocalLog.log(s); - Log.e(TAG, s); + Log.e(TAG, s, null); } /** diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index a6c6d8f31b..402ea5491d 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -711,6 +711,7 @@ public class WifiMetrics { private boolean mIsEcpsPriorityAccessSupported = false; private NetworkDetail.HSRelease mHsRelease = NetworkDetail.HSRelease.Unknown; private ApType6GHz mApType6GHz = ApType6GHz.AP_TYPE_6GHZ_UNKNOWN; + public @WifiAnnotations.ChannelWidth int mChannelWidth = ScanResult.UNSPECIFIED; public String toString() { StringBuilder sb = new StringBuilder(); @@ -746,6 +747,7 @@ public class WifiMetrics { sb.append(", mApType6Ghz=" + mApType6GHz); sb.append(", mIsEcpsPriorityAccessSupported=" + mIsEcpsPriorityAccessSupported); sb.append(", mHsRelease=" + mHsRelease); + sb.append(", mChannelWidth" + mChannelWidth); } return sb.toString(); } @@ -1175,6 +1177,7 @@ public class WifiMetrics { private boolean mIsCarrierWifi; private boolean mIsOobPseudonymEnabled; private int mRole; + private int mUid; private int mCarrierId; private int mEapType; private int mPhase2Method; @@ -1428,6 +1431,7 @@ public class WifiMetrics { + mConnectionEvent.isFirstConnectionAfterBoot); sb.append(", isCarrierWifi=" + mIsCarrierWifi); sb.append(", isOobPseudonymEnabled=" + mIsOobPseudonymEnabled); + sb.append(", uid=" + mUid); return sb.toString(); } } @@ -1922,7 +1926,7 @@ public class WifiMetrics { */ public int startConnectionEvent( String ifaceName, WifiConfiguration config, String targetBSSID, int roamType, - boolean isOobPseudonymEnabled, int role) { + boolean isOobPseudonymEnabled, int role, int uid) { synchronized (mLock) { int overlapWithLastConnectionMs = 0; ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName); @@ -1974,6 +1978,7 @@ public class WifiMetrics { currentConnectionEvent.mConnectionEvent.isFirstConnectionAfterBoot = mFirstConnectionAfterBoot; currentConnectionEvent.mRole = role; + currentConnectionEvent.mUid = uid; mFirstConnectionAfterBoot = false; mConnectionEventList.add(currentConnectionEvent); mScanResultRssiTimestampMillis = -1; @@ -2126,6 +2131,20 @@ public class WifiMetrics { } /** + * Set channel width of the current connection. + */ + public void setConnectionChannelWidth(String interfaceName, + @WifiAnnotations.ChannelWidth int channelWidth) { + synchronized (mLock) { + ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get( + interfaceName); + if (currentConnectionEvent != null) { + currentConnectionEvent.mRouterFingerPrint.mChannelWidth = channelWidth; + } + } + } + + /** * Set the max link speed supported by current network */ public void setConnectionMaxSupportedLinkSpeedMbps( @@ -2210,10 +2229,10 @@ public class WifiMetrics { currentConnectionEvent.mConfigSsid, mClock.getElapsedSinceBootMillis(), band, currentConnectionEvent.mAuthType); - - // TODO(b/166309727) need to add ifaceName to WifiStatsLog - WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED, - true, band, currentConnectionEvent.mAuthType); + if (currentConnectionEvent.mRole == WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY) { + WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED, + true, band, currentConnectionEvent.mAuthType); + } } currentConnectionEvent.mConnectionEvent.connectionResult = @@ -2247,7 +2266,8 @@ public class WifiMetrics { toMetricPhase2Method(currentConnectionEvent.mPhase2Method), currentConnectionEvent.mPasspointRoamingType, currentConnectionEvent.mCarrierId, - currentConnectionEvent.mTofuConnectionState); + currentConnectionEvent.mTofuConnectionState, + currentConnectionEvent.mUid); if (connectionSucceeded) { reportRouterCapabilities(currentConnectionEvent.mRouterFingerPrint); @@ -2642,6 +2662,25 @@ public class WifiMetrics { == WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__PASSPOINT_ROAMING_TYPE__ROAMING_RCOI_OPENROAMING_SETTLED; } + private int convertChannelWidthToProto(@WifiAnnotations.ChannelWidth int channelWidth) { + switch(channelWidth) { + case ScanResult.CHANNEL_WIDTH_20MHZ: + return WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_20MHZ; + case ScanResult.CHANNEL_WIDTH_40MHZ: + return WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_40MHZ; + case ScanResult.CHANNEL_WIDTH_80MHZ: + return WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_80MHZ; + case ScanResult.CHANNEL_WIDTH_160MHZ: + return WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_160MHZ; + case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: + return WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_80MHZ_PLUS_MHZ; + case ScanResult.CHANNEL_WIDTH_320MHZ: + return WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_320MHZ; + default: + return WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_UNKNOWN; + } + } + private void reportRouterCapabilities(RouterFingerPrint r) { WifiStatsLog.write(WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED, r.mIsFrameworkInitiatedRoaming, r.mRouterFingerPrintProto.channelInfo, @@ -2657,7 +2696,8 @@ public class WifiMetrics { r.mIsBroadcastTwtSupported, r.mIsRestrictedTwtSupported, r.mIs11McSupported, r.mIs11AzSupported, convertHsReleasetoProto(r.mHsRelease), r.mRouterFingerPrintProto.isPasspointHomeProvider, - convertApType6GhzToProto(r.mApType6GHz), r.mIsEcpsPriorityAccessSupported); + convertApType6GhzToProto(r.mApType6GHz), r.mIsEcpsPriorityAccessSupported, + convertChannelWidthToProto(r.mChannelWidth)); } /** @@ -2673,12 +2713,13 @@ public class WifiMetrics { if (!isPrimary(ifaceName)) { return; } - WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED, - false, - mCurrentSession != null ? mCurrentSession.mBand : 0, - mCurrentSession != null ? mCurrentSession.mAuthType : 0); - if (mCurrentSession != null) { + if (mCurrentSession.mConnectionEvent.mRole == WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY) { + WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED, + false, + mCurrentSession.mBand, + mCurrentSession.mAuthType); + } mCurrentSession.mSessionEndTimeMillis = mClock.getElapsedSinceBootMillis(); int durationSeconds = (int) (mCurrentSession.mSessionEndTimeMillis - mCurrentSession.mSessionStartTimeMillis) / 1000; @@ -2849,7 +2890,7 @@ public class WifiMetrics { currentConnectionEvent.mRouterFingerPrint.mIsTwtRequired = networkDetail.isTwtRequired(); currentConnectionEvent.mRouterFingerPrint.mIsFilsSupported = networkDetail.isFilsCapable(); currentConnectionEvent.mRouterFingerPrint.mIs11AzSupported = - networkDetail.is11azSupported(); + networkDetail.is80211azNtbResponder() || networkDetail.is80211azTbResponder(); currentConnectionEvent.mRouterFingerPrint.mIs11McSupported = networkDetail.is80211McResponderSupport(); currentConnectionEvent.mRouterFingerPrint.mIsMboSupported = networkDetail.isMboSupported(); @@ -4860,9 +4901,6 @@ public class WifiMetrics { + mContext.getResources().getBoolean( R.bool.config_wifi_connected_mac_randomization_supported)); pw.println("mWifiLogProto.scoreExperimentId=" + mWifiLogProto.scoreExperimentId); - pw.println("mExperimentValues.wifiIsUnusableLoggingEnabled=" - + mContext.getResources().getBoolean( - R.bool.config_wifiIsUnusableEventMetricsEnabled)); pw.println("mExperimentValues.wifiDataStallMinTxBad=" + mContext.getResources().getInteger( R.integer.config_wifiDataStallMinTxBad)); @@ -5565,8 +5603,6 @@ public class WifiMetrics { mWifiLogProto.wifiWakeStats = mWifiWakeMetrics.buildProto(); mWifiLogProto.isMacRandomizationOn = mContext.getResources().getBoolean( R.bool.config_wifi_connected_mac_randomization_supported); - mExperimentValues.wifiIsUnusableLoggingEnabled = mContext.getResources().getBoolean( - R.bool.config_wifiIsUnusableEventMetricsEnabled); mExperimentValues.linkSpeedCountsLoggingEnabled = mContext.getResources().getBoolean( R.bool.config_wifiLinkSpeedMetricsEnabled); mExperimentValues.wifiDataStallMinTxBad = mContext.getResources().getInteger( @@ -6876,9 +6912,6 @@ public class WifiMetrics { return; } mScoreBreachLowTimeMillis = -1; - if (!mContext.getResources().getBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled)) { - return; - } long currentBootTime = mClock.getElapsedSinceBootMillis(); switch (triggerType) { @@ -7768,7 +7801,7 @@ public class WifiMetrics { /** * Add a new listener for Wi-Fi usability stats handling. */ - public void addOnWifiUsabilityListener(IOnWifiUsabilityStatsListener listener) { + public void addOnWifiUsabilityListener(@NonNull IOnWifiUsabilityStatsListener listener) { if (!mOnWifiUsabilityListeners.register(listener)) { Log.e(TAG, "Failed to add listener"); return; @@ -7782,7 +7815,7 @@ public class WifiMetrics { /** * Remove an existing listener for Wi-Fi usability stats handling. */ - public void removeOnWifiUsabilityListener(IOnWifiUsabilityStatsListener listener) { + public void removeOnWifiUsabilityListener(@NonNull IOnWifiUsabilityStatsListener listener) { mOnWifiUsabilityListeners.unregister(listener); if (DBG) { Log.v(TAG, "Removing listener. Num listeners: " @@ -9424,6 +9457,10 @@ public class WifiMetrics { getSoftApStartedStaApConcurrency(isStaApSupported, isStaDbsSupported), getSoftApStartedStaStatus(staFreqMhz), getSoftApStartedAuthType(securityType)); + if (startResult == SoftApManager.START_RESULT_SUCCESS) { + WifiStatsLog.write(WifiStatsLog.SOFT_AP_STATE_CHANGED, + WifiStatsLog.SOFT_AP_STATE_CHANGED__HOTSPOT_ON__STATE_ON); + } } private static int getSoftApStoppedStopEvent(@SoftApManager.StopEvent int stopEvent) { @@ -9608,5 +9645,7 @@ public class WifiMetrics { dbsFailureBand, dbsTimeoutBand, getSoftApStoppedUpstreamType(upstreamCaps)); + WifiStatsLog.write(WifiStatsLog.SOFT_AP_STATE_CHANGED, + WifiStatsLog.SOFT_AP_STATE_CHANGED__HOTSPOT_ON__STATE_OFF); } } diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 69f61808da..9c2237e7a3 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -21,7 +21,10 @@ import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP; import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE; import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA; +import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_P2P; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_NATIVE_SUPPORTED_FEATURES; +import static com.android.server.wifi.p2p.WifiP2pNative.P2P_IFACE_NAME; +import static com.android.server.wifi.p2p.WifiP2pNative.P2P_INTERFACE_PROPERTY; import android.annotation.IntDef; import android.annotation.NonNull; @@ -32,6 +35,7 @@ import android.net.MacAddress; import android.net.TrafficStats; import android.net.apf.ApfCapabilities; import android.net.wifi.CoexUnsafeChannel; +import android.net.wifi.MscsParams; import android.net.wifi.OuiKeyedData; import android.net.wifi.QosPolicyParams; import android.net.wifi.ScanResult; @@ -42,13 +46,17 @@ import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiContext; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.RoamingMode; import android.net.wifi.WifiScanner; +import android.net.wifi.WifiScanner.ScanData; import android.net.wifi.WifiSsid; import android.net.wifi.nl80211.DeviceWiphyCapabilities; import android.net.wifi.nl80211.NativeScanResult; import android.net.wifi.nl80211.NativeWifiClient; import android.net.wifi.nl80211.RadioChainInfo; import android.net.wifi.nl80211.WifiNl80211Manager; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSessionCallback; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -59,6 +67,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; +import android.util.SparseIntArray; import com.android.internal.annotations.Immutable; import com.android.internal.annotations.VisibleForTesting; @@ -86,6 +95,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -133,6 +143,15 @@ public class WifiNative { private InterfaceObserverInternal mInterfaceObserver; private InterfaceEventCallback mInterfaceListener; private @WifiManager.MloMode int mCachedMloMode = WifiManager.MLO_MODE_DEFAULT; + private boolean mIsLocationModeEnabled = false; + private long mLastLocationModeEnabledTimeMs = 0; + private Map<String, Bundle> mCachedTwtCapabilities = new ArrayMap<>(); + /** + * Mapping of unknown AKMs configured in overlay config item + * config_wifiUnknownAkmToKnownAkmMapping to ScanResult security key management scheme + * (ScanResult.KEY_MGMT_XX) + */ + @VisibleForTesting @Nullable SparseIntArray mUnknownAkmMap; public WifiNative(WifiVendorHal vendorHal, SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, @@ -152,6 +171,70 @@ public class WifiNative { mBuildProperties = buildProperties; mWifiInjector = wifiInjector; mContext = wifiInjector.getContext(); + initializeUnknownAkmMapping(); + } + + private void initializeUnknownAkmMapping() { + String[] unknownAkmMapping = + mContext.getResources() + .getStringArray(R.array.config_wifiUnknownAkmToKnownAkmMapping); + if (unknownAkmMapping == null) { + return; + } + for (String line : unknownAkmMapping) { + if (line == null) { + continue; + } + String[] items = line.split(","); + if (items.length != 2) { + Log.e( + TAG, + "Failed to parse config_wifiUnknownAkmToKnownAkmMapping line=" + + line + + ". Should contain only two values separated by comma"); + continue; + } + try { + int unknownAkm = Integer.parseInt(items[0].trim()); + int knownAkm = Integer.parseInt(items[1].trim()); + // Convert the OEM configured known AKM suite selector to + // ScanResult security key management scheme(ScanResult.KEY_MGMT_XX)*/ + int keyMgmtScheme = + InformationElementUtil.Capabilities.akmToScanResultKeyManagementScheme( + knownAkm); + if (keyMgmtScheme != ScanResult.KEY_MGMT_UNKNOWN) { + if (mUnknownAkmMap == null) { + mUnknownAkmMap = new SparseIntArray(); + } + mUnknownAkmMap.put(unknownAkm, keyMgmtScheme); + Log.d( + TAG, + "unknown AKM = " + + unknownAkm + + " - converted keyMgmtScheme: " + + keyMgmtScheme); + } else { + Log.e( + TAG, + "Known AKM: " + + knownAkm + + " is not defined in the framework." + + " Hence Failed to add AKM: " + + unknownAkm + + " in UnknownAkmMap." + + " Parsed config from overlay: " + + line); + } + } catch (Exception e) { + // failure to parse. Something is wrong with the configuration. + Log.e( + TAG, + "Parsing config_wifiUnknownAkmToKnownAkmMapping line=" + + line + + ". Exception occurred:" + + e); + } + } } /** @@ -168,6 +251,13 @@ public class WifiNative { } /** + * Get TWT capabilities for the interface + */ + public Bundle getTwtCapabilities(String interfaceName) { + return mCachedTwtCapabilities.get(interfaceName); + } + + /** * Callbacks for SoftAp interface. */ public class SoftApHalCallbackFromWificond implements WifiNl80211Manager.SoftApCallback { @@ -190,7 +280,7 @@ public class WifiNative { @Override public void onSoftApChannelSwitched(int frequency, int bandwidth) { mSoftApHalCallback.onInfoChanged(mIfaceName, frequency, bandwidth, - ScanResult.WIFI_STANDARD_UNKNOWN, null); + ScanResult.WIFI_STANDARD_UNKNOWN, null, Collections.emptyList()); } @Override @@ -248,9 +338,12 @@ public class WifiNative { * indication that the SoftAp is not enabled. * @param bandwidth The new bandwidth of the SoftAp. * @param generation The new generation of the SoftAp. + * @param vendorData List of {@link OuiKeyedData} containing vendor-specific configuration + * data, or empty list if not provided. */ void onInfoChanged(String apIfaceInstance, int frequency, int bandwidth, - int generation, MacAddress apIfaceInstanceMacAddress); + int generation, MacAddress apIfaceInstanceMacAddress, + @NonNull List<OuiKeyedData> vendorData); /** * Invoked when there is a change in the associated station (STA). * @@ -269,13 +362,15 @@ public class WifiNative { /** * Meta-info about every iface that is active. */ - private static class Iface { + public static class Iface { /** Type of ifaces possible */ public static final int IFACE_TYPE_AP = 0; public static final int IFACE_TYPE_STA_FOR_CONNECTIVITY = 1; public static final int IFACE_TYPE_STA_FOR_SCAN = 2; + public static final int IFACE_TYPE_P2P = 3; - @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA_FOR_CONNECTIVITY, IFACE_TYPE_STA_FOR_SCAN}) + @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA_FOR_CONNECTIVITY, IFACE_TYPE_STA_FOR_SCAN, + IFACE_TYPE_P2P}) @Retention(RetentionPolicy.SOURCE) public @interface IfaceType{} @@ -399,6 +494,11 @@ public class WifiNative { return false; } + /** Checks if there are any P2P iface active. */ + private boolean hasAnyP2pIface() { + return hasAnyIfaceOfType(Iface.IFACE_TYPE_P2P); + } + /** Checks if there are any STA (for connectivity) iface active. */ private boolean hasAnyStaIfaceForConnectivity() { return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY); @@ -622,10 +722,19 @@ public class WifiNative { private void stopSupplicantIfNecessary() { synchronized (mLock) { if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) { - if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) { - Log.e(TAG, "Failed to deregister supplicant death handler"); + if (mSupplicantStaIfaceHal.isInitializationStarted()) { + if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) { + Log.e(TAG, "Failed to deregister supplicant death handler"); + } + + } + if (!mIfaceMgr.hasAnyP2pIface()) { + if (mSupplicantStaIfaceHal.isInitializationStarted()) { + mSupplicantStaIfaceHal.terminate(); + } else { + mWifiInjector.getWifiP2pNative().stopP2pSupplicantIfNecessary(); + } } - mSupplicantStaIfaceHal.terminate(); } } } @@ -1118,6 +1227,68 @@ public class WifiNative { } } + private String createP2pIfaceFromHalOrGetNameFromProperty( + HalDeviceManager.InterfaceDestroyedListener p2pInterfaceDestroyedListener, + Handler handler, WorkSource requestorWs) { + synchronized (mLock) { + if (mWifiVendorHal.isVendorHalSupported()) { + return mWifiInjector.getHalDeviceManager().createP2pIface( + p2pInterfaceDestroyedListener, handler, requestorWs); + } else { + Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface."); + return mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); + } + } + } + + /** + * Helper function to handle creation of P2P iface. + * For devices which do not the support the HAL, this will bypass HalDeviceManager & + * teardown any existing iface. + */ + public Iface createP2pIface( + HalDeviceManager.InterfaceDestroyedListener p2pInterfaceDestroyedListener, + Handler handler, WorkSource requestorWs) { + synchronized (mLock) { + // Make sure HAL is started for p2p + if (!startHal()) { + Log.e(TAG, "Failed to start Hal"); + mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToHal(); + return null; + } + // maintain iface status in WifiNative + Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_P2P); + if (iface == null) { + Log.e(TAG, "Failed to allocate new P2P iface"); + stopHalAndWificondIfNecessary(); + return null; + } + iface.name = createP2pIfaceFromHalOrGetNameFromProperty( + p2pInterfaceDestroyedListener, handler, requestorWs); + if (TextUtils.isEmpty(iface.name)) { + Log.e(TAG, "Failed to create P2p iface in HalDeviceManager"); + mIfaceMgr.removeIface(iface.id); + mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToHal(); + stopHalAndWificondIfNecessary(); + return null; + } + return iface; + } + } + + /** + * Teardown P2p iface with input interface Id which was returned by createP2pIface. + * + * @param interfaceId the interface identify which was gerenated when creating P2p iface. + */ + public void teardownP2pIface(int interfaceId) { + synchronized (mLock) { + mIfaceMgr.removeIface(interfaceId); + stopHalAndWificondIfNecessary(); + stopSupplicantIfNecessary(); + } + } + /** * Get list of instance name from this bridged AP iface. * @@ -1531,7 +1702,8 @@ public class WifiNative { return false; } if (mContext.getResources().getBoolean( - R.bool.config_wifiNetworkCentricQosPolicyFeatureEnabled)) { + R.bool.config_wifiNetworkCentricQosPolicyFeatureEnabled) + && isSupplicantUsingAidlService()) { mQosPolicyFeatureEnabled = mSupplicantStaIfaceHal .setNetworkCentricQosPolicyFeatureEnabled(iface.name, true); if (!mQosPolicyFeatureEnabled) { @@ -1871,8 +2043,12 @@ public class WifiNative { InformationElementUtil.parseInformationElements(result.getInformationElements()); InformationElementUtil.Capabilities capabilities = new InformationElementUtil.Capabilities(); - capabilities.from(ies, result.getCapabilities(), mIsEnhancedOpenSupported, - result.getFrequencyMhz()); + capabilities.from( + ies, + result.getCapabilities(), + mIsEnhancedOpenSupported, + result.getFrequencyMhz(), + mUnknownAkmMap); String flags = capabilities.generateCapabilitiesString(); NetworkDetail networkDetail; try { @@ -3126,6 +3302,15 @@ public class WifiNative { } /** + * Check whether Supplicant is using the AIDL HAL service. + * + * @return true if the Supplicant is using the AIDL service, false otherwise. + */ + public boolean isSupplicantUsingAidlService() { + return mSupplicantStaIfaceHal.isAidlService(); + } + + /** * Check whether the Supplicant AIDL service is running at least the expected version. * * @param expectedVersion Version number to check. @@ -3460,6 +3645,62 @@ public class WifiNative { } /** + * Sets whether global location mode is enabled. + */ + public void setLocationModeEnabled(boolean enabled) { + if (!mIsLocationModeEnabled && enabled) { + mLastLocationModeEnabledTimeMs = SystemClock.elapsedRealtime(); + } + Log.d(TAG, "mIsLocationModeEnabled " + enabled + + " mLastLocationModeEnabledTimeMs " + mLastLocationModeEnabledTimeMs); + mIsLocationModeEnabled = enabled; + } + + @NonNull + private ScanResult[] getCachedScanResultsFilteredByLocationModeEnabled( + @NonNull ScanResult[] scanResults) { + List<ScanResult> resultList = new ArrayList<ScanResult>(); + for (ScanResult scanResult : scanResults) { + if (mIsLocationModeEnabled + && scanResult.timestamp >= mLastLocationModeEnabledTimeMs * 1000) { + resultList.add(scanResult); + } + } + return resultList.toArray(new ScanResult[0]); + } + + /** + * Gets the cached scan data from the given client interface + */ + @Nullable + ScanData getCachedScanResults(String ifaceName) { + ScanData scanData = mWifiVendorHal.getCachedScanData(ifaceName); + if (scanData == null || scanData.getResults() == null) { + return null; + } + ScanResult[] results = getCachedScanResultsFilteredByLocationModeEnabled( + scanData.getResults()); + return new ScanData(0, 0, 0, scanData.getScannedBands(), results); + } + + /** + * Gets the cached scan data from all client interfaces + */ + @NonNull + public ScanData getCachedScanResultsFromAllClientIfaces() { + ScanData consolidatedScanData = new ScanData(); + Set<String> ifaceNames = getClientInterfaceNames(); + for (String ifaceName : ifaceNames) { + ScanData scanData = getCachedScanResults(ifaceName); + if (scanData == null) { + continue; + } + consolidatedScanData.addResults(scanData.getResults()); + } + return consolidatedScanData; + } + + /** * Gets the latest link layer stats * @param ifaceName Name of the interface. */ @@ -3521,6 +3762,19 @@ public class WifiNative { } /** + * Returns whether P2p + STA concurrency is supported or not. + */ + public boolean isP2pStaConcurrencySupported() { + synchronized (mLock) { + return mWifiVendorHal.canDeviceSupportCreateTypeCombo( + new SparseArray<Integer>() {{ + put(HDM_CREATE_IFACE_STA, 1); + put(HDM_CREATE_IFACE_P2P, 1); + }}); + } + } + + /** * Returns whether a new AP iface can be created or not. */ public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) { @@ -3674,6 +3928,8 @@ public class WifiNative { Log.v(TAG, ": DPP AKM supported"); } } + Bundle twtCapabilities = mWifiVendorHal.getTwtCapabilities(ifaceName); + if (twtCapabilities != null) mCachedTwtCapabilities.put(ifaceName, twtCapabilities); return featureSet; } @@ -3729,12 +3985,14 @@ public class WifiNative { public boolean is11bMode; /** Indicates the AP support for TID-to-link mapping negotiation. */ public boolean apTidToLinkMapNegotiationSupported; + public @NonNull List<OuiKeyedData> vendorData; ConnectionCapabilities() { wifiStandard = ScanResult.WIFI_STANDARD_UNKNOWN; channelBandwidth = ScanResult.CHANNEL_WIDTH_20MHZ; maxNumberTxSpatialStreams = 1; maxNumberRxSpatialStreams = 1; is11bMode = false; + vendorData = Collections.emptyList(); } } @@ -4112,6 +4370,9 @@ public class WifiNative { * @param pw PrintWriter to write dump to */ protected void dump(PrintWriter pw) { + pw.println("Dump of " + TAG); + pw.println("mIsLocationModeEnabled: " + mIsLocationModeEnabled); + pw.println("mLastLocationModeEnabledTimeMs: " + mLastLocationModeEnabledTimeMs); mHostapdHal.dump(pw); } @@ -4584,6 +4845,20 @@ public class WifiNative { * @return the device capabilities for this interface */ public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) { + return getDeviceWiphyCapabilities(ifaceName, false); + } + + /** + * Get the Wiphy capabilities of a device for a given interface + * If the interface is not associated with one, + * it will be read from the device through wificond + * + * @param ifaceName name of the interface + * @param isBridgedAp If the iface is bridge AP iface or not. + * @return the device capabilities for this interface + */ + public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName, + boolean isBridgedAp) { synchronized (mLock) { Iface iface = mIfaceMgr.getIface(ifaceName); if (iface == null) { @@ -4591,7 +4866,15 @@ public class WifiNative { return null; } if (iface.phyCapabilities == null) { - iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities(ifaceName); + if (isBridgedAp) { + List<String> instances = getBridgedApInstances(ifaceName); + if (instances != null && instances.size() != 0) { + iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities( + instances.get(0)); + } + } else { + iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities(ifaceName); + } } if (iface.phyCapabilities != null && iface.phyCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE) @@ -4848,30 +5131,36 @@ public class WifiNative { return mHostapdHal.isSoftApInstanceDiedHandlerSupported(); } - @VisibleForTesting /** Checks if there are any STA (for connectivity) iface active. */ + @VisibleForTesting boolean hasAnyStaIfaceForConnectivity() { return mIfaceMgr.hasAnyStaIfaceForConnectivity(); } - @VisibleForTesting /** Checks if there are any STA (for scan) iface active. */ + @VisibleForTesting boolean hasAnyStaIfaceForScan() { return mIfaceMgr.hasAnyStaIfaceForScan(); } - @VisibleForTesting /** Checks if there are any AP iface active. */ + @VisibleForTesting boolean hasAnyApIface() { return mIfaceMgr.hasAnyApIface(); } - @VisibleForTesting /** Checks if there are any iface active. */ + @VisibleForTesting boolean hasAnyIface() { return mIfaceMgr.hasAnyIface(); } + /** Checks if there are any P2P iface active. */ + @VisibleForTesting + boolean hasAnyP2pIface() { + return mIfaceMgr.hasAnyP2pIface(); + } + /** * Sets or clean mock wifi service * @@ -5055,4 +5344,135 @@ public class WifiNative { public boolean setAfcChannelAllowance(WifiChip.AfcChannelAllowance afcChannelAllowance) { return mWifiVendorHal.setAfcChannelAllowance(afcChannelAllowance); } + + /** + * Enable Mirrored Stream Classification Service (MSCS) and configure using + * the provided configuration values. + * + * @param mscsParams {@link MscsParams} object containing the configuration parameters. + * @param ifaceName Name of the interface. + */ + public void enableMscs(@NonNull MscsParams mscsParams, String ifaceName) { + mSupplicantStaIfaceHal.enableMscs(mscsParams, ifaceName); + } + + /** + * Resend the previously configured MSCS parameters on this interface, if any exist. + * + * @param ifaceName Name of the interface. + */ + public void resendMscs(String ifaceName) { + mSupplicantStaIfaceHal.resendMscs(ifaceName); + } + + /** + * Disable Mirrored Stream Classification Service (MSCS). + * + * @param ifaceName Name of the interface. + */ + public void disableMscs(String ifaceName) { + mSupplicantStaIfaceHal.disableMscs(ifaceName); + } + + /** + * Set the roaming mode value. + * + * @param ifaceName Name of the interface. + * @param roamingMode {@link android.net.wifi.WifiManager.RoamingMode}. + * @return {@link WifiStatusCode#SUCCESS} if success, otherwise error code. + */ + public @WifiStatusCode int setRoamingMode(@NonNull String ifaceName, + @RoamingMode int roamingMode) { + return mWifiVendorHal.setRoamingMode(ifaceName, roamingMode); + } + + /* + * TWT callback events + */ + public interface WifiTwtEvents { + /** + * Called when a TWT operation fails + * + * @param cmdId Unique command id. + * @param twtErrorCode Error code + */ + void onTwtFailure(int cmdId, @TwtSessionCallback.TwtErrorCode int twtErrorCode); + + /** + * Called when {@link #setupTwtSession(int, String, TwtRequest)} succeeds. + * + * @param cmdId Unique command id used in {@link #setupTwtSession(int, String, TwtRequest)} + * @param wakeDurationUs TWT wake duration for the session in microseconds + * @param wakeIntervalUs TWT wake interval for the session in microseconds + * @param linkId Multi link operation link id + * @param sessionId TWT session id + */ + void onTwtSessionCreate(int cmdId, int wakeDurationUs, long wakeIntervalUs, int linkId, + int sessionId); + /** + * Called when TWT session is torn down by {@link #tearDownTwtSession(int, String, int)}. + * Can also be called unsolicitedly by the vendor software with proper reason code. + * + * @param cmdId Unique command id used in {@link #tearDownTwtSession(int, String, int)} + * @param twtSessionId TWT session Id + * @param twtReasonCode Reason code for teardown + */ + void onTwtSessionTeardown(int cmdId, int twtSessionId, + @TwtSessionCallback.TwtReasonCode int twtReasonCode); + + /** + * Called as a response to {@link #getStatsTwtSession(int, String, int)} + * + * @param cmdId Unique command id used in {@link #getStatsTwtSession(int, String, int)} + * @param twtSessionId TWT session Id + * @param twtStats TWT stats object + */ + void onTwtSessionStats(int cmdId, int twtSessionId, Bundle twtStats); + } + + + /** + * Sets up a TWT session for the interface + * + * @param commandId A unique command id to identify this command + * @param interfaceName Interface name + * @param twtRequest TWT request parameters + * @return true if successful, otherwise false + */ + public boolean setupTwtSession(int commandId, String interfaceName, TwtRequest twtRequest) { + return mWifiVendorHal.setupTwtSession(commandId, interfaceName, twtRequest); + } + + /** + * Registers TWT callbacks + * + * @param wifiTwtCallback TWT callbacks + */ + public void registerTwtCallbacks(WifiTwtEvents wifiTwtCallback) { + mWifiVendorHal.registerTwtCallbacks(wifiTwtCallback); + } + + /** + * Teardown the TWT session + * + * @param commandId A unique command id to identify this command + * @param interfaceName Interface name + * @param sessionId TWT session id + * @return true if successful, otherwise false + */ + public boolean tearDownTwtSession(int commandId, String interfaceName, int sessionId) { + return mWifiVendorHal.tearDownTwtSession(commandId, interfaceName, sessionId); + } + + /** + * Gets stats of the TWT session + * + * @param commandId A unique command id to identify this command + * @param interfaceName Interface name + * @param sessionId TWT session id + * @return true if successful, otherwise false + */ + public boolean getStatsTwtSession(int commandId, String interfaceName, int sessionId) { + return mWifiVendorHal.getStatsTwtSession(commandId, interfaceName, sessionId); + } } diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java index a03dd40b5b..9313733182 100644 --- a/service/java/com/android/server/wifi/WifiNetworkFactory.java +++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java @@ -31,6 +31,7 @@ import static java.lang.Math.toIntExact; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AppOpsManager; @@ -147,6 +148,7 @@ public class WifiNetworkFactory extends NetworkFactory { private final ClientModeImplMonitor mClientModeImplMonitor; private final FrameworkFacade mFacade; private final MultiInternetManager mMultiInternetManager; + private final NetworkCapabilities mCapabilitiesFilter; private RemoteCallbackList<INetworkRequestMatchCallback> mRegisteredCallbacks; // Store all user approved access points for apps. @VisibleForTesting @@ -592,6 +594,7 @@ public class WifiNetworkFactory extends NetworkFactory { mUserApprovedAccessPointMap = new HashMap<>(); mFacade = facade; mMultiInternetManager = multiInternetManager; + mCapabilitiesFilter = nc; // register the data store for serializing/deserializing data. configStore.registerStoreData( @@ -611,6 +614,18 @@ public class WifiNetworkFactory extends NetworkFactory { }); } + // package-private + @TargetApi(Build.VERSION_CODES.S) + void updateSubIdsInCapabilitiesFilter(Set<Integer> subIds) { + // setSubscriptionIds is only available on Android S+ devices. + if (SdkLevel.isAtLeastS()) { + NetworkCapabilities newFilter = + new NetworkCapabilities.Builder(mCapabilitiesFilter) + .setSubscriptionIds(subIds).build(); + setCapabilityFilter(newFilter); + } + } + private void saveToStore() { // Set the flag to let WifiConfigStore that we have new data to write. mHasNewDataToSerialize = true; @@ -906,12 +921,12 @@ public class WifiNetworkFactory extends NetworkFactory { mActiveSpecificNetworkRequest.getRequestorPackageName())); } - - if (!triggerConnectIfUserApprovedMatchFound(revokeNormalBypass)) { + ScanResult[] cachedScanResults = getFilteredCachedScanResults(); + if (!triggerConnectIfUserApprovedMatchFound(revokeNormalBypass, cachedScanResults)) { // Didn't find an approved match, send the matching results to UI and trigger // periodic scans for finding a network in the request. // Fetch the latest cached scan results to speed up network matching. - ScanResult[] cachedScanResults = getFilteredCachedScanResults(); + if (mVerboseLoggingEnabled) { Log.v(TAG, "Using cached " + cachedScanResults.length + " scan results"); } @@ -1125,7 +1140,7 @@ public class WifiNetworkFactory extends NetworkFactory { new NetworkUpdateResult(networkId), new ActionListenerWrapper(listener), mActiveSpecificNetworkRequest.getRequestorUid(), - mActiveSpecificNetworkRequest.getRequestorPackageName()); + mActiveSpecificNetworkRequest.getRequestorPackageName(), null); // Post an alarm to handle connection timeout. scheduleConnectionTimeout(); @@ -1271,7 +1286,7 @@ public class WifiNetworkFactory extends NetworkFactory { return; } - if (!mPendingConnectionSuccess) { + if (!mPendingConnectionSuccess || mActiveSpecificNetworkRequest == null) { if (mConnectedSpecificNetworkRequest != null) { Log.w(TAG, "Connection is terminated, cancelling " + mConnectedSpecificNetworkRequest); @@ -1645,7 +1660,7 @@ public class WifiNetworkFactory extends NetworkFactory { ScanResult[] scanResults) { if (mActiveSpecificNetworkRequestSpecifier == null) { Log.e(TAG, "Scan results received with no active network request. Ignoring..."); - return new ArrayList<>(); + return Collections.emptyList(); } List<ScanResult> matchedScanResults = new ArrayList<>(); WifiNetworkSpecifier wns = mActiveSpecificNetworkRequestSpecifier; @@ -1914,7 +1929,8 @@ public class WifiNetworkFactory extends NetworkFactory { * * @return true if a pre-approved network was found for connection, false otherwise. */ - private boolean triggerConnectIfUserApprovedMatchFound(boolean revokeNormalBypass) { + private boolean triggerConnectIfUserApprovedMatchFound(boolean revokeNormalBypass, + ScanResult[] scanResults) { if (mActiveSpecificNetworkRequestSpecifier == null) return false; boolean requestForSingleAccessPoint = isActiveRequestForSingleAccessPoint(); if (!requestForSingleAccessPoint && !isActiveRequestForSingleNetwork()) { @@ -1939,7 +1955,9 @@ public class WifiNetworkFactory extends NetworkFactory { } return false; } - if (requestForSingleAccessPoint) { + List<ScanResult> matchedScanResults = + getNetworksMatchingActiveNetworkRequest(scanResults); + if (requestForSingleAccessPoint && !matchedScanResults.isEmpty()) { Log.v(TAG, "Approved access point found in matching scan results. " + "Triggering connect " + ssid + "/" + bssid); // Request is for a single AP which is already approved. Connect directly. diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java index 445bf562f8..35316d65d4 100644 --- a/service/java/com/android/server/wifi/WifiNetworkSelector.java +++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java @@ -21,6 +21,8 @@ import static android.net.wifi.WifiNetworkSelectionConfig.ASSOCIATED_NETWORK_SEL import static android.net.wifi.WifiNetworkSelectionConfig.ASSOCIATED_NETWORK_SELECTION_OVERRIDE_ENABLED; import static android.net.wifi.WifiNetworkSelectionConfig.ASSOCIATED_NETWORK_SELECTION_OVERRIDE_NONE; +import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -218,7 +220,7 @@ public class WifiNetworkSelector { // be retrieved in bugreport. It is also used to print the log in the console. private void localLog(String log) { mLocalLog.log(log); - if (mVerboseLoggingEnabled) Log.d(TAG, log); + if (mVerboseLoggingEnabled) Log.d(TAG, log, null); } /** @@ -426,12 +428,7 @@ public class WifiNetworkSelector { } - private boolean isNetworkSelectionNeeded(@NonNull List<ScanDetail> scanDetails, - @NonNull List<ClientModeManagerState> cmmStates) { - if (scanDetails.size() == 0) { - localLog("Empty connectivity scan results. Skip network selection."); - return false; - } + private boolean isNetworkSelectionNeeded(@NonNull List<ClientModeManagerState> cmmStates) { for (ClientModeManagerState cmmState : cmmStates) { // network selection needed by this CMM instance, perform network selection if (isNetworkSelectionNeededForCmm(cmmState)) { @@ -927,6 +924,7 @@ public class WifiNetworkSelector { public final boolean ipProvisioningTimedOut; /** Currently connected network */ public final WifiInfo wifiInfo; + public final ActiveModeManager.ClientRole role; ClientModeManagerState(@NonNull ClientModeManager clientModeManager) { ifaceName = clientModeManager.getInterfaceName(); @@ -934,6 +932,7 @@ public class WifiNetworkSelector { disconnected = clientModeManager.isDisconnected(); ipProvisioningTimedOut = clientModeManager.isIpProvisioningTimedOut(); wifiInfo = clientModeManager.getConnectionInfo(); + role = clientModeManager.getRole(); } ClientModeManagerState() { @@ -942,16 +941,19 @@ public class WifiNetworkSelector { disconnected = true; wifiInfo = new WifiInfo(); ipProvisioningTimedOut = false; + role = null; } @VisibleForTesting ClientModeManagerState(@NonNull String ifaceName, boolean connected, boolean disconnected, - @NonNull WifiInfo wifiInfo, boolean ipProvisioningTimedOut) { + @NonNull WifiInfo wifiInfo, boolean ipProvisioningTimedOut, + ActiveModeManager.ClientRole role) { this.ifaceName = ifaceName; this.connected = connected; this.disconnected = disconnected; this.wifiInfo = wifiInfo; this.ipProvisioningTimedOut = ipProvisioningTimedOut; + this.role = role; } @Override @@ -962,6 +964,7 @@ public class WifiNetworkSelector { return Objects.equals(ifaceName, thatCmmState.ifaceName) && connected == thatCmmState.connected && disconnected == thatCmmState.disconnected + && role == thatCmmState.role // Since wifiinfo does not have equals currently. && Objects.equals(wifiInfo.getSSID(), thatCmmState.wifiInfo.getSSID()) && Objects.equals(wifiInfo.getBSSID(), thatCmmState.wifiInfo.getBSSID()); @@ -970,12 +973,13 @@ public class WifiNetworkSelector { @Override public int hashCode() { return Objects.hash(ifaceName, connected, disconnected, - wifiInfo.getSSID(), wifiInfo.getBSSID()); + wifiInfo.getSSID(), wifiInfo.getBSSID(), role); } @Override public String toString() { return "ClientModeManagerState: " + ifaceName + + ", role:" + role + ", connection state: " + (connected ? " connected" : (disconnected ? " disconnected" : "unknown")) + ", WifiInfo: " + wifiInfo; @@ -1036,6 +1040,20 @@ public class WifiNetworkSelector { mLastSelectionWeightEnabled = enabled; } + private String getConnectChoiceKey(@NonNull List<ClientModeManagerState> cmmStates) { + for (ClientModeManagerState cmmState : cmmStates) { + if (cmmState.role != ROLE_CLIENT_PRIMARY) { + continue; + } + WifiConfiguration currentNetwork = + mWifiConfigManager.getConfiguredNetwork(cmmState.wifiInfo.getNetworkId()); + if (currentNetwork != null) { + return currentNetwork.getNetworkSelectionStatus().getConnectChoice(); + } + } + return null; + } + /** * Returns the list of Candidates from networks in range. * @@ -1048,15 +1066,14 @@ public class WifiNetworkSelector { * @param oemPaidNetworkAllowed True if oem paid networks are allowed for connection * @param oemPrivateNetworkAllowed True if oem private networks are allowed for connection * @param restrictedNetworkAllowedUids a set of Uids are allowed for restricted network - * @param multiInternetNetworkAllowed True if multi internet networks are allowed for - * connection. + * @param skipSufficiencyCheck True to skip network sufficiency check * @return list of valid Candidate(s) */ public List<WifiCandidates.Candidate> getCandidatesFromScan( @NonNull List<ScanDetail> scanDetails, @NonNull Set<String> bssidBlocklist, @NonNull List<ClientModeManagerState> cmmStates, boolean untrustedNetworkAllowed, boolean oemPaidNetworkAllowed, boolean oemPrivateNetworkAllowed, - Set<Integer> restrictedNetworkAllowedUids, boolean multiInternetNetworkAllowed) { + Set<Integer> restrictedNetworkAllowedUids, boolean skipSufficiencyCheck) { mFilteredNetworks.clear(); mConnectableNetworks.clear(); if (scanDetails.size() == 0) { @@ -1071,58 +1088,73 @@ public class WifiNetworkSelector { for (NetworkNominator registeredNominator : mNominators) { registeredNominator.update(scanDetails); } - // Update the matching profiles into WifiConfigManager, help displaying Passpoint networks - // in Wifi Picker - mWifiInjector.getPasspointNetworkNominateHelper().updatePasspointConfig(scanDetails); - - // Shall we start network selection at all? - if (!multiInternetNetworkAllowed && !isNetworkSelectionNeeded(scanDetails, cmmStates)) { - return null; - } // Filter out unwanted networks. mFilteredNetworks = filterScanResults(scanDetails, bssidBlocklist, cmmStates); if (mFilteredNetworks.size() == 0) { return null; } + // Update the matching profiles into WifiConfigManager, help displaying Passpoint networks + // in Wifi Picker + mWifiInjector.getPasspointNetworkNominateHelper().updatePasspointConfig(mFilteredNetworks); + + boolean networkSelectionNeeded = skipSufficiencyCheck + || isNetworkSelectionNeeded(cmmStates); + final String userConnectChoiceKey; + if (!networkSelectionNeeded) { + userConnectChoiceKey = getConnectChoiceKey(cmmStates); + if (userConnectChoiceKey == null) { + return null; + } + // Continue candidate selection but only allow the user connect choice as candidate + localLog("Current network is sufficient. Continue network selection only " + + "considering user connect choice: " + userConnectChoiceKey); + } else { + userConnectChoiceKey = null; + } WifiCandidates wifiCandidates = new WifiCandidates(mWifiScoreCard, mContext); - for (ClientModeManagerState cmmState : cmmStates) { - // Always get the current BSSID from WifiInfo in case that firmware initiated - // roaming happened. - String currentBssid = cmmState.wifiInfo.getBSSID(); - WifiConfiguration currentNetwork = - mWifiConfigManager.getConfiguredNetwork(cmmState.wifiInfo.getNetworkId()); - if (currentNetwork != null) { - wifiCandidates.setCurrent(currentNetwork.networkId, currentBssid); - // We always want the current network to be a candidate so that it can participate. - // It may also get re-added by a nominator, in which case this fallback - // will be replaced. - MacAddress bssid = MacAddress.fromString(currentBssid); - SecurityParams params = currentNetwork.getNetworkSelectionStatus() - .getLastUsedSecurityParams(); - if (null == params) { - localLog("No known candidate security params for current network."); - continue; + if (userConnectChoiceKey == null) { + // Add connected network as candidates unless only considering connect choice. + for (ClientModeManagerState cmmState : cmmStates) { + // Always get the current BSSID from WifiInfo in case that firmware initiated + // roaming happened. + String currentBssid = cmmState.wifiInfo.getBSSID(); + WifiConfiguration currentNetwork = + mWifiConfigManager.getConfiguredNetwork(cmmState.wifiInfo.getNetworkId()); + if (currentNetwork != null) { + wifiCandidates.setCurrent(currentNetwork.networkId, currentBssid); + // We always want the current network to be a candidate so that it can + // participate. + // It may also get re-added by a nominator, in which case this fallback + // will be replaced. + MacAddress bssid = MacAddress.fromString(currentBssid); + SecurityParams params = currentNetwork.getNetworkSelectionStatus() + .getLastUsedSecurityParams(); + if (null == params) { + localLog("No known candidate security params for current network."); + continue; + } + WifiCandidates.Key key = new WifiCandidates.Key( + ScanResultMatchInfo.fromWifiConfiguration(currentNetwork), + bssid, currentNetwork.networkId, + params.getSecurityType()); + ScanDetail scanDetail = findScanDetailForBssid(mFilteredNetworks, currentBssid); + int predictedTputMbps = (scanDetail == null) ? 0 + : predictThroughput(scanDetail); + wifiCandidates.add(key, currentNetwork, + NetworkNominator.NOMINATOR_ID_CURRENT, + cmmState.wifiInfo.getRssi(), + cmmState.wifiInfo.getFrequency(), + ScanResult.CHANNEL_WIDTH_20MHZ, // channel width unavailable in WifiInfo + calculateLastSelectionWeight(currentNetwork.networkId, + WifiConfiguration.isMetered(currentNetwork, cmmState.wifiInfo)), + WifiConfiguration.isMetered(currentNetwork, cmmState.wifiInfo), + isFromCarrierOrPrivilegedApp(currentNetwork), + predictedTputMbps, + (scanDetail != null) ? scanDetail.getScanResult().getApMldMacAddress() + : null); } - WifiCandidates.Key key = new WifiCandidates.Key( - ScanResultMatchInfo.fromWifiConfiguration(currentNetwork), - bssid, currentNetwork.networkId, - params.getSecurityType()); - ScanDetail scanDetail = findScanDetailForBssid(mFilteredNetworks, currentBssid); - int predictedTputMbps = (scanDetail == null) ? 0 : predictThroughput(scanDetail); - wifiCandidates.add(key, currentNetwork, - NetworkNominator.NOMINATOR_ID_CURRENT, - cmmState.wifiInfo.getRssi(), - cmmState.wifiInfo.getFrequency(), - ScanResult.CHANNEL_WIDTH_20MHZ, // channel width not available in WifiInfo - calculateLastSelectionWeight(currentNetwork.networkId, - WifiConfiguration.isMetered(currentNetwork, cmmState.wifiInfo)), - WifiConfiguration.isMetered(currentNetwork, cmmState.wifiInfo), - isFromCarrierOrPrivilegedApp(currentNetwork), - predictedTputMbps, - (scanDetail != null) ? scanDetail.getScanResult().getApMldMacAddress() - : null); } } @@ -1141,6 +1173,10 @@ public class WifiNetworkSelector { WifiCandidates.Key key = wifiCandidates.keyFromScanDetailAndConfig( scanDetail, config); if (key != null) { + if (userConnectChoiceKey != null + && !userConnectChoiceKey.equals(config.getProfileKey())) { + return; + } boolean metered = false; for (ClientModeManagerState cmmState : cmmStates) { if (isEverMetered(config, cmmState.wifiInfo, scanDetail)) { @@ -1181,6 +1217,16 @@ public class WifiNetworkSelector { } /** + * Check Wi-Fi7 is enabled for all candidates. + */ + private boolean isWifi7Enabled(List<WifiCandidates.Candidate> candidates) { + for (WifiCandidates.Candidate candidate : candidates) { + if (!mWifiConfigManager.isWifi7Enabled(candidate.getNetworkConfigId())) return false; + } + return true; + } + + /** * Update multi link candidate's throughput which is used in network selection by * {@link ThroughputScorer} * @@ -1221,6 +1267,7 @@ public class WifiNetworkSelector { for (List<WifiCandidates.Candidate> mlCandidates : wifiCandidates.getMultiLinkCandidates()) { + if (!isWifi7Enabled(mlCandidates)) continue; for (List<Integer> bands : simultaneousBandCombinations) { // Limit the radios/bands to maximum STR link supported in multi link operation. if (bands.size() > maxMloStrLinkCount) break; @@ -1453,7 +1500,7 @@ public class WifiNetworkSelector { /** * Using the registered Scorers, choose the best network from the list of Candidate(s). * The ScanDetailCache is also updated here. - * @param candidates - Candidates to perferm network selection on. + * @param candidates - Candidates to perform network selection on. * @param overrideEnabled If it is allowed to override candidate with User Connect Choice. * @return WifiConfiguration - the selected network, or null. */ diff --git a/service/java/com/android/server/wifi/WifiPseudonymManager.java b/service/java/com/android/server/wifi/WifiPseudonymManager.java index e102dd6e0a..5418a632ec 100644 --- a/service/java/com/android/server/wifi/WifiPseudonymManager.java +++ b/service/java/com/android/server/wifi/WifiPseudonymManager.java @@ -428,7 +428,7 @@ public final class WifiPseudonymManager { if (!mVerboseLogEnabled) { return; } - Log.d(TAG, msg); + Log.d(TAG, msg, null); } @VisibleForTesting diff --git a/service/java/com/android/server/wifi/WifiRoamingConfigStore.java b/service/java/com/android/server/wifi/WifiRoamingConfigStore.java new file mode 100644 index 0000000000..adce4365fc --- /dev/null +++ b/service/java/com/android/server/wifi/WifiRoamingConfigStore.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; +import com.android.server.wifi.util.XmlUtil; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +/** + * Store data for storing B2B wifi roaming policies. + * These are key (string) / value pairs that are stored in + * WifiConfigStore.xml file in a separate section. + */ +public class WifiRoamingConfigStore { + private static final String TAG = "WifiRoamingConfigStore"; + private static final int INVALID_ROAMING_MODE = -1; + + // To store roaming policies that are added by the device owner (DO) or + // the profile owner of an organization owned device (COPE). + private final Map<String, Integer> mDeviceAdminRoamingPolicies = new ArrayMap<>(); + // To store roaming policies that are added by non-admins. + private final Map<String, Integer> mNonAdminRoamingPolicies = new ArrayMap<>(); + private final WifiConfigManager mWifiConfigManager; + private boolean mHasNewDataToSerialize = false; + + public WifiRoamingConfigStore(@NonNull WifiConfigManager wifiConfigManager, + @NonNull WifiConfigStore wifiConfigStore) { + mWifiConfigManager = wifiConfigManager; + // Register our data store. + wifiConfigStore.registerStoreData(new StoreData()); + } + + /** + * Trigger config store writes in the main wifi service looper's handler. + */ + private void triggerSaveToStore() { + mHasNewDataToSerialize = true; + mWifiConfigManager.saveToStore(true); + } + + /** + * Add a roaming policy to the corresponding stored policies. + * + * @param ssid of the network on which policy to be added. + * @param roamingMode denotes roaming mode value configured. + * @param isDeviceOwner flag denoting whether API is called by the device owner. + */ + public void addRoamingMode(@NonNull String ssid, @NonNull int roamingMode, + boolean isDeviceOwner) { + if (isDeviceOwner) { + mDeviceAdminRoamingPolicies.put(ssid, roamingMode); + } else { + mNonAdminRoamingPolicies.put(ssid, roamingMode); + } + triggerSaveToStore(); + } + + /** + * Remove a roaming policy from the corresponding stored policies. + * + * @param ssid of the network on which policy to be removed. + * @param isDeviceOwner flag denoting whether API is called by the device owner. + */ + public void removeRoamingMode(@NonNull String ssid, boolean isDeviceOwner) { + if (isDeviceOwner) { + mDeviceAdminRoamingPolicies.remove(ssid); + } else { + mNonAdminRoamingPolicies.remove(ssid); + } + triggerSaveToStore(); + } + + /** + * Retrieve roaming policy/mode for the given network name. + * + * @param ssid of the network which needs to be queried to fetch policy. + * @return roaming mode stored in policy list, + * {@value WifiManager#ROAMING_MODE_NORMAL} if the key does not exist. + */ + public @NonNull int getRoamingMode(@NonNull String ssid) { + int roamingMode; + roamingMode = mDeviceAdminRoamingPolicies.getOrDefault(ssid, INVALID_ROAMING_MODE); + if (roamingMode == INVALID_ROAMING_MODE) { + roamingMode = mNonAdminRoamingPolicies.getOrDefault(ssid, + WifiManager.ROAMING_MODE_NORMAL); + } + return roamingMode; + } + + /** + * Get all the network roaming policies configured. + * + * @param isDeviceOwner flag denoting whether API is called by the device owner. + * @return Map of corresponding policies for the API caller, + * where key is ssid and value is roaming mode/policy configured for that ssid. + */ + public Map<String, Integer> getPerSsidRoamingModes(boolean isDeviceOwner) { + Map<String, Integer> roamingPolicies = new ArrayMap<>(); + if (isDeviceOwner) { + roamingPolicies.putAll(mDeviceAdminRoamingPolicies); + } else { + roamingPolicies.putAll(mNonAdminRoamingPolicies); + } + return roamingPolicies; + } + + /** + * Dump all roaming policies for debugging. + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(); + pw.println("Dump of " + TAG); + pw.println("DEVICE_ADMIN_POLICIES"); + for (Map.Entry<String, Integer> entry : mDeviceAdminRoamingPolicies.entrySet()) { + pw.print(entry.getKey()); + pw.print("="); + pw.println(entry.getValue()); + } + pw.println(); + pw.println("NON_ADMIN_POLICIES"); + for (Map.Entry<String, Integer> entry : mNonAdminRoamingPolicies.entrySet()) { + pw.print(entry.getKey()); + pw.print("="); + pw.println(entry.getValue()); + } + } + + /** + * Store data for persisting the roaming policies data to config store. + */ + private class StoreData implements WifiConfigStore.StoreData { + private static final String XML_TAG_SECTION_HEADER = "RoamingPolicies"; + private static final String XML_TAG_DEVICE_ADMIN_POLICIES = "DeviceAdminPolicies"; + private static final String XML_TAG_NON_ADMIN_POLICIES = "NonAdminPolicies"; + + @Override + public void serializeData(XmlSerializer out, + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) + throws XmlPullParserException, IOException { + XmlUtil.writeNextValue(out, XML_TAG_DEVICE_ADMIN_POLICIES, mDeviceAdminRoamingPolicies); + XmlUtil.writeNextValue(out, XML_TAG_NON_ADMIN_POLICIES, mNonAdminRoamingPolicies); + mHasNewDataToSerialize = false; + } + + @Override + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) + throws XmlPullParserException, IOException { + if (in == null) { + mDeviceAdminRoamingPolicies.clear(); + mNonAdminRoamingPolicies.clear(); + return; + } + Map<String, Integer> deviceAdminPolicies = null, nonAdminPolicies = null; + 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_DEVICE_ADMIN_POLICIES: + deviceAdminPolicies = (HashMap) value; + break; + case XML_TAG_NON_ADMIN_POLICIES: + nonAdminPolicies = (HashMap) value; + break; + default: + Log.w(TAG, "Ignoring unknown tag under " + XML_TAG_SECTION_HEADER + ": " + + valueName[0]); + break; + } + } + if (deviceAdminPolicies != null) { + mDeviceAdminRoamingPolicies.putAll(deviceAdminPolicies); + } + if (nonAdminPolicies != null) { + mNonAdminRoamingPolicies.putAll(nonAdminPolicies); + } + } + + @Override + public void resetData() { + mDeviceAdminRoamingPolicies.clear(); + mNonAdminRoamingPolicies.clear(); + } + + @Override + public boolean hasNewDataToSerialize() { + return mHasNewDataToSerialize; + } + + @Override + public String getName() { + return XML_TAG_SECTION_HEADER; + } + + @Override + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_SHARED_GENERAL; + } + } +} diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java index 4de21283c0..e94e337874 100644 --- a/service/java/com/android/server/wifi/WifiScoreCard.java +++ b/service/java/com/android/server/wifi/WifiScoreCard.java @@ -119,7 +119,7 @@ public class WifiScoreCard { static final int SUFFICIENT_RECENT_STATS_ONLY = 1; static final int SUFFICIENT_RECENT_PREV_STATS = 2; - private static final int MAX_FREQUENCIES_PER_SSID = 10; + private static final int MAX_FREQUENCIES_PER_SSID = 30; private static final int MAX_TRAFFIC_STATS_POLL_TIME_DELTA_MS = 6_000; private final Clock mClock; @@ -2097,13 +2097,13 @@ public class WifiScoreCard { private void logd(String string) { if (mVerboseLoggingEnabled) { - Log.d(TAG, string); + Log.d(TAG, string, null); } } private void logv(String string) { if (mVerboseLoggingEnabled) { - Log.v(TAG, string); + Log.v(TAG, string, null); } mLocalLog.log(string); } diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index bf162ceb08..697d908d85 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -27,6 +27,7 @@ import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERI import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL; import static android.net.wifi.WifiManager.NOT_OVERRIDE_EXISTING_NETWORKS_ON_RESTORE; import static android.net.wifi.WifiManager.PnoScanResultsCallback.REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED; +import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL; import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL; import static android.net.wifi.WifiManager.VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY; import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; @@ -55,6 +56,7 @@ import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_P2P; import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA; import static com.android.server.wifi.ScanRequestProxy.createBroadcastOptionsForScanResultsAvailable; import static com.android.server.wifi.SelfRecovery.REASON_API_CALL; +import static com.android.server.wifi.WifiSettingsConfigStore.D2D_ALLOWED_WHEN_INFRA_STA_DISABLED; import static com.android.server.wifi.WifiSettingsConfigStore.SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI; import static com.android.server.wifi.WifiSettingsConfigStore.SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI_SET_BY_API; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_AWARE_VERBOSE_LOGGING_ENABLED; @@ -93,12 +95,14 @@ import android.net.MacAddress; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkStack; +import android.net.TetheringManager; import android.net.Uri; import android.net.ip.IpClientUtil; import android.net.wifi.BaseWifiService; import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.IActionListener; import android.net.wifi.IBooleanListener; +import android.net.wifi.IByteArrayListener; import android.net.wifi.ICoexCallback; import android.net.wifi.IDppCallback; import android.net.wifi.IIntegerListener; @@ -107,6 +111,7 @@ import android.net.wifi.ILastCallerListener; import android.net.wifi.IListListener; import android.net.wifi.ILocalOnlyConnectionStatusListener; import android.net.wifi.ILocalOnlyHotspotCallback; +import android.net.wifi.IMapListener; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.IOnWifiActivityEnergyInfoListener; import android.net.wifi.IOnWifiDriverCountryCodeChangedListener; @@ -119,17 +124,22 @@ import android.net.wifi.ISubsystemRestartCallback; import android.net.wifi.ISuggestionConnectionStatusListener; import android.net.wifi.ISuggestionUserApprovalStatusListener; import android.net.wifi.ITrafficStateCallback; +import android.net.wifi.ITwtCallback; +import android.net.wifi.ITwtCapabilitiesListener; +import android.net.wifi.ITwtStatsListener; import android.net.wifi.IWifiBandsListener; import android.net.wifi.IWifiConnectedNetworkScorer; import android.net.wifi.IWifiLowLatencyLockListener; import android.net.wifi.IWifiNetworkSelectionConfigListener; import android.net.wifi.IWifiNetworkStateChangedListener; import android.net.wifi.IWifiVerboseLoggingStatusChangedListener; +import android.net.wifi.MscsParams; import android.net.wifi.QosPolicyParams; import android.net.wifi.ScanResult; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApInfo; +import android.net.wifi.SoftApState; import android.net.wifi.WifiAnnotations.WifiStandard; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiBands; @@ -142,10 +152,9 @@ import android.net.wifi.WifiManager.AddNetworkResult; import android.net.wifi.WifiManager.CoexRestriction; import android.net.wifi.WifiManager.DeviceMobilityState; import android.net.wifi.WifiManager.LocalOnlyHotspotCallback; +import android.net.wifi.WifiManager.RoamingMode; import android.net.wifi.WifiManager.SapClientBlockedReason; -import android.net.wifi.WifiManager.SapStartFailure; import android.net.wifi.WifiManager.SuggestionConnectionStatusListener; -import android.net.wifi.WifiManager.WifiApState; import android.net.wifi.WifiNetworkSelectionConfig; import android.net.wifi.WifiNetworkSuggestion; import android.net.wifi.WifiScanner; @@ -153,6 +162,9 @@ import android.net.wifi.WifiSsid; import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSession; +import android.net.wifi.twt.TwtSessionCallback; import android.net.wifi.util.ScanResultUtil; import android.os.AsyncTask; import android.os.Binder; @@ -239,6 +251,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.IntConsumer; /** * WifiService handles remote WiFi operation requests by implementing @@ -276,6 +289,8 @@ public class WifiServiceImpl extends BaseWifiService { /** Backup/Restore Module */ private final WifiBackupRestore mWifiBackupRestore; private final SoftApBackupRestore mSoftApBackupRestore; + private final WifiSettingsBackupRestore mWifiSettingsBackupRestore; + private final BackupRestoreController mBackupRestoreController; private final CoexManager mCoexManager; private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; private final WifiConfigManager mWifiConfigManager; @@ -381,6 +396,7 @@ public class WifiServiceImpl extends BaseWifiService { private WifiNetworkSelectionConfig mNetworkSelectionConfig; private ApplicationQosPolicyRequestHandler mApplicationQosPolicyRequestHandler; private final AfcManager mAfcManager; + private final TwtManager mTwtManager; /** * The wrapper of SoftApCallback is used in WifiService internally. @@ -390,7 +406,7 @@ public class WifiServiceImpl extends BaseWifiService { /** * see: {@code WifiManager.SoftApCallback#onStateChanged(int, int)} */ - void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {} + void onStateChanged(SoftApState state) {} /** * The callback which only is used in service internally and pass to WifiManager. @@ -418,12 +434,11 @@ public class WifiServiceImpl extends BaseWifiService { * Notify register the state of soft AP changed. */ public void notifyRegisterOnStateChanged(RemoteCallbackList<ISoftApCallback> callbacks, - int state, int failureReason) { + SoftApState state) { int itemCount = callbacks.beginBroadcast(); for (int i = 0; i < itemCount; i++) { try { - callbacks.getBroadcastItem(i).onStateChanged(state, - failureReason); + callbacks.getBroadcastItem(i).onStateChanged(state); } catch (RemoteException e) { Log.e(TAG, "onStateChanged: remote exception -- " + e); } @@ -497,7 +512,6 @@ public class WifiServiceImpl extends BaseWifiService { } } - public WifiServiceImpl(WifiContext context, WifiInjector wifiInjector) { mContext = context; mWifiInjector = wifiInjector; @@ -518,6 +532,8 @@ public class WifiServiceImpl extends BaseWifiService { mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager(); mWifiBackupRestore = mWifiInjector.getWifiBackupRestore(); mSoftApBackupRestore = mWifiInjector.getSoftApBackupRestore(); + mWifiSettingsBackupRestore = mWifiInjector.getWifiSettingsBackupRestore(); + mBackupRestoreController = mWifiInjector.getBackupRestoreController(); mWifiApConfigStore = mWifiInjector.getWifiApConfigStore(); mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil(); mLog = mWifiInjector.makeLog(TAG); @@ -560,6 +576,7 @@ public class WifiServiceImpl extends BaseWifiService { mApplicationQosPolicyRequestHandler = mWifiInjector.getApplicationQosPolicyRequestHandler(); mWifiPulledAtomLogger = mWifiInjector.getWifiPulledAtomLogger(); mAfcManager = mWifiInjector.getAfcManager(); + mTwtManager = mWifiInjector.getTwtManager(); } /** @@ -586,6 +603,15 @@ public class WifiServiceImpl extends BaseWifiService { mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility().initialize(); mWifiInjector.getWifiNotificationManager().createNotificationChannels(); // Align the value between config stroe (i.e.WifiConfigStore.xml) and WifiGlobals. + mSettingsConfigStore.registerChangeListener(WIFI_WEP_ALLOWED, + (key, value) -> { + if (mWifiGlobals.isWepAllowed() != value) { + // It should only happen when settings is restored from cloud. + handleWepAllowedChanged(value); + Log.i(TAG, "(Cloud Restoration) Wep allowed is changed to " + value); + } + }, + new Handler(mWifiHandlerThread.getLooper())); mWifiGlobals.setWepAllowed(mSettingsConfigStore.get(WIFI_WEP_ALLOWED)); mContext.registerReceiver( new BroadcastReceiver() { @@ -694,7 +720,6 @@ public class WifiServiceImpl extends BaseWifiService { mWifiTetheringDisallowed = mUserManager.getUserRestrictions() .getBoolean(UserManager.DISALLOW_WIFI_TETHERING); } - setPulledAtomCallbacks(); // Adding optimizations of only receiving broadcasts when wifi is enabled // can result in race conditions when apps toggle wifi in the background @@ -705,7 +730,6 @@ public class WifiServiceImpl extends BaseWifiService { mActiveModeWarden.start(); registerForCarrierConfigChange(); mWifiInjector.getAdaptiveConnectivityEnabledSettingObserver().initialize(); - mWifiInjector.getWifiDeviceStateChangeManager().handleBootCompleted(); mIsWifiServiceStarted = true; }); } @@ -720,6 +744,7 @@ public class WifiServiceImpl extends BaseWifiService { private void updateLocationMode() { mIsLocationModeEnabled = mWifiPermissionsUtil.isLocationModeEnabled(); mWifiConnectivityManager.setLocationModeEnabled(mIsLocationModeEnabled); + mWifiNative.setLocationModeEnabled(mIsLocationModeEnabled); } /** @@ -843,8 +868,6 @@ public class WifiServiceImpl extends BaseWifiService { // Start to listen country code change to avoid query supported channels causes boot // time increased. mCountryCode.registerListener(mCountryCodeTracker); - mTetheredSoftApTracker.handleBootCompleted(); - mLohsSoftApTracker.handleBootCompleted(); mWifiInjector.getSarManager().handleBootCompleted(); mWifiInjector.getSsidTranslator().handleBootCompleted(); mWifiInjector.getPasspointManager().handleBootCompleted(); @@ -855,6 +878,9 @@ public class WifiServiceImpl extends BaseWifiService { mWifiConfigManager.updateTrustOnFirstUseFlag(isTrustOnFirstUseSupported()); } updateVerboseLoggingEnabled(); + mWifiInjector.getWifiDeviceStateChangeManager().handleBootCompleted(); + setPulledAtomCallbacks(); + mTwtManager.registerWifiNativeTwtEvents(); }); } @@ -1166,10 +1192,7 @@ public class WifiServiceImpl extends BaseWifiService { && !isGuestUser()) || isPrivileged(pid, uid) || mWifiPermissionsUtil.isAdmin(uid, packageName) - || mWifiPermissionsUtil.isSystem(packageName, uid) - // TODO(b/140540984): Remove this bypass. - || (mWifiPermissionsUtil.checkSystemAlertWindowPermission(uid, packageName) - && !isGuestUser()); + || mWifiPermissionsUtil.isSystem(packageName, uid); } private boolean isGuestUser() { @@ -1261,7 +1284,7 @@ public class WifiServiceImpl extends BaseWifiService { // for any requester. To prevent non-privileged apps from deleting a tethering AP by // enabling Wi-Fi, only allow privileged apps to toggle Wi-Fi if tethering AP is up. if (!SdkLevel.isAtLeastS() && !isPrivileged - && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) { + && mTetheredSoftApTracker.getState().getState() == WIFI_AP_STATE_ENABLED) { mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush(); return false; } @@ -1528,7 +1551,7 @@ public class WifiServiceImpl extends BaseWifiService { if (mVerboseLoggingEnabled) { mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush(); } - return mTetheredSoftApTracker.getState(); + return mTetheredSoftApTracker.getState().getState(); } /** @@ -1685,7 +1708,7 @@ public class WifiServiceImpl extends BaseWifiService { if (!startSoftApInternal(new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, mTetheredSoftApTracker.getSoftApCapability(), - mCountryCode.getCountryCode()), requestorWs)) { + mCountryCode.getCountryCode(), null), requestorWs)) { mTetheredSoftApTracker.setFailedWhileEnabling(); return false; } @@ -1715,7 +1738,49 @@ public class WifiServiceImpl extends BaseWifiService { } mLog.info("startTetheredHotspot uid=%").c(callingUid).flush(); + return startTetheredHotspotInternal(new SoftApModeConfiguration( + WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, + mTetheredSoftApTracker.getSoftApCapability(), + mCountryCode.getCountryCode(), null /* request */), callingUid, packageName); + } + + /** + * see {@link WifiManager#startTetheredHotspotRequest(TetheringManager.TetheringRequest)} + * @param request TetheringRequest details of the Soft AP. + * @return {@code true} if softap start was triggered + * @throws SecurityException if the caller does not have permission to start softap + */ + @Override + public boolean startTetheredHotspotRequest(@NonNull TetheringManager.TetheringRequest request, + @NonNull String packageName) { + if (request == null) { + throw new IllegalArgumentException("TetheringRequest must not be null"); + } + + // NETWORK_STACK is a signature only permission. + enforceNetworkStackPermission(); + int callingUid = Binder.getCallingUid(); + mWifiPermissionsUtil.checkPackage(callingUid, packageName); + + // If user restriction is set, cannot start softap + if (mWifiTetheringDisallowed) { + mLog.err("startTetheredHotspotRequest with user restriction: not permitted").flush(); + return false; + } + mLog.info("startTetheredHotspotRequest uid=%").c(callingUid).flush(); + return startTetheredHotspotInternal(new SoftApModeConfiguration( + WifiManager.IFACE_IP_MODE_TETHERED, null /* config */, + mTetheredSoftApTracker.getSoftApCapability(), + mCountryCode.getCountryCode(), request), callingUid, packageName); + } + + /** + * Internal method to start tethered hotspot. Callers of this method should have already checked + * proper permissions beyond the NetworkStack permission. + */ + private boolean startTetheredHotspotInternal(@NonNull SoftApModeConfiguration modeConfig, + int callingUid, String packageName) { if (!mTetheredSoftApTracker.setEnablingIfAllowed()) { mLog.err("Tethering is already active or activating.").flush(); return false; @@ -1732,10 +1797,7 @@ public class WifiServiceImpl extends BaseWifiService { Binder.restoreCallingIdentity(id); } - if (!startSoftApInternal(new SoftApModeConfiguration( - WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, - mTetheredSoftApTracker.getSoftApCapability(), - mCountryCode.getCountryCode()), requestorWs)) { + if (!startSoftApInternal(modeConfig, requestorWs)) { mTetheredSoftApTracker.setFailedWhileEnabling(); return false; } @@ -1873,31 +1935,44 @@ public class WifiServiceImpl extends BaseWifiService { Log.e(TAG, "Country code not consistent! expect " + countryCode + " actual " + mCountryCode.getCurrentDriverCountryCode()); } - mTetheredSoftApTracker.updateAvailChannelListInSoftApCapability(countryCode); - mLohsSoftApTracker.updateAvailChannelListInSoftApCapability(countryCode); - mActiveModeWarden.updateSoftApCapability( - mTetheredSoftApTracker.getSoftApCapability(), - WifiManager.IFACE_IP_MODE_TETHERED); - // TODO: b/197529327 trigger Lohs capability callback & update available - // channels - mActiveModeWarden.updateSoftApCapability( - mLohsSoftApTracker.getSoftApCapability(), - WifiManager.IFACE_IP_MODE_LOCAL_ONLY); // Store Soft AP channels for reference after a reboot before the driver is up. Resources res = mContext.getResources(); mSettingsConfigStore.put(WifiSettingsConfigStore.WIFI_SOFT_AP_COUNTRY_CODE, countryCode); List<Integer> freqs = new ArrayList<>(); + SparseArray<int[]> channelMap = new SparseArray<>( + SoftApConfiguration.BAND_TYPES.length); for (int band : SoftApConfiguration.BAND_TYPES) { + if (!ApConfigUtil.isSoftApBandSupported(mContext, band)) { + continue; + } List<Integer> freqsForBand = ApConfigUtil.getAvailableChannelFreqsForBand( band, mWifiNative, res, true); if (freqsForBand != null) { freqs.addAll(freqsForBand); + int[] channel = new int[freqsForBand.size()]; + for (int i = 0; i < freqsForBand.size(); i++) { + channel[i] = ScanResult.convertFrequencyMhzToChannelIfSupported( + freqsForBand.get(i)); + } + channelMap.put(band, channel); } } mSettingsConfigStore.put( WifiSettingsConfigStore.WIFI_AVAILABLE_SOFT_AP_FREQS_MHZ, new JSONArray(freqs).toString()); + mTetheredSoftApTracker.updateAvailChannelListInSoftApCapability(countryCode, + channelMap); + mLohsSoftApTracker.updateAvailChannelListInSoftApCapability(countryCode, + channelMap); + mActiveModeWarden.updateSoftApCapability( + mTetheredSoftApTracker.getSoftApCapability(), + WifiManager.IFACE_IP_MODE_TETHERED); + // TODO: b/197529327 trigger Lohs capability callback & update available + // channels + mActiveModeWarden.updateSoftApCapability( + mLohsSoftApTracker.getSoftApCapability(), + WifiManager.IFACE_IP_MODE_LOCAL_ONLY); } if (SdkLevel.isAtLeastT()) { int itemCount = mRegisteredDriverCountryCodeListeners.beginBroadcast(); @@ -1943,7 +2018,9 @@ public class WifiServiceImpl extends BaseWifiService { * {@link WifiManager#WIFI_AP_STATE_FAILED} */ private final Object mLock = new Object(); - private int mSoftApState = WIFI_AP_STATE_DISABLED; + @NonNull + private SoftApState mSoftApState = + new SoftApState(WIFI_AP_STATE_DISABLED, 0, null, null); private Map<String, List<WifiClient>> mSoftApConnectedClientsMap = new HashMap(); private Map<String, SoftApInfo> mSoftApInfoMap = new HashMap(); private boolean mIsBridgedMode = false; @@ -1952,33 +2029,37 @@ public class WifiServiceImpl extends BaseWifiService { protected final RemoteCallbackList<ISoftApCallback> mRegisteredSoftApCallbacks = new RemoteCallbackList<>(); - public int getState() { + public SoftApState getState() { synchronized (mLock) { return mSoftApState; } } - public void setState(int state) { + public void setState(SoftApState softApState) { synchronized (mLock) { - mSoftApState = state; + mSoftApState = softApState; } } public boolean setEnablingIfAllowed() { synchronized (mLock) { - if (mSoftApState != WIFI_AP_STATE_DISABLED - && mSoftApState != WIFI_AP_STATE_FAILED) { + int state = mSoftApState.getState(); + if (state != WIFI_AP_STATE_DISABLED + && state != WIFI_AP_STATE_FAILED) { return false; } - mSoftApState = WIFI_AP_STATE_ENABLING; + mSoftApState = new SoftApState( + WIFI_AP_STATE_ENABLING, 0, null, null); return true; } } public void setFailedWhileEnabling() { synchronized (mLock) { - if (mSoftApState == WIFI_AP_STATE_ENABLING) { - mSoftApState = WIFI_AP_STATE_FAILED; + int state = mSoftApState.getState(); + if (state == WIFI_AP_STATE_ENABLING) { + mSoftApState = new SoftApState( + WIFI_AP_STATE_FAILED, 0, null, null); } } } @@ -2017,10 +2098,6 @@ public class WifiServiceImpl extends BaseWifiService { } } - public void handleBootCompleted() { - updateAvailChannelListInSoftApCapability(mCountryCode.getCurrentDriverCountryCode()); - } - public SoftApCapability getSoftApCapability() { synchronized (mLock) { if (mSoftApCapability == null) { @@ -2029,14 +2106,15 @@ public class WifiServiceImpl extends BaseWifiService { mSoftApCapability, mWifiInjector.getSettingsConfigStore()); // Default country code mSoftApCapability = updateSoftApCapabilityWithAvailableChannelList( - mSoftApCapability, mCountryCode.getCountryCode()); + mSoftApCapability, mCountryCode.getCountryCode(), null); } return mSoftApCapability; } } private SoftApCapability updateSoftApCapabilityWithAvailableChannelList( - @NonNull SoftApCapability softApCapability, @Nullable String countryCode) { + @NonNull SoftApCapability softApCapability, @Nullable String countryCode, + @Nullable SparseArray<int[]> channelMap) { if (!mIsBootComplete) { // The available channel list is from wificond or HAL. // It might be a failure or stuck during wificond or HAL init. @@ -2046,16 +2124,30 @@ public class WifiServiceImpl extends BaseWifiService { mSoftApCapability.setCountryCode(countryCode); } return ApConfigUtil.updateSoftApCapabilityWithAvailableChannelList( - softApCapability, mContext, mWifiNative); + softApCapability, mContext, mWifiNative, channelMap); } - public void updateAvailChannelListInSoftApCapability(@Nullable String countryCode) { + public void updateAvailChannelListInSoftApCapability(@Nullable String countryCode, + @Nullable SparseArray<int[]> channelMap) { onCapabilityChanged(updateSoftApCapabilityWithAvailableChannelList( - getSoftApCapability(), countryCode)); + getSoftApCapability(), countryCode, channelMap)); } public boolean registerSoftApCallback(ISoftApCallback callback) { - return mRegisteredSoftApCallbacks.register(callback); + if (!mRegisteredSoftApCallbacks.register(callback)) { + return false; + } + + // Update the client about the current state immediately after registering the callback + try { + callback.onStateChanged(getState()); + callback.onConnectedClientsOrInfoChanged(getSoftApInfos(), + getConnectedClients(), getIsBridgedMode(), true); + callback.onCapabilityChanged(getSoftApCapability()); + } catch (RemoteException e) { + Log.e(TAG, "registerSoftApCallback: remote exception -- " + e); + } + return true; } public void unregisterSoftApCallback(ISoftApCallback callback) { @@ -2064,19 +2156,11 @@ public class WifiServiceImpl extends BaseWifiService { /** * Called when soft AP state changes. - * - * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED}, - * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, - * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} - * @param failureReason reason when in failed state. One of - * {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL} */ @Override - public void onStateChanged(int state, int failureReason) { - synchronized (mLock) { - mSoftApState = state; - } - notifyRegisterOnStateChanged(mRegisteredSoftApCallbacks, state, failureReason); + public void onStateChanged(SoftApState softApState) { + setState(softApState); + notifyRegisterOnStateChanged(mRegisteredSoftApCallbacks, softApState); } /** @@ -2344,11 +2428,13 @@ public class WifiServiceImpl extends BaseWifiService { mActiveConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_LOCAL_ONLY, - softApConfig, lohsCapability, mCountryCode.getCountryCode()); + softApConfig, lohsCapability, mCountryCode.getCountryCode(), null); mIsExclusive = (request.getCustomConfig() != null); // Report the error if we got failure in startSoftApInternal if (!startSoftApInternal(mActiveConfig, request.getWorkSource())) { - onStateChanged(WIFI_AP_STATE_FAILED, ERROR_GENERIC); + onStateChanged(new SoftApState( + WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL, + mActiveConfig.getTetheringRequest(), null /* iface */)); } } @@ -2428,12 +2514,12 @@ public class WifiServiceImpl extends BaseWifiService { } @Override - public void onStateChanged(int state, int failureReason) { + public void onStateChanged(SoftApState softApState) { // The AP state update from ClientModeImpl for softap synchronized (mLocalOnlyHotspotRequests) { - Log.d(TAG, "lohs.onStateChanged: currentState=" + state - + " previousState=" + getState() + " errorCode= " + failureReason - + " ifaceName=" + mLohsInterfaceName); + Log.d(TAG, "lohs.onStateChanged: " + softApState); + int state = softApState.getState(); + int failureReason = softApState.getFailureReasonInternal(); // check if we have a failure - since it is possible (worst case scenario where // WifiController and ClientModeImpl are out of sync wrt modes) to get two FAILED @@ -2467,8 +2553,8 @@ public class WifiServiceImpl extends BaseWifiService { WifiManager.IFACE_IP_MODE_UNSPECIFIED); } // For enabling and enabled, just record the new state - setState(state); - notifyRegisterOnStateChanged(mRegisteredSoftApCallbacks, state, failureReason); + setState(softApState); + notifyRegisterOnStateChanged(mRegisteredSoftApCallbacks, softApState); } } } @@ -2510,16 +2596,6 @@ public class WifiServiceImpl extends BaseWifiService { Log.e(TAG, "registerSoftApCallback: Failed to add callback"); return; } - // Update the client about the current state immediately after registering the callback - try { - callback.onStateChanged(mTetheredSoftApTracker.getState(), 0); - callback.onConnectedClientsOrInfoChanged(mTetheredSoftApTracker.getSoftApInfos(), - mTetheredSoftApTracker.getConnectedClients(), - mTetheredSoftApTracker.getIsBridgedMode(), true); - callback.onCapabilityChanged(mTetheredSoftApTracker.getSoftApCapability()); - } catch (RemoteException e) { - Log.e(TAG, "registerSoftApCallback: remote exception -- " + e); - } }); } @@ -2651,7 +2727,7 @@ public class WifiServiceImpl extends BaseWifiService { } // check if we are currently tethering if (!mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs) - && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) { + && mTetheredSoftApTracker.getState().getState() == WIFI_AP_STATE_ENABLED) { // Tethering is enabled, cannot start LocalOnlyHotspot mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.") .flush(); @@ -2716,16 +2792,6 @@ public class WifiServiceImpl extends BaseWifiService { Log.e(TAG, "registerSoftApCallback: Failed to add callback"); return; } - // Update the client about the current state immediately after registering the callback - try { - callback.onStateChanged(mLohsSoftApTracker.getState(), 0); - callback.onConnectedClientsOrInfoChanged(mLohsSoftApTracker.getSoftApInfos(), - mLohsSoftApTracker.getConnectedClients(), - mLohsSoftApTracker.getIsBridgedMode(), true); - callback.onCapabilityChanged(mLohsSoftApTracker.getSoftApCapability()); - } catch (RemoteException e) { - Log.e(TAG, "registerSoftApCallback: remote exception -- " + e); - } }); } @@ -2850,7 +2916,7 @@ public class WifiServiceImpl extends BaseWifiService { listener.onResult(mWifiApConfigStore .getLastConfiguredTetheredApPassphraseSinceBoot()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -3060,7 +3126,11 @@ public class WifiServiceImpl extends BaseWifiService { } @Override - public void getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener) { + public void getWifiActivityEnergyInfoAsync(@NonNull IOnWifiActivityEnergyInfoListener + listener) { + if (listener == null) { + throw new IllegalArgumentException("listener should not be null"); + } enforceAccessPermission(); if (mVerboseLoggingEnabled) { mLog.info("getWifiActivityEnergyInfoAsync uid=%") @@ -3363,7 +3433,7 @@ public class WifiServiceImpl extends BaseWifiService { mNetworkSelectionConfig = builder.build(); listener.onResult(mNetworkSelectionConfig); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -3911,7 +3981,7 @@ public class WifiServiceImpl extends BaseWifiService { mConnectHelper.connectToNetwork( new NetworkUpdateResult(netId), new ActionListenerWrapper(connectListener), - callingUid, packageName) + callingUid, packageName, null) ) ); // now wait for response. @@ -4121,7 +4191,7 @@ public class WifiServiceImpl extends BaseWifiService { try { listener.onResult(mWifiConnectivityManager.getAutoJoinEnabledExternal()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -4412,7 +4482,7 @@ public class WifiServiceImpl extends BaseWifiService { try { listener.onResult(getChannelDataInternal()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -5020,7 +5090,7 @@ public class WifiServiceImpl extends BaseWifiService { mActiveModeWarden.getPrimaryClientModeManager() .enableTdlsWithRemoteIpAddress(remoteAddress, enable)); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -5068,7 +5138,7 @@ public class WifiServiceImpl extends BaseWifiService { mActiveModeWarden.getPrimaryClientModeManager() .enableTdls(remoteMacAddress, enable)); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -5087,7 +5157,7 @@ public class WifiServiceImpl extends BaseWifiService { mActiveModeWarden.getPrimaryClientModeManager() .isTdlsOperationCurrentlyAvailable()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -5110,7 +5180,7 @@ public class WifiServiceImpl extends BaseWifiService { mActiveModeWarden.getPrimaryClientModeManager() .getMaxSupportedConcurrentTdlsSessions()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -5129,7 +5199,7 @@ public class WifiServiceImpl extends BaseWifiService { mActiveModeWarden.getPrimaryClientModeManager() .getNumberOfEnabledTdlsSessions()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -5334,6 +5404,8 @@ public class WifiServiceImpl extends BaseWifiService { pw.println(); mWifiBackupRestore.dump(fd, pw, args); pw.println(); + mBackupRestoreController.dump(fd, pw, args); + pw.println(); pw.println("ScoringParams: " + mWifiInjector.getScoringParams()); pw.println(); mSettingsConfigStore.dump(fd, pw, args); @@ -5349,6 +5421,8 @@ public class WifiServiceImpl extends BaseWifiService { pw.println(); mWifiConfigManager.dump(fd, pw, args); pw.println(); + pw.println("WifiApConfigStore config: " + mWifiApConfigStore.getApConfiguration()); + pw.println(); mPasspointManager.dump(pw); mWifiInjector.getPasspointNetworkNominateHelper().dump(pw); pw.println(); @@ -5369,6 +5443,8 @@ public class WifiServiceImpl extends BaseWifiService { mWifiInjector.getLinkProbeManager().dump(fd, pw, args); pw.println(); mWifiNative.dump(pw); + pw.println(); + mWifiInjector.getWifiRoamingModeManager().dump(fd, pw, args); } }); } @@ -5540,6 +5616,8 @@ public class WifiServiceImpl extends BaseWifiService { } ApConfigUtil.enableVerboseLogging(mVerboseLoggingEnabled); mApplicationQosPolicyRequestHandler.enableVerboseLogging(mVerboseLoggingEnabled); + mWifiSettingsBackupRestore.enableVerboseLogging(mVerboseLoggingEnabled); + mBackupRestoreController.enableVerboseLogging(mVerboseLoggingEnabled); } @Override @@ -5673,6 +5751,54 @@ public class WifiServiceImpl extends BaseWifiService { /** * Retrieve the data to be backed to save the current state. * + * The data includes: + * 1. Wifi Settings (WifiSettingsConfigStore) + * 2. WifiConfiguration/IpConfiguration (original backup by retrieveBackupData) + * 3. SoftApConfiguration (original backup by retrieveSoftApBackupData) + * + * @param listener the listener to be used to receive backup data. + */ + @Override + public void retrieveWifiBackupData(IByteArrayListener listener) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + enforceNetworkSettingsPermission(); + mLog.info("retrieveWifiBackupData uid=%").c(Binder.getCallingUid()).flush(); + if (listener == null) { + throw new IllegalArgumentException("listener should not be null"); + } + mWifiThreadRunner.post(() -> { + try { + listener.onResult(mBackupRestoreController.retrieveBackupData()); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + }); + } + + /** + * Restore state from the backed up data. + * + * The api will guarantee the device would not damage when adding new XML tag. + * + * @param data Raw byte stream of the backed up data. + */ + @Override + public void restoreWifiBackupData(byte[] data) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + enforceNetworkSettingsPermission(); + mWifiThreadRunner.post(() -> { + mLog.info("restoreWifiBackupData uid=%").c(Binder.getCallingUid()).flush(); + mBackupRestoreController.parserBackupDataAndDispatch(data); + }); + } + + /** + * Retrieve the data to be backed to save the current state. + * * @return Raw byte stream of the data to be backed up. */ @Override @@ -6338,6 +6464,9 @@ public class WifiServiceImpl extends BaseWifiService { */ @Override public void removeOnWifiUsabilityStatsListener(IOnWifiUsabilityStatsListener listener) { + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); if (mVerboseLoggingEnabled) { @@ -6412,21 +6541,61 @@ public class WifiServiceImpl extends BaseWifiService { * @param netId Network ID of existing config to connect to if the supplied config is null * @param callback Listener to notify action result * @param packageName Package name of the requesting App + * @param extras Bundle of extras * * see: {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)} * {@link WifiManager#connect(int, WifiManager.ActionListener)} */ @Override public void connect(WifiConfiguration config, int netId, @Nullable IActionListener callback, - @NonNull String packageName) { - int uid = Binder.getCallingUid(); + @NonNull String packageName, Bundle extras) { + int uid = getMockableCallingUid(); if (!isPrivileged(Binder.getCallingPid(), uid)) { throw new SecurityException(TAG + ": Permission denied"); } if (packageName == null) { throw new IllegalArgumentException("packageName must not be null"); } - mLog.info("connect uid=%").c(uid).flush(); + final String attributionTagToUse; + final int uidToUse; + final String packageNameToUse; + if (SdkLevel.isAtLeastS() && UserHandle.getAppId(uid) == Process.SYSTEM_UID) { + AttributionSource as = extras.getParcelable( + WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE); + if (as == null) { + throw new SecurityException("connect attributionSource is null"); + } + if (!as.checkCallingUid()) { + throw new SecurityException( + "connect invalid (checkCallingUid fails) attribution source=" + + as); + } + // an attribution chain is either of size 1: unregistered (valid by definition) or + // size >1: in which case all are validated. + AttributionSource asIt = as; + AttributionSource asLast = as; + if (as.getNext() != null) { + do { + if (!asIt.isTrusted(mContext)) { + throw new SecurityException( + "connect invalid (isTrusted fails) attribution source=" + + asIt); + } + asIt = asIt.getNext(); + if (asIt != null) asLast = asIt; + } while (asIt != null); + } + // use the last AttributionSource in the chain - i.e. the original caller + attributionTagToUse = asLast.getAttributionTag(); + uidToUse = asLast.getUid(); + packageNameToUse = asLast.getPackageName(); + } else { + attributionTagToUse = mContext.getAttributionTag(); + uidToUse = uid; + packageNameToUse = packageName; + } + mLog.info("connect uid=% uidToUse=% packageNameToUse=% attributionTagToUse=%") + .c(uid).c(uidToUse).c(packageNameToUse).c(attributionTagToUse).flush(); mLastCallerInfoManager.put(config != null ? WifiManager.API_CONNECT_CONFIG : WifiManager.API_CONNECT_NETWORK_ID, Process.myTid(), uid, Binder.getCallingPid(), packageName, true); @@ -6552,7 +6721,8 @@ public class WifiServiceImpl extends BaseWifiService { mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers( () -> mConnectHelper.connectToNetwork( - result, wrapper, uid, packageName)); + result, wrapper, uidToUse, packageNameToUse, + attributionTagToUse)); }); } @@ -6846,7 +7016,7 @@ public class WifiServiceImpl extends BaseWifiService { mWifiConnectivityManager.setExternalPnoScanRequest( uid, packageName, binder, callback, ssids, frequencies); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -6899,7 +7069,7 @@ public class WifiServiceImpl extends BaseWifiService { } listener.onResult(lastCallerInfo.getPackageName(), lastCallerInfo.getToggleState()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -7302,10 +7472,19 @@ public class WifiServiceImpl extends BaseWifiService { ); } - @VisibleForTesting + /** + * See {@link android.net.wifi.WifiManager#isPreferredNetworkOffloadSupported()}. + */ + @Override public boolean isPnoSupported() { - return mWifiGlobals.isBackgroundScanSupported() - || (getSupportedFeatures() & WifiManager.WIFI_FEATURE_PNO) != 0; + return mWifiGlobals.isSwPnoEnabled() + || (mWifiGlobals.isBackgroundScanSupported() + && (getSupportedFeatures() & WifiManager.WIFI_FEATURE_PNO) != 0); + } + + private boolean isAggressiveRoamingModeSupported() { + return (getSupportedFeatures() & WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT) + != 0; } /** @@ -7609,8 +7788,8 @@ public class WifiServiceImpl extends BaseWifiService { return policyIdSet.size() == policyIds.length; } - private boolean policiesHaveDirection(List<QosPolicyParams> policyList, - @QosPolicyParams.Direction int direction) { + private boolean policiesHaveSameDirection(List<QosPolicyParams> policyList) { + int direction = policyList.get(0).getDirection(); for (QosPolicyParams policy : policyList) { if (policy.getDirection() != direction) { return false; @@ -7628,7 +7807,7 @@ public class WifiServiceImpl extends BaseWifiService { } listener.onResult(statusList); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } } @@ -7661,14 +7840,21 @@ public class WifiServiceImpl extends BaseWifiService { return; } - // Only downlink policies are currently supported. if (policyParamsList.size() == 0 || policyParamsList.size() > WifiManager.getMaxNumberOfPoliciesPerQosRequest() || !policyIdsAreUnique(policyParamsList) - || !policiesHaveDirection(policyParamsList, QosPolicyParams.DIRECTION_DOWNLINK)) { + || !policiesHaveSameDirection(policyParamsList)) { throw new IllegalArgumentException("policyParamsList is invalid"); } + if (!(SdkLevel.isAtLeastV() && isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX)) + && policyParamsList.get(0).getDirection() == QosPolicyParams.DIRECTION_UPLINK) { + Log.e(TAG, "Uplink QoS policies are only supported on devices with SDK >= V" + + " and 11ax support"); + rejectAllQosPolicies(policyParamsList, listener); + return; + } + mWifiThreadRunner.post(() -> { mApplicationQosPolicyRequestHandler.queueAddRequest( policyParamsList, listener, binder, uid); @@ -7762,7 +7948,7 @@ public class WifiServiceImpl extends BaseWifiService { try { listener.onResult(mWifiGlobals.getPollRssiIntervalMillis()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -7792,7 +7978,7 @@ public class WifiServiceImpl extends BaseWifiService { try { listener.onResult(mWifiNative.setMloMode(mode) == WifiStatusCode.SUCCESS); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -7819,7 +8005,7 @@ public class WifiServiceImpl extends BaseWifiService { try { listener.onResult(mWifiNative.getMloMode()); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -7902,7 +8088,7 @@ public class WifiServiceImpl extends BaseWifiService { listener.onResult(mWifiNative.getMaxMloAssociationLinkCount( mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName())); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -7934,7 +8120,7 @@ public class WifiServiceImpl extends BaseWifiService { listener.onResult(mWifiNative.getMaxMloStrLinkCount( mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName())); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -7979,7 +8165,7 @@ public class WifiServiceImpl extends BaseWifiService { } listener.onResult(supportedBands); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -8021,10 +8207,28 @@ public class WifiServiceImpl extends BaseWifiService { mLog.info("setWepAllowed=% uid=%").c(isAllowed).c(callingUid).flush(); mWifiThreadRunner.post(() -> { mSettingsConfigStore.put(WIFI_WEP_ALLOWED, isAllowed); - mWifiGlobals.setWepAllowed(isAllowed); + handleWepAllowedChanged(isAllowed); }); } + private void handleWepAllowedChanged(boolean isAllowed) { + mWifiGlobals.setWepAllowed(isAllowed); + if (!isAllowed) { + for (ClientModeManager clientModeManager + : mActiveModeWarden.getClientModeManagers()) { + if (!(clientModeManager instanceof ConcreteClientModeManager)) { + continue; + } + ConcreteClientModeManager cmm = (ConcreteClientModeManager) clientModeManager; + WifiInfo info = cmm.getConnectionInfo(); + if (info != null + && info.getCurrentSecurityType() == WifiInfo.SECURITY_TYPE_WEP) { + clientModeManager.disconnect(); + } + } + } + } + /** * See {@link WifiManager#queryWepAllowed(Executor, Consumer)} */ @@ -8042,7 +8246,100 @@ public class WifiServiceImpl extends BaseWifiService { try { listener.onResult(mSettingsConfigStore.get(WIFI_WEP_ALLOWED)); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); + } + }); + } + + /** + * See {@link WifiManager#enableMscs(MscsParams)} + */ + @Override + public void enableMscs(@NonNull MscsParams mscsParams) { + int uid = Binder.getCallingUid(); + if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { + throw new SecurityException( + "UID=" + uid + " is not allowed to set network selection config"); + } + Objects.requireNonNull(mscsParams); + mWifiThreadRunner.post(() -> { + List<ClientModeManager> clientModeManagers = + mActiveModeWarden.getInternetConnectivityClientModeManagers(); + for (ClientModeManager cmm : clientModeManagers) { + mWifiNative.enableMscs(mscsParams, cmm.getInterfaceName()); + } + }); + } + + /** + * See {@link WifiManager#disableMscs()} + */ + @Override + public void disableMscs() { + int uid = Binder.getCallingUid(); + if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { + throw new SecurityException( + "UID=" + uid + " is not allowed to set network selection config"); + } + mWifiThreadRunner.post(() -> { + List<ClientModeManager> clientModeManagers = + mActiveModeWarden.getInternetConnectivityClientModeManagers(); + for (ClientModeManager cmm : clientModeManagers) { + mWifiNative.disableMscs(cmm.getInterfaceName()); + } + }); + } + + /** + * See {@link android.net.wifi.WifiManager#setSendDhcpHostnameRestriction(int)}. + */ + public void setSendDhcpHostnameRestriction(@NonNull String packageName, + @WifiManager.SendDhcpHostnameRestriction int restriction) { + int callingUid = Binder.getCallingUid(); + int callingPid = Binder.getCallingPid(); + if (mVerboseLoggingEnabled) { + mLog.info("setSendDhcpHostnameRestriction:% uid=% package=%").c(restriction) + .c(callingUid).c(packageName).flush(); + } + if ((restriction + & ~WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN + & ~WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE) != 0) { + throw new IllegalArgumentException("Unknown dhcp hostname restriction flags: " + + restriction); + } + if (!isSettingsOrSuw(callingPid, callingUid) + && !mWifiPermissionsUtil.isDeviceOwner(callingUid, packageName)) { + throw new SecurityException("Uid " + callingUid + + " is not allowed to query the global dhcp hostname restriction"); + } + mWifiThreadRunner.post(() -> mWifiGlobals.setSendDhcpHostnameRestriction(restriction)); + } + + /** + * See {@link WifiManager#querySendDhcpHostnameRestriction(Executor, IntConsumer)} + */ + @Override + public void querySendDhcpHostnameRestriction(@NonNull String packageName, + @NonNull IIntegerListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener should not be null"); + } + int callingUid = Binder.getCallingUid(); + int callingPid = Binder.getCallingPid(); + if (mVerboseLoggingEnabled) { + mLog.info("querySendDhcpHostnameRestriction: uid=% package=%") + .c(callingUid).c(packageName).flush(); + } + if (!isSettingsOrSuw(callingPid, callingUid) + && !mWifiPermissionsUtil.isDeviceOwner(callingUid, packageName)) { + throw new SecurityException("Uid " + callingUid + + " is not allowed to query the global dhcp hostname restriction"); + } + mWifiThreadRunner.post(() -> { + try { + listener.onResult(mWifiGlobals.getSendDhcpHostnameRestriction()); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); } }); } @@ -8058,4 +8355,243 @@ public class WifiServiceImpl extends BaseWifiService { } return mWifiGlobals.forceOverlayConfigValue(configString, value, isEnabled); } + + /** + * See {@link WifiManager#setPerSsidRoamingMode(WifiSsid, int)} + */ + @Override + public void setPerSsidRoamingMode(WifiSsid ssid, @RoamingMode int roamingMode, + @NonNull String packageName) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + if (!isAggressiveRoamingModeSupported()) { + throw new UnsupportedOperationException("Aggressive roaming mode not supported"); + } + Objects.requireNonNull(ssid, "ssid cannot be null"); + Objects.requireNonNull(packageName, "packageName cannot be null"); + + if (roamingMode < WifiManager.ROAMING_MODE_NONE + || roamingMode > WifiManager.ROAMING_MODE_AGGRESSIVE) { + throw new IllegalArgumentException("invalid roaming mode: " + roamingMode); + } + + int uid = Binder.getCallingUid(); + mWifiPermissionsUtil.checkPackage(uid, packageName); + boolean isDeviceOwner = mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin( + uid, packageName); + if (!isDeviceOwner && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) + && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { + throw new SecurityException("Uid=" + uid + " is not allowed to add roaming policies"); + } + + //Store Roaming Mode per ssid + mWifiThreadRunner.post(() -> { + mWifiInjector.getWifiRoamingModeManager().setPerSsidRoamingMode(ssid, + roamingMode, isDeviceOwner); + }); + } + + /** + * See {@link WifiManager#removePerSsidRoamingMode(WifiSsid)} + */ + @Override + public void removePerSsidRoamingMode(WifiSsid ssid, @NonNull String packageName) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + if (!isAggressiveRoamingModeSupported()) { + throw new UnsupportedOperationException("Aggressive roaming mode not supported"); + } + Objects.requireNonNull(ssid, "ssid cannot be null"); + Objects.requireNonNull(packageName, "packageName cannot be null"); + + int uid = Binder.getCallingUid(); + mWifiPermissionsUtil.checkPackage(uid, packageName); + boolean isDeviceOwner = mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin( + uid, packageName); + if (!isDeviceOwner && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) + && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { + throw new SecurityException("Uid=" + uid + " is not allowed " + + "to remove roaming policies"); + } + + // Remove Roaming Mode per ssid + mWifiThreadRunner.post(() -> { + mWifiInjector.getWifiRoamingModeManager().removePerSsidRoamingMode( + ssid, isDeviceOwner); + }); + } + + /** + * See {@link WifiManager#getPerSsidRoamingModes(Executor, Consumer)} + */ + @Override + public void getPerSsidRoamingModes(@NonNull String packageName, + @NonNull IMapListener listener) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + if (!isAggressiveRoamingModeSupported()) { + throw new UnsupportedOperationException("Aggressive roaming mode not supported"); + } + Objects.requireNonNull(packageName, "packageName cannot be null"); + Objects.requireNonNull(listener, "listener cannot be null"); + + int uid = Binder.getCallingUid(); + boolean isDeviceOwner = mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin( + uid, packageName); + mWifiPermissionsUtil.checkPackage(uid, packageName); + if (!isDeviceOwner && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) + && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { + throw new SecurityException("Uid=" + uid + " is not allowed to get roaming policies"); + } + + // Get Roaming Modes per ssid + mWifiThreadRunner.post(() -> { + try { + Map<String, Integer> roamingPolicies = + mWifiInjector.getWifiRoamingModeManager().getPerSsidRoamingModes( + isDeviceOwner); + listener.onResult(roamingPolicies); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage()); + } + }); + } + + /** + * See {@link WifiManager#getTwtCapabilities(Executor, Consumer)} + */ + @Override + public void getTwtCapabilities(ITwtCapabilitiesListener listener, Bundle extras) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION); + if (mVerboseLoggingEnabled) { + mLog.info("getTwtCapabilities: Uid=% Package Name=%").c(Binder.getCallingUid()).c( + getPackageName(extras)).flush(); + } + if (listener == null) { + throw new IllegalArgumentException("listener should not be null"); + } + mWifiThreadRunner.post(() -> { + mTwtManager.getTwtCapabilities( + mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(), listener); + }); + } + + /** + * See {@link WifiManager#setupTwtSession(TwtRequest, Executor, TwtSessionCallback)} + */ + @Override + public void setupTwtSession(TwtRequest twtRequest, ITwtCallback iTwtCallback, Bundle extras) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + if (iTwtCallback == null) { + throw new IllegalArgumentException("Callback should not be null"); + } + if (twtRequest == null) { + throw new IllegalArgumentException("twtRequest should not be null"); + } + enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION); + int callingUid = Binder.getCallingUid(); + if (mVerboseLoggingEnabled) { + mLog.info("setupTwtSession: Uid=% Package Name=%").c(callingUid).c( + getPackageName(extras)).flush(); + } + mWifiThreadRunner.post(() -> { + try { + String bssid = mActiveModeWarden.getPrimaryClientModeManager().getConnectedBssid(); + if (!mActiveModeWarden.getPrimaryClientModeManager().isConnected() + || bssid == null) { + iTwtCallback.onFailure(TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + return; + } + mTwtManager.setupTwtSession( + mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(), + twtRequest, iTwtCallback, callingUid, bssid); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + }); + } + + /** + /** + * See {@link TwtSession#getStats(Executor, Consumer)}} + */ + @Override + public void getStatsTwtSession(int sessionId, ITwtStatsListener iTwtStatsListener, + Bundle extras) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + if (iTwtStatsListener == null) { + throw new IllegalArgumentException("Callback should not be null"); + } + enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION); + if (mVerboseLoggingEnabled) { + mLog.info("getStatsTwtSession: Uid=% Package Name=%").c(Binder.getCallingUid()).c( + getPackageName(extras)).flush(); + } + mWifiThreadRunner.post(() -> { + mTwtManager.getStatsTwtSession( + mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(), + iTwtStatsListener, sessionId); + }); + } + + /** + * See {@link TwtSession#teardown()} + */ + @Override + public void teardownTwtSession(int sessionId, Bundle extras) { + if (!SdkLevel.isAtLeastV()) { + throw new UnsupportedOperationException("SDK level too old"); + } + enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION); + if (mVerboseLoggingEnabled) { + mLog.info("teardownTwtSession: Uid=% Package Name=%").c(Binder.getCallingUid()).c( + getPackageName(extras)).flush(); + } + mWifiThreadRunner.post(() -> { + mTwtManager.tearDownTwtSession( + mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(), sessionId); + }); + } + + /** + * See {@link WifiManager#setD2dAllowedWhenInfraStaDisabled(boolean)}. + */ + @Override + public void setD2dAllowedWhenInfraStaDisabled(boolean isAllowed) { + int callingUid = Binder.getCallingUid(); + if (!isSettingsOrSuw(Binder.getCallingPid(), callingUid)) { + throw new SecurityException("Uid " + callingUid + + " is not allowed to set d2d allowed when infra Sta is disabled"); + } + mLog.info("setD2dAllowedWhenInfraStaDisabled=% uid=%").c(isAllowed).c(callingUid).flush(); + mWifiThreadRunner.post( + () -> mSettingsConfigStore.put(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED, isAllowed)); + } + + /** + * See {@link WifiManager#queryD2dAllowedWhenInfraStaDisabled(Executor, Consumer)} + */ + @Override + public void queryD2dAllowedWhenInfraStaDisabled(@NonNull IBooleanListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener should not be null"); + } + mWifiThreadRunner.post(() -> { + try { + listener.onResult(mSettingsConfigStore.get(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED)); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + }); + } } diff --git a/service/java/com/android/server/wifi/WifiSettingsBackupRestore.java b/service/java/com/android/server/wifi/WifiSettingsBackupRestore.java new file mode 100644 index 0000000000..e539655c9e --- /dev/null +++ b/service/java/com/android/server/wifi/WifiSettingsBackupRestore.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2024 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.util.Log; + +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.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * Class used to backup/restore data using the SettingsBackupAgent. + * There are 2 symmetric API's exposed here: + * 1. retrieveBackupDataFromSettingsConfigStore: Retrieve the configuration data to be backed up. + * 2. retrieveSettingsFromBackupData: Restore the configuration using the provided data. + * The byte stream to be backed up is XML encoded and versioned to migrate the data easily across + * revisions. + */ +public class WifiSettingsBackupRestore { + private static final String TAG = "WifiSettingsBackupRestore"; + + public static final String XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA = + "WifiSettingsSection"; + + private WifiSettingsConfigStore mWifiSettingsConfigStore; + private Map<String, WifiSettingsConfigStore.Key> mRestoreSettingsMap = new HashMap<>(); + /** + * Verbose logging flag. + */ + private boolean mVerboseLoggingEnabled = false; + + public WifiSettingsBackupRestore(WifiSettingsConfigStore settingsConfigStore) { + mWifiSettingsConfigStore = settingsConfigStore; + for (WifiSettingsConfigStore.Key key : mWifiSettingsConfigStore.getAllKeys()) { + mRestoreSettingsMap.put(key.key, key); + } + } + + /** + * Retrieve a byte stream representing the data that needs to be backed up from the + * provided WifiSettingsConfigStore. + */ + public void retrieveBackupDataFromSettingsConfigStore(XmlSerializer out, + ByteArrayOutputStream outputStream) { + Map<String, Object> backupSettingsMap = new HashMap<>(); + try { + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + // Start writing the XML stream. + XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA); + XmlUtil.writeNextSectionStart(out, + WifiSettingsConfigStore.StoreData.XML_TAG_SECTION_HEADER); + // Prepare the setting's map. + for (WifiSettingsConfigStore.Key key + : mWifiSettingsConfigStore.getAllBackupRestoreKeys()) { + backupSettingsMap.put(key.key, mWifiSettingsConfigStore.get(key)); + } + XmlUtil.writeNextValue(out, WifiSettingsConfigStore.StoreData.XML_TAG_VALUES, + backupSettingsMap); + + XmlUtil.writeNextSectionEnd(out, + WifiSettingsConfigStore.StoreData.XML_TAG_SECTION_HEADER); + XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA); + } catch (XmlPullParserException | IOException e) { + Log.e(TAG, "Error retrieving the backup data: " + e); + } + } + + /** + * Parse out the wifi settings from the back up data and restore it. + * + * @param in the xml parser. + * @param depth the current depth which the tag XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA. + */ + public void restoreSettingsFromBackupData(XmlPullParser in, int depth) { + if (in == null) { + Log.e(TAG, "Invalid backup data received"); + return; + } + try { + XmlUtil.gotoNextSectionWithName(in, + WifiSettingsConfigStore.StoreData.XML_TAG_SECTION_HEADER, depth + 1); + Map<String, Object> values = + WifiSettingsConfigStore.StoreData.deserializeSettingsData(in, depth + 2); + if (values != null) { + for (String keyString : values.keySet()) { + if (mRestoreSettingsMap.containsKey(keyString)) { + if (mVerboseLoggingEnabled) { + Log.i(TAG, "Restored Settings: " + keyString + + " with value: " + values.get(keyString)); + } + mWifiSettingsConfigStore.put(mRestoreSettingsMap.get(keyString), + values.get(keyString)); + } else { + Log.e(TAG, "Unexpcected Settings found: " + keyString + + " with value: " + values.get(keyString)); + } + } + } + } catch (XmlPullParserException | IOException | ClassCastException + | IllegalArgumentException e) { + Log.e(TAG, "Error parsing the backup data: " + e); + } + } + + /** + * Enable verbose logging. + * + * @param verboseEnabled whether or not verbosity log level is enabled. + */ + public void enableVerboseLogging(boolean verboseEnabled) { + mVerboseLoggingEnabled = verboseEnabled; + } +} diff --git a/service/java/com/android/server/wifi/WifiSettingsConfigStore.java b/service/java/com/android/server/wifi/WifiSettingsConfigStore.java index c49ec13cc1..09988abc3b 100644 --- a/service/java/com/android/server/wifi/WifiSettingsConfigStore.java +++ b/service/java/com/android/server/wifi/WifiSettingsConfigStore.java @@ -26,6 +26,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.wifi.util.SettingsMigrationDataHolder; import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; @@ -39,7 +40,9 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; /** * Store data for storing wifi settings. These are key (string) / value pairs that are stored in @@ -193,6 +196,16 @@ public class WifiSettingsConfigStore { public static final Key<Boolean> WIFI_WIPHY_11BE_SUPPORTED = new Key<>("wifi_wiphy_11be_supported", true); + /** + * Whether the D2D is allowed or not when infra sta is disabled. + */ + public static final Key<Boolean> D2D_ALLOWED_WHEN_INFRA_STA_DISABLED = + new Key<>("d2d_allowed_when_infra_sta_disabled", false); + + // List of all keys which require to backup and restore. + private static final List<Key> sBackupRestoreKeys = List.of( + WIFI_WEP_ALLOWED, + D2D_ALLOWED_WHEN_INFRA_STA_DISABLED); /******** Wifi shared pref keys ***************/ private final Context mContext; @@ -237,6 +250,14 @@ public class WifiSettingsConfigStore { wifiConfigStore.registerStoreData(new StoreData()); } + public ArrayList<Key> getAllKeys() { + return sKeys; + } + + public List<Key> getAllBackupRestoreKeys() { + return sBackupRestoreKeys; + } + private void invokeAllListeners() { synchronized (mLock) { for (Key key : sKeys) { @@ -417,18 +438,44 @@ public class WifiSettingsConfigStore { sKeys.add(this); } + @VisibleForTesting + public String getKey() { + return key; + } + @Override public String toString() { return "[Key " + key + ", DefaultValue: " + defaultValue + "]"; } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + // null instanceof [type]" also returns false + if (!(o instanceof Key)) { + return false; + } + + Key anotherKey = (Key) o; + return Objects.equals(key, anotherKey.key) + && Objects.equals(defaultValue, anotherKey.defaultValue); + } + + @Override + public int hashCode() { + return Objects.hash(key, defaultValue); + } } /** * Store data for persisting the settings data to config store. */ - private class StoreData implements WifiConfigStore.StoreData { - private static final String XML_TAG_SECTION_HEADER = "Settings"; - private static final String XML_TAG_VALUES = "Values"; + public class StoreData implements WifiConfigStore.StoreData { + public static final String XML_TAG_SECTION_HEADER = "Settings"; + public static final String XML_TAG_VALUES = "Values"; @Override public void serializeData(XmlSerializer out, @@ -450,6 +497,22 @@ public class WifiSettingsConfigStore { migrateFromSettingsIfNeeded(); return; } + Map<String, Object> values = deserializeSettingsData(in, outerTagDepth); + if (values != null) { + synchronized (mLock) { + mSettings.putAll(values); + // Invoke all the registered listeners. + invokeAllListeners(); + } + } + } + + /** + * Parse out the wifi settings from the input xml stream. + */ + public static Map<String, Object> deserializeSettingsData( + XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException { Map<String, Object> values = null; while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { String[] valueName = new String[1]; @@ -467,13 +530,7 @@ public class WifiSettingsConfigStore { break; } } - if (values != null) { - synchronized (mLock) { - mSettings.putAll(values); - // Invoke all the registered listeners. - invokeAllListeners(); - } - } + return values; } @Override diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java index 1541273ba5..98807410f7 100644 --- a/service/java/com/android/server/wifi/WifiShellCommand.java +++ b/service/java/com/android/server/wifi/WifiShellCommand.java @@ -61,6 +61,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApInfo; +import android.net.wifi.SoftApState; import android.net.wifi.SupplicantState; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiClient; @@ -232,17 +233,17 @@ public class WifiShellCommand extends BasicShellCommandHandler { } @Override - public void onStateChanged(int state, int failureReason) { - mPrintWriter.println("onStateChanged with state: " + state - + " failure reason: " + failureReason); - mSapState = state; - if (state == WifiManager.WIFI_AP_STATE_ENABLED) { + public void onStateChanged(SoftApState state) { + mPrintWriter.println("onStateChanged with state: " + state); + + mSapState = state.getState(); + if (mSapState == WifiManager.WIFI_AP_STATE_ENABLED) { mPrintWriter.println(" SAP is enabled successfully"); // Skip countDown() and wait for onInfoChanged() which has // the confirmed softAp channel information - } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) { + } else if (mSapState == WifiManager.WIFI_AP_STATE_DISABLED) { mPrintWriter.println(" SAP is disabled"); - } else if (state == WifiManager.WIFI_AP_STATE_FAILED) { + } else if (mSapState == WifiManager.WIFI_AP_STATE_FAILED) { mPrintWriter.println(" SAP failed to start"); mCountDownLatch.countDown(); } @@ -596,21 +597,22 @@ public class WifiShellCommand extends BasicShellCommandHandler { } case "imsi-protection-exemption-clear-user-approved-for-carrier": { String arg1 = getNextArgRequired(); - int carrierId = -1; try { - carrierId = Integer.parseInt(arg1); + final int carrierId = Integer.parseInt(arg1); + mWifiThreadRunner.post(() -> + mWifiCarrierInfoManager.clearImsiPrivacyExemptionForCarrier( + carrierId)); } catch (NumberFormatException e) { pw.println("Invalid argument to " + "'imsi-protection-exemption-clear-user-approved-for-carrier' " + "- 'carrierId' must be an Integer"); return -1; } - mWifiCarrierInfoManager.clearImsiPrivacyExemptionForCarrier(carrierId); return 0; } case "network-requests-remove-user-approved-access-points": { String packageName = getNextArgRequired(); - mWifiNetworkFactory.removeApp(packageName); + mWifiThreadRunner.post(() -> mWifiNetworkFactory.removeApp(packageName)); return 0; } case "clear-user-disabled-networks": { @@ -1005,7 +1007,8 @@ public class WifiShellCommand extends BasicShellCommandHandler { } }; WifiConfiguration config = buildWifiConfiguration(pw); - mWifiService.connect(config, -1, actionListener, SHELL_PACKAGE_NAME); + mWifiService.connect(config, -1, actionListener, SHELL_PACKAGE_NAME, + new Bundle()); // wait for status. countDownLatch.await(500, TimeUnit.MILLISECONDS); setAutoJoin(pw, config.SSID, config.allowAutojoin); @@ -2057,6 +2060,19 @@ public class WifiShellCommand extends BasicShellCommandHandler { return 0; } + case "get-cached-scan-data": + WifiScanner.ScanData scanData = + mWifiNative.getCachedScanResultsFromAllClientIfaces(); + + if (scanData.getResults().length > 0) { + pw.println("Successfully get cached scan data: "); + for (ScanResult scanResult : scanData.getResults()) { + pw.println(scanResult); + } + } else { + pw.println("Cached scan data is empty"); + } + return 0; case "configure-afc-server": final String url = getNextArgRequired(); @@ -2960,6 +2976,8 @@ public class WifiShellCommand extends BasicShellCommandHandler { pw.println(" '15' - band 2.4, 5, and 6 GHz with DFS channels"); pw.println(" '16' - band 60 GHz"); pw.println(" '31' - band 2.4, 5, 6 and 60 GHz with DFS channels"); + pw.println(" get-cached-scan-data"); + pw.println(" Gets scan data cached by the firmware"); pw.println(" force-overlay-config-value <overlayName> <configString> enabled|disabled"); pw.println(" Force overlay to a specified value. See below for supported overlays."); pw.println(" <overlayName> - name of the overlay whose value is overridden."); diff --git a/service/java/com/android/server/wifi/WifiSignalPollResults.java b/service/java/com/android/server/wifi/WifiSignalPollResults.java index c82281d8b7..9e83c001e2 100644 --- a/service/java/com/android/server/wifi/WifiSignalPollResults.java +++ b/service/java/com/android/server/wifi/WifiSignalPollResults.java @@ -180,4 +180,14 @@ public class WifiSignalPollResults { public int getFrequency(int linkId) { return mEntries.getOrDefault(linkId, mDefault).frequencyMHz; } + + /** + * Return whether the poll results available for the specific link. + * + * @param linkId Identifier of the link. + * @return true if available, otherwise false + */ + public boolean isAvailable(int linkId) { + return mEntries.containsKey(linkId); + } } diff --git a/service/java/com/android/server/wifi/WifiThreadRunner.java b/service/java/com/android/server/wifi/WifiThreadRunner.java index c3210de5c9..0a9eb524df 100644 --- a/service/java/com/android/server/wifi/WifiThreadRunner.java +++ b/service/java/com/android/server/wifi/WifiThreadRunner.java @@ -16,10 +16,13 @@ package com.android.server.wifi; +import static com.android.server.wifi.RunnerHandler.KEY_SIGNATURE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; import android.os.Looper; +import android.os.Message; import android.os.SystemClock; import android.util.Log; @@ -186,6 +189,20 @@ public class WifiThreadRunner { } /** + * Asynchronously runs a Runnable on the main Wifi thread. With specified task name for metrics + * logging + * @return true if the runnable was successfully posted <b>(not executed)</b> to the main Wifi + * thread, false otherwise + * @param runnable The Runnable that will be executed. + * @param taskName The task name for performance logging + */ + public boolean post(@NonNull Runnable runnable, String taskName) { + Message m = Message.obtain(mHandler, runnable); + m.getData().putString(KEY_SIGNATURE, taskName); + return mHandler.sendMessage(m); + } + + /** * Asynchronously runs a Runnable on the main Wifi thread with delay. * * @param runnable The Runnable that will be executed. diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java index 6dadd23364..9e50b0b1d4 100644 --- a/service/java/com/android/server/wifi/WifiVendorHal.java +++ b/service/java/com/android/server/wifi/WifiVendorHal.java @@ -31,8 +31,11 @@ import android.net.wifi.ScanResult; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.RoamingMode; import android.net.wifi.WifiScanner; import android.net.wifi.WifiSsid; +import android.net.wifi.twt.TwtRequest; +import android.os.Bundle; import android.os.Handler; import android.os.WorkSource; import android.text.TextUtils; @@ -116,6 +119,7 @@ public class WifiVendorHal { private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks; private final WifiStaIface.Callback mWifiStaIfaceEventCallback; private final ChipEventCallback mWifiChipEventCallback; + private WifiNative.WifiTwtEvents mWifiTwtEvents; // Plumbing for event handling. // @@ -124,7 +128,6 @@ public class WifiVendorHal { // https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5 private final Handler mHalEventHandler; - /** * Wi-Fi chip related info. */ @@ -716,6 +719,20 @@ public class WifiVendorHal { } /** + * Gets the cached scan data. + * + * @param ifaceName Name of the interface. + */ + @Nullable + public WifiScanner.ScanData getCachedScanData(@NonNull String ifaceName) { + synchronized (sLock) { + WifiStaIface iface = getStaIface(ifaceName); + if (iface == null) return null; + return iface.getCachedScanData(); + } + } + + /** * Get the link layer statistics * * Note - we always enable link layer stats on a STA interface. @@ -1715,6 +1732,82 @@ public class WifiVendorHal { } eventHandler.onRssiThresholdBreached((byte) currRssi); } + + /** + * Called when a TWT operation fails. + * + * @param cmdId Unique command id which is failed + * @param twtErrorCode Error code + */ + @Override + public void onTwtFailure(int cmdId, int twtErrorCode) { + synchronized (sLock) { + mHalEventHandler.post(() -> { + if (mWifiTwtEvents == null) return; + mWifiTwtEvents.onTwtFailure(cmdId, twtErrorCode); + }); + } + } + + /** + * Called when {@link WifiStaIface#setupTwtSession(int, TwtRequest)} succeeds. + * + * @param cmdId Unique command id used in + * {@link WifiStaIface#setupTwtSession(int, TwtRequest)} + * @param wakeDurationUs TWT wake duration for the session in microseconds + * @param wakeIntervalUs TWT wake interval for the session in microseconds + * @param linkId Multi link operation link id + * @param sessionId TWT session id + */ + @Override + public void onTwtSessionCreate(int cmdId, int wakeDurationUs, long wakeIntervalUs, + int linkId, int sessionId) { + synchronized (sLock) { + mHalEventHandler.post(() -> { + if (mWifiTwtEvents == null) return; + mWifiTwtEvents.onTwtSessionCreate(cmdId, wakeDurationUs, wakeIntervalUs, + linkId, + sessionId); + }); + } + + } + + /** + * Called when TWT session is torndown by {@link WifiStaIface#tearDownTwtSession(int, int)}. + * Can also be called unsolicitedly by the vendor software with proper reason code. + * + * @param cmdId Unique command id used in + * {@link WifiStaIface#tearDownTwtSession(int, int)} + * @param twtSessionId TWT session Id + */ + @Override + public void onTwtSessionTeardown(int cmdId, int twtSessionId, int twtReasonCode) { + synchronized (sLock) { + mHalEventHandler.post(() -> { + if (mWifiTwtEvents == null) return; + mWifiTwtEvents.onTwtSessionTeardown(cmdId, twtSessionId, twtReasonCode); + }); + } + } + + /** + * Called as a response to {@link WifiStaIface#getStatsTwtSession(int, int)} + * + * @param cmdId Unique command id used in + * {@link WifiStaIface#getStatsTwtSession(int, int)} + * @param twtSessionId TWT session Id + * @param twtStats TWT stats bundle + */ + @Override + public void onTwtSessionStats(int cmdId, int twtSessionId, Bundle twtStats) { + synchronized (sLock) { + mHalEventHandler.post(() -> { + if (mWifiTwtEvents == null) return; + mWifiTwtEvents.onTwtSessionStats(cmdId, twtSessionId, twtStats); + }); + } + } } /** @@ -2006,4 +2099,67 @@ public class WifiVendorHal { if (mWifiChip == null) return false; return mWifiChip.setAfcChannelAllowance(afcChannelAllowance); } + + /** + * See {@link WifiNative#setRoamingMode(String, int)}. + */ + public @WifiStatusCode int setRoamingMode(@NonNull String ifaceName, + @RoamingMode int roamingMode) { + synchronized (sLock) { + WifiStaIface iface = getStaIface(ifaceName); + if (iface == null) return WifiStatusCode.ERROR_WIFI_IFACE_INVALID; + return iface.setRoamingMode(roamingMode); + } + } + + /** + * See {@link WifiNative#getTwtCapabilities(String)} + */ + public Bundle getTwtCapabilities(String ifaceName) { + synchronized (sLock) { + WifiStaIface wifiStaIface = getStaIface(ifaceName); + if (wifiStaIface == null) return null; + return wifiStaIface.getTwtCapabilities(); + } + } + + /** + * See {@link WifiNative#registerTwtCallbacks(TwtManager.WifiNativeTwtEvents)} + */ + public void registerTwtCallbacks(WifiNative.WifiTwtEvents wifiTwtCallback) { + mWifiTwtEvents = wifiTwtCallback; + } + + /** + * See {@link WifiNative#setupTwtSession(int, String, TwtRequest)} + */ + public boolean setupTwtSession(int cmdId, String ifaceName, TwtRequest twtRequest) { + synchronized (sLock) { + WifiStaIface wifiStaIface = getStaIface(ifaceName); + if (wifiStaIface == null) return false; + return wifiStaIface.setupTwtSession(cmdId, twtRequest); + } + } + + /** + * See {@link WifiNative#tearDownTwtSession(int, String, int)} + */ + public boolean tearDownTwtSession(int cmdId, String ifaceName, int sessionId) { + synchronized (sLock) { + WifiStaIface wifiStaIface = getStaIface(ifaceName); + if (wifiStaIface == null) return false; + return wifiStaIface.tearDownTwtSession(cmdId, sessionId); + } + } + + /** + * See {@link WifiNative#getStatsTwtSession(int, String, int)} + */ + public boolean getStatsTwtSession(int cmdId, String ifaceName, int sessionId) { + synchronized (sLock) { + WifiStaIface wifiStaIface = getStaIface(ifaceName); + if (wifiStaIface == null) return false; + return wifiStaIface.getStatsTwtSession(cmdId, sessionId); + } + } } diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java b/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java index 06bc0a7262..e5fdeed2ff 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java @@ -24,6 +24,8 @@ import static com.android.server.wifi.aware.WifiAwareStateManager.INSTANT_MODE_D import static com.android.server.wifi.aware.WifiAwareStateManager.NAN_PAIRING_REQUEST_TYPE_SETUP; import static com.android.server.wifi.aware.WifiAwareStateManager.NAN_PAIRING_REQUEST_TYPE_VERIFICATION; +import android.annotation.NonNull; +import android.net.wifi.OuiKeyedData; import android.net.wifi.WifiScanner; import android.net.wifi.aware.AwarePairingConfig; import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; @@ -41,6 +43,7 @@ import com.android.server.wifi.hal.WifiNanIface.NanStatusCode; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Arrays; +import java.util.List; /** * Manages the state of a single Aware discovery session (publish or subscribe). @@ -512,10 +515,11 @@ public class WifiAwareDiscoverySessionState { * @param peerId ID of the peer. Obtained through previous communication (a * match indication). * @param method proposed bootstrapping method + * @param isComeBack If the request is for a previous comeback response * @return True if the request send succeed. */ public boolean initiateBootstrapping(short transactionId, - int peerId, int method, byte[] cookie) { + int peerId, int method, byte[] cookie, boolean isComeBack) { PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); if (peerInfo == null) { Log.e(TAG, "initiateBootstrapping: attempting to send pairing request to an address" @@ -529,7 +533,7 @@ public class WifiAwareDiscoverySessionState { } boolean success = mWifiAwareNativeApi.initiateBootstrapping(transactionId, - peerInfo.mInstanceId, peerInfo.mMac, method, cookie); + peerInfo.mInstanceId, peerInfo.mMac, method, cookie, mPubSubId, isComeBack); if (!success) { try { mCallback.onBootstrappingVerificationConfirmed(peerId, false, method); @@ -563,7 +567,7 @@ public class WifiAwareDiscoverySessionState { } boolean success = mWifiAwareNativeApi.respondToBootstrappingRequest(transactionId, - bootstrappingId, accept); + bootstrappingId, accept, mPubSubId); return success; } @@ -585,16 +589,21 @@ public class WifiAwareDiscoverySessionState { public int onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndication, int rangeMm, int peerCipherSuite, byte[] scid, String pairingAlias, - AwarePairingConfig pairingConfig) { + AwarePairingConfig pairingConfig, @NonNull List<OuiKeyedData> vendorDataList) { int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac); + OuiKeyedData[] vendorDataArray = null; + if (!vendorDataList.isEmpty()) { + vendorDataArray = new OuiKeyedData[vendorDataList.size()]; + vendorDataList.toArray(vendorDataArray); + } try { if (rangingIndication == 0) { mCallback.onMatch(peerId, serviceSpecificInfo, matchFilter, peerCipherSuite, scid, - pairingAlias, pairingConfig); + pairingAlias, pairingConfig, vendorDataArray); } else { mCallback.onMatchWithDistance(peerId, serviceSpecificInfo, matchFilter, rangeMm, - peerCipherSuite, scid, pairingAlias, pairingConfig); + peerCipherSuite, scid, pairingAlias, pairingConfig, vendorDataArray); } } catch (RemoteException e) { Log.w(TAG, "onMatch: RemoteException (FYI): " + e); diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java index f7391971c3..44f8bce00d 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java @@ -798,10 +798,12 @@ public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellC * indication). * @param peer The MAC address of the peer to create a connection with. * @param method proposed bootstrapping method + * @param pubSubId ID of the publish/subscribe session - obtained when creating a session. + * @param isComeBack If the request is for a previous comeback response * @return True if the request send success */ public boolean initiateBootstrapping(short transactionId, int peerId, byte[] peer, int method, - byte[] cookie) { + byte[] cookie, byte pubSubId, boolean isComeBack) { if (mVerboseLoggingEnabled) { Log.v(TAG, "initiateBootstrapping: transactionId=" + transactionId + ", peerId=" + peerId + ", method=" + method @@ -817,7 +819,8 @@ public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellC try { MacAddress peerMac = MacAddress.fromBytes(peer); - return iface.initiateBootstrapping(transactionId, peerId, peerMac, method, cookie); + return iface.initiateBootstrapping(transactionId, peerId, peerMac, method, cookie, + pubSubId, isComeBack); } catch (IllegalArgumentException e) { Log.e(TAG, "Invalid peer mac received: " + Arrays.toString(peer)); return false; @@ -826,14 +829,17 @@ public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellC /** * Response to a bootstrapping request for this from this session - * @param transactionId Transaction ID for the transaction - used in the - * async callback to match with the original request. + * + * @param transactionId Transaction ID for the transaction - used in the + * async callback to match with the original request. * @param bootstrappingId The id of the current boostraping session - * @param accept True is proposed method is accepted + * @param accept True is proposed method is accepte + * @param pubSubId ID of the publish/subscribe session - obtained when creating a + * session. * @return True if the request send success */ public boolean respondToBootstrappingRequest(short transactionId, int bootstrappingId, - boolean accept) { + boolean accept, byte pubSubId) { if (mVerboseLoggingEnabled) { Log.v(TAG, "respondToBootstrappingRequest: transactionId=" + transactionId); } @@ -845,7 +851,8 @@ public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellC return false; } - return iface.respondToBootstrappingRequest(transactionId, bootstrappingId, accept); + return iface.respondToBootstrappingRequest(transactionId, bootstrappingId, accept, + pubSubId); } /** diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java index 0e8e33e268..d6f02bcd78 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java @@ -16,6 +16,8 @@ package com.android.server.wifi.aware; +import android.annotation.Nullable; +import android.net.wifi.OuiKeyedData; import android.net.wifi.aware.AwarePairingConfig; import android.net.wifi.aware.IdentityChangedListener; import android.net.wifi.aware.WifiAwareChannelInfo; @@ -337,11 +339,12 @@ public class WifiAwareNativeCallback implements WifiNanIface.Callback, public void eventMatch(byte discoverySessionId, int peerId, byte[] addr, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndicationType, int rangingMeasurementInMm, byte[] scid, int peerCipherType, byte[] nonce, byte[] tag, - AwarePairingConfig pairingConfig) { + AwarePairingConfig pairingConfig, @Nullable List<OuiKeyedData> vendorData) { incrementCbCount(CB_EV_MATCH); mWifiAwareStateManager.onMatchNotification(discoverySessionId, peerId, addr, serviceSpecificInfo, matchFilter, rangingIndicationType, - rangingMeasurementInMm, scid, peerCipherType, nonce, tag, pairingConfig); + rangingMeasurementInMm, scid, peerCipherType, nonce, tag, pairingConfig, + vendorData); } @Override diff --git a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java index c75b0df4be..8d0e2ce51a 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java @@ -58,6 +58,7 @@ import com.android.server.wifi.BuildProperties; import com.android.server.wifi.Clock; import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.InterfaceConflictManager; +import com.android.server.wifi.RunnerHandler; import com.android.server.wifi.SystemBuildProperties; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiSettingsConfigStore; @@ -129,7 +130,9 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { mWifiPermissionsUtil = wifiPermissionsUtil; mStateManager = awareStateManager; mShellCommand = awareShellCommand; - mHandler = new Handler(handlerThread.getLooper()); + mHandler = new RunnerHandler(handlerThread.getLooper(), mContext.getResources() + .getInteger(R.integer.config_wifiConfigurationWifiRunnerThresholdInMs), + WifiInjector.getInstance().getWifiHandlerLocalLog()); mWifiAwareNativeManager = wifiAwareNativeManager; mWifiAwareNativeApi = wifiAwareNativeApi; mWifiAwareNativeCallback = wifiAwareNativeCallback; @@ -334,7 +337,22 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { } if (configRequest != null) { - enforceNetworkStackPermission(); + boolean networkStackPermission = checkNetworkStackPermission(); + boolean manageNetworkSelectionPermission = + mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid); + if (!(networkStackPermission || manageNetworkSelectionPermission)) { + throw new SecurityException("Insufficient permission to include a ConfigRequest"); + } + + if (!networkStackPermission) { + // OEM apps with only the network selection permission can provide a config request, + // but they should only modify the vendor data field. + ConfigRequest.Builder builder = new ConfigRequest.Builder(); + if (SdkLevel.isAtLeastV()) { + builder.setVendorData(configRequest.getVendorData()); + } + configRequest = builder.build(); + } } else { configRequest = new ConfigRequest.Builder().build(); } @@ -349,7 +367,7 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { } if (mVerboseLoggingEnabled) { - Log.v(TAG, "connect: uid=" + uid + ", clientId=" + clientId + ", configRequest" + Log.v(TAG, "connect: uid=" + uid + ", clientId=" + clientId + ", configRequest=" + configRequest + ", notifyOnIdentityChanged=" + notifyOnIdentityChanged); } @@ -832,4 +850,9 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { private void enforceNetworkStackPermission() { mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_STACK, TAG); } + + private boolean checkNetworkStackPermission() { + return mContext.checkCallingOrSelfPermission(Manifest.permission.NETWORK_STACK) + == PackageManager.PERMISSION_GRANTED; + } } diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java index 4c099d72c7..14a60547a1 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java @@ -68,6 +68,7 @@ import android.net.MacAddress; import android.net.wifi.IBooleanListener; import android.net.wifi.IIntegerListener; import android.net.wifi.IListListener; +import android.net.wifi.OuiKeyedData; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; @@ -107,7 +108,6 @@ import android.util.StatsEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.MessageUtils; -import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; import com.android.modules.utils.BasicShellCommandHandler; @@ -116,6 +116,7 @@ import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.Clock; import com.android.server.wifi.HalDeviceManager; import com.android.server.wifi.InterfaceConflictManager; +import com.android.server.wifi.RunnerState; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.aware.PairingConfigManager.PairingSecurityAssociationInfo; import com.android.server.wifi.hal.WifiNanIface.NanStatusCode; @@ -347,6 +348,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe private static final String MESSAGE_BUNDLE_KEY_BOOTSTRAPPING_IS_COME_BACK_REQUEST = "bootstrapping_is_come_back"; private static final String MESSAGE_BUNDLE_KEY_CALLER_TYPE = "caller_type"; + private static final String MESSAGE_BUNDLE_KEY_VENDOR_DATA = "vendor_data"; private WifiAwareNativeApi mWifiAwareNativeApi; private WifiAwareNativeManager mWifiAwareNativeManager; @@ -1065,7 +1067,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe listener.onResult(mPairingConfigManager .getAllPairedDevices(callingPackage)); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } } ); @@ -1099,7 +1101,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe try { listener.onResult(state.getConfigRequest().mMasterPreference); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -1131,7 +1133,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe try { listener.onResult(mOpportunisticSet.contains(ctxPkg)); } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, e.getMessage(), e); } }); } @@ -1938,7 +1940,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe public void onMatchNotification(int pubSubId, int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndication, int rangeMm, byte[] scid, int peerCipherSuite, byte[] nonce, byte[] tag, - AwarePairingConfig pairingConfig) { + AwarePairingConfig pairingConfig, @Nullable List<OuiKeyedData> vendorData) { Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); msg.arg1 = NOTIFICATION_TYPE_MATCH; msg.arg2 = pubSubId; @@ -1953,6 +1955,8 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_NONCE, nonce); msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_TAG, tag); msg.getData().putParcelable(MESSAGE_BUNDLE_KEY_PAIRING_CONFIG, pairingConfig); + msg.getData().putParcelableArrayList(MESSAGE_BUNDLE_KEY_VENDOR_DATA, + vendorData != null ? new ArrayList<>(vendorData) : new ArrayList<>()); mSm.sendMessage(msg); } @@ -2167,9 +2171,9 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe class WifiAwareStateMachine extends StateMachine { private static final int TRANSACTION_ID_IGNORE = 0; - private final DefaultState mDefaultState = new DefaultState(); - private final WaitState mWaitState = new WaitState(); - private final WaitForResponseState mWaitForResponseState = new WaitForResponseState(); + private final DefaultState mDefaultState; + private final WaitState mWaitState; + private final WaitForResponseState mWaitForResponseState; private final WaitingState mWaitingState = new WaitingState(this); private short mNextTransactionId = 1; @@ -2198,7 +2202,11 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe WifiAwareStateMachine(String name, Looper looper) { super(name, looper); - + final int threshold = mContext.getResources().getInteger( + R.integer.config_wifiConfigurationWifiRunnerThresholdInMs); + mDefaultState = new DefaultState(threshold); + mWaitState = new WaitState(threshold); + mWaitForResponseState = new WaitForResponseState(threshold); addState(mDefaultState); /* --> */ addState(mWaitState, mDefaultState); /* ----> */ addState(mWaitingState, mWaitState); @@ -2207,15 +2215,160 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe setInitialState(mWaitState); } + @Override + protected String getWhatToString(int what) { + return switch (what) { + case COMMAND_TYPE_CONNECT -> "COMMAND_TYPE_CONNECT"; + case COMMAND_TYPE_DISCONNECT -> "COMMAND_TYPE_DISCONNECT"; + case COMMAND_TYPE_TERMINATE_SESSION -> "COMMAND_TYPE_TERMINATE_SESSION"; + case COMMAND_TYPE_PUBLISH -> "COMMAND_TYPE_PUBLISH"; + case COMMAND_TYPE_UPDATE_PUBLISH -> "COMMAND_TYPE_UPDATE_PUBLISH"; + case COMMAND_TYPE_SUBSCRIBE -> "COMMAND_TYPE_SUBSCRIBE"; + case COMMAND_TYPE_UPDATE_SUBSCRIBE -> "COMMAND_TYPE_UPDATE_SUBSCRIBE"; + case COMMAND_TYPE_ENQUEUE_SEND_MESSAGE -> "COMMAND_TYPE_ENQUEUE_SEND_MESSAGE"; + case COMMAND_TYPE_ENABLE_USAGE -> "COMMAND_TYPE_ENABLE_USAGE"; + case COMMAND_TYPE_DISABLE_USAGE -> "COMMAND_TYPE_DISABLE_USAGE"; + case COMMAND_TYPE_GET_CAPABILITIES -> "COMMAND_TYPE_GET_CAPABILITIES"; + case COMMAND_TYPE_DELETE_ALL_DATA_PATH_INTERFACES + -> "COMMAND_TYPE_DELETE_ALL_DATA_PATH_INTERFACES"; + case COMMAND_TYPE_CREATE_DATA_PATH_INTERFACE + -> "COMMAND_TYPE_CREATE_DATA_PATH_INTERFACE"; + case COMMAND_TYPE_DELETE_DATA_PATH_INTERFACE + -> "COMMAND_TYPE_DELETE_DATA_PATH_INTERFACE"; + case COMMAND_TYPE_INITIATE_DATA_PATH_SETUP + -> "COMMAND_TYPE_INITIATE_DATA_PATH_SETUP"; + case COMMAND_TYPE_RESPOND_TO_DATA_PATH_SETUP_REQUEST + -> "COMMAND_TYPE_RESPOND_TO_DATA_PATH_SETUP_REQUEST"; + case COMMAND_TYPE_END_DATA_PATH -> "COMMAND_TYPE_END_DATA_PATH"; + case COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE -> "COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE"; + case COMMAND_TYPE_RECONFIGURE -> "COMMAND_TYPE_RECONFIGURE"; + case COMMAND_TYPE_DELAYED_INITIALIZATION -> "COMMAND_TYPE_DELAYED_INITIALIZATION"; + case COMMAND_TYPE_GET_AWARE -> "COMMAND_TYPE_GET_AWARE"; + case COMMAND_TYPE_RELEASE_AWARE -> "COMMAND_TYPE_RELEASE_AWARE"; + case COMMAND_TYPE_DISABLE -> "COMMAND_TYPE_DISABLE"; + case COMMAND_TYPE_INITIATE_PAIRING_REQUEST + -> "COMMAND_TYPE_INITIATE_PAIRING_REQUEST"; + case COMMAND_TYPE_RESPONSE_PAIRING_REQUEST + -> "COMMAND_TYPE_RESPONSE_PAIRING_REQUEST"; + case COMMAND_TYPE_INITIATE_BOOTSTRAPPING_REQUEST + -> "COMMAND_TYPE_INITIATE_BOOTSTRAPPING_REQUEST"; + case COMMAND_TYPE_RESPONSE_BOOTSTRAPPING_REQUEST + -> "COMMAND_TYPE_RESPONSE_BOOTSTRAPPING_REQUEST"; + case COMMAND_TYPE_SUSPEND_SESSION -> "COMMAND_TYPE_SUSPEND_SESSION"; + case COMMAND_TYPE_RESUME_SESSION -> "COMMAND_TYPE_RESUME_SESSION"; + case COMMAND_TYPE_END_PAIRING -> "COMMAND_TYPE_END_PAIRING"; + + case RESPONSE_TYPE_ON_CONFIG_SUCCESS -> "RESPONSE_TYPE_ON_CONFIG_SUCCESS"; + case RESPONSE_TYPE_ON_CONFIG_FAIL -> "RESPONSE_TYPE_ON_CONFIG_FAIL"; + case RESPONSE_TYPE_ON_SESSION_CONFIG_SUCCESS + -> "RESPONSE_TYPE_ON_SESSION_CONFIG_SUCCESS"; + case RESPONSE_TYPE_ON_SESSION_CONFIG_FAIL -> "RESPONSE_TYPE_ON_SESSION_CONFIG_FAIL"; + case RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_SUCCESS + -> "RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_SUCCESS"; + case RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_FAIL + -> "RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_FAIL"; + case RESPONSE_TYPE_ON_CAPABILITIES_UPDATED + -> "RESPONSE_TYPE_ON_CAPABILITIES_UPDATED"; + case RESPONSE_TYPE_ON_CREATE_INTERFACE -> "RESPONSE_TYPE_ON_CREATE_INTERFACE"; + case RESPONSE_TYPE_ON_DELETE_INTERFACE -> "RESPONSE_TYPE_ON_DELETE_INTERFACE"; + case RESPONSE_TYPE_ON_INITIATE_DATA_PATH_SUCCESS + -> "RESPONSE_TYPE_ON_INITIATE_DATA_PATH_SUCCESS"; + case RESPONSE_TYPE_ON_INITIATE_DATA_PATH_FAIL + -> "RESPONSE_TYPE_ON_INITIATE_DATA_PATH_FAIL"; + case RESPONSE_TYPE_ON_RESPOND_TO_DATA_PATH_SETUP_REQUEST + -> "RESPONSE_TYPE_ON_RESPOND_TO_DATA_PATH_SETUP_REQUEST"; + case RESPONSE_TYPE_ON_END_DATA_PATH -> "RESPONSE_TYPE_ON_END_DATA_PATH"; + case RESPONSE_TYPE_ON_DISABLE -> "RESPONSE_TYPE_ON_DISABLE"; + case RESPONSE_TYPE_ON_INITIATE_PAIRING_SUCCESS + -> "RESPONSE_TYPE_ON_INITIATE_PAIRING_SUCCESS"; + case RESPONSE_TYPE_ON_INITIATE_PAIRING_FAIL + -> "RESPONSE_TYPE_ON_INITIATE_PAIRING_FAIL"; + case RESPONSE_TYPE_ON_RESPONSE_PAIRING_SUCCESS + -> "RESPONSE_TYPE_ON_RESPONSE_PAIRING_SUCCESS"; + case RESPONSE_TYPE_ON_RESPONSE_PAIRING_FAIL + -> "RESPONSE_TYPE_ON_RESPONSE_PAIRING_FAIL"; + case RESPONSE_TYPE_ON_INITIATE_BOOTSTRAPPING_SUCCESS + -> "RESPONSE_TYPE_ON_INITIATE_BOOTSTRAPPING_SUCCESS"; + case RESPONSE_TYPE_ON_INITIATE_BOOTSTRAPPING_FAIL + -> "RESPONSE_TYPE_ON_INITIATE_BOOTSTRAPPING_FAIL"; + case RESPONSE_TYPE_ON_RESPONSE_BOOTSTRAPPING_SUCCESS + -> "RESPONSE_TYPE_ON_RESPONSE_BOOTSTRAPPING_SUCCESS"; + case RESPONSE_TYPE_ON_RESPONSE_BOOTSTRAPPING_FAIL + -> "RESPONSE_TYPE_ON_RESPONSE_BOOTSTRAPPING_FAIL"; + case RESPONSE_TYPE_ON_SUSPEND -> "RESPONSE_TYPE_ON_SUSPEND"; + case RESPONSE_TYPE_ON_RESUME -> "RESPONSE_TYPE_ON_RESUME"; + case RESPONSE_TYPE_ON_END_PAIRING -> "RESPONSE_TYPE_ON_END_PAIRING"; + + case NOTIFICATION_TYPE_INTERFACE_CHANGE -> "NOTIFICATION_TYPE_INTERFACE_CHANGE"; + case NOTIFICATION_TYPE_CLUSTER_CHANGE -> "NOTIFICATION_TYPE_CLUSTER_CHANGE"; + case NOTIFICATION_TYPE_MATCH -> "NOTIFICATION_TYPE_MATCH"; + case NOTIFICATION_TYPE_SESSION_TERMINATED -> "NOTIFICATION_TYPE_SESSION_TERMINATED"; + case NOTIFICATION_TYPE_MESSAGE_RECEIVED -> "NOTIFICATION_TYPE_MESSAGE_RECEIVED"; + case NOTIFICATION_TYPE_AWARE_DOWN -> "NOTIFICATION_TYPE_AWARE_DOWN"; + case NOTIFICATION_TYPE_ON_MESSAGE_SEND_SUCCESS + -> "NOTIFICATION_TYPE_ON_MESSAGE_SEND_SUCCESS"; + case NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL + -> "NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL"; + case NOTIFICATION_TYPE_ON_DATA_PATH_REQUEST + -> "NOTIFICATION_TYPE_ON_DATA_PATH_REQUEST"; + case NOTIFICATION_TYPE_ON_DATA_PATH_CONFIRM + -> "NOTIFICATION_TYPE_ON_DATA_PATH_CONFIRM"; + case NOTIFICATION_TYPE_ON_DATA_PATH_END -> "NOTIFICATION_TYPE_ON_DATA_PATH_END"; + case NOTIFICATION_TYPE_ON_DATA_PATH_SCHED_UPDATE + -> "NOTIFICATION_TYPE_ON_DATA_PATH_SCHED_UPDATE"; + case NOTIFICATION_TYPE_MATCH_EXPIRED -> "NOTIFICATION_TYPE_MATCH_EXPIRED"; + case NOTIFICATION_TYPE_ON_PAIRING_REQUEST -> "NOTIFICATION_TYPE_ON_PAIRING_REQUEST"; + case NOTIFICATION_TYPE_ON_PAIRING_CONFIRM -> "NOTIFICATION_TYPE_ON_PAIRING_CONFIRM"; + case NOTIFICATION_TYPE_ON_BOOTSTRAPPING_REQUEST + -> "NOTIFICATION_TYPE_ON_BOOTSTRAPPING_REQUEST"; + case NOTIFICATION_TYPE_ON_BOOTSTRAPPING_CONFIRM + -> "NOTIFICATION_TYPE_ON_BOOTSTRAPPING_CONFIRM"; + case NOTIFICATION_TYPE_ON_SUSPENSION_MODE_CHANGED + -> "NOTIFICATION_TYPE_ON_SUSPENSION_MODE_CHANGED"; + case RunnerState.STATE_ENTER_CMD -> "Enter"; + case RunnerState.STATE_EXIT_CMD -> "Exit"; + case MESSAGE_TYPE_COMMAND -> "MESSAGE_TYPE_COMMAND"; + case MESSAGE_TYPE_RESPONSE -> "MESSAGE_TYPE_RESPONSE"; + case MESSAGE_TYPE_NOTIFICATION -> "MESSAGE_TYPE_NOTIFICATION"; + case MESSAGE_TYPE_RESPONSE_TIMEOUT -> "MESSAGE_TYPE_RESPONSE_TIMEOUT"; + case MESSAGE_TYPE_SEND_MESSAGE_TIMEOUT -> "MESSAGE_TYPE_SEND_MESSAGE_TIMEOUT"; + case MESSAGE_TYPE_DATA_PATH_TIMEOUT -> "MESSAGE_TYPE_DATA_PATH_TIMEOUT"; + case MESSAGE_TYPE_PAIRING_TIMEOUT -> "MESSAGE_TYPE_PAIRING_TIMEOUT"; + case MESSAGE_TYPE_BOOTSTRAPPING_TIMEOUT -> "MESSAGE_TYPE_BOOTSTRAPPING_TIMEOUT"; + default -> { + Log.e(TAG, "unknown message what: " + what); + yield "what:" + what; + } + }; + } + public void onAwareDownCleanupSendQueueState() { mSendQueueBlocked = false; mHostQueuedSendMessages.clear(); mFwQueuedSendMessages.clear(); } - private class DefaultState extends State { + private class DefaultState extends RunnerState { + + DefaultState(int threshold) { + super(threshold, mWifiInjector.getWifiHandlerLocalLog()); + } + @Override - public boolean processMessage(Message msg) { + public String getMessageLogRec(int what) { + return WifiAwareStateManager.class.getSimpleName() + "." + + DefaultState.class.getSimpleName() + "." + getWhatToString(what); + } + + @Override + public void enterImpl() { + } + + @Override + public void exitImpl() { + } + @Override + public boolean processMessageImpl(Message msg) { if (mVdbg) { Log.v(TAG, getName() + msg.toString()); } @@ -2264,9 +2417,27 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe } } - private class WaitState extends State { + private class WaitState extends RunnerState { + + WaitState(int threshold) { + super(threshold, mWifiInjector.getWifiHandlerLocalLog()); + } + @Override - public boolean processMessage(Message msg) { + public String getMessageLogRec(int what) { + return WifiAwareStateManager.class.getSimpleName() + "." + + WaitState.class.getSimpleName() + "." + getWhatToString(what); + } + + @Override + public void enterImpl() { + } + + @Override + public void exitImpl() { + } + @Override + public boolean processMessageImpl(Message msg) { if (mVdbg) { Log.v(TAG, getName() + msg.toString()); } @@ -2295,12 +2466,22 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe } } - private class WaitForResponseState extends State { + private class WaitForResponseState extends RunnerState { private static final long AWARE_COMMAND_TIMEOUT = 5_000; private WakeupMessage mTimeoutMessage; + WaitForResponseState(int threshold) { + super(threshold, mWifiInjector.getWifiHandlerLocalLog()); + } + @Override - public void enter() { + public String getMessageLogRec(int what) { + return WifiAwareStateManager.class.getSimpleName() + "." + + WaitForResponseState.class.getSimpleName() + "." + getWhatToString(what); + } + + @Override + public void enterImpl() { mTimeoutMessage = new WakeupMessage(mContext, getHandler(), HAL_COMMAND_TIMEOUT_TAG, MESSAGE_TYPE_RESPONSE_TIMEOUT, mCurrentCommand.arg1, mCurrentTransactionId); mTimeoutMessage.schedule(SystemClock.elapsedRealtime() + AWARE_COMMAND_TIMEOUT); @@ -2308,12 +2489,12 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe } @Override - public void exit() { + public void exitImpl() { mTimeoutMessage.cancel(); } @Override - public boolean processMessage(Message msg) { + public boolean processMessageImpl(Message msg) { if (mVdbg) { Log.v(TAG, getName() + msg.toString()); } @@ -2392,10 +2573,12 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe byte[] tag = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_TAG); AwarePairingConfig pairingConfig = msg.getData() .getParcelable(MESSAGE_BUNDLE_KEY_PAIRING_CONFIG); + ArrayList<OuiKeyedData> vendorData = + msg.getData().getParcelableArrayList(MESSAGE_BUNDLE_KEY_VENDOR_DATA); onMatchLocal(pubSubId, requesterInstanceId, peerMac, serviceSpecificInfo, matchFilter, rangingIndication, rangeMm, cipherSuite, scid, nonce, tag, - pairingConfig); + pairingConfig, vendorData); break; } case NOTIFICATION_TYPE_MATCH_EXPIRED: { @@ -2834,8 +3017,10 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe int method = data.getInt(MESSAGE_BUNDLE_KEY_BOOTSTRAPPING_METHOD); byte[] cookie = data.getByteArray( MESSAGE_BUNDLE_KEY_BOOTSTRAPPING_COME_BACK_COOKIE); + boolean isComeBack = data + .getBoolean(MESSAGE_BUNDLE_KEY_BOOTSTRAPPING_IS_COME_BACK_REQUEST); waitForResponse = initiateBootstrappingRequestLocal(mCurrentTransactionId, - clientId, sessionId, peerId, method, cookie); + clientId, sessionId, peerId, method, cookie, isComeBack); break; } case COMMAND_TYPE_RESPONSE_BOOTSTRAPPING_REQUEST: { @@ -3963,7 +4148,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe } private boolean initiateBootstrappingRequestLocal(short transactionId, int clientId, - int sessionId, int peerId, int method, byte[] cookie) { + int sessionId, int peerId, int method, byte[] cookie, boolean isComeBack) { String methodString = "initiateBootstrappingRequestLocal"; if (mVdbg) { Log.v(TAG, methodString + ": transactionId=" + transactionId @@ -3974,7 +4159,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe if (session == null) { return false; } - return session.initiateBootstrapping(transactionId, peerId, method, cookie); + return session.initiateBootstrapping(transactionId, peerId, method, cookie, isComeBack); } private boolean respondToBootstrappingRequestLocal(short transactionId, int clientId, @@ -4950,7 +5135,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe private void onMatchLocal(int pubSubId, int requestorinstanceid, byte[] peerMac, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndication, int rangeMm, int cipherSuite, byte[] scid, byte[] nonce, byte[] tag, - AwarePairingConfig pairingConfig) { + AwarePairingConfig pairingConfig, @NonNull List<OuiKeyedData> vendorData) { if (mVerboseLoggingEnabled) { Log.v(TAG, "onMatch: pubSubId=" + pubSubId + ", requestorInstanceId=" + requestorinstanceid @@ -4974,7 +5159,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe data.first.getCallingPackage(), nonce, tag, peerMac); int peerId = data.second.onMatch(requestorinstanceid, peerMac, serviceSpecificInfo, matchFilter, rangingIndication, rangeMm, cipherSuite, scid, pairingAlias, - pairingConfig); + pairingConfig, vendorData); if (TextUtils.isEmpty(pairingAlias)) { return; } @@ -5287,6 +5472,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe int clusterHigh = ConfigRequest.CLUSTER_ID_MAX; int[] discoveryWindowInterval = {ConfigRequest.DW_INTERVAL_NOT_INIT, ConfigRequest.DW_INTERVAL_NOT_INIT}; + List<OuiKeyedData> vendorData = null; if (configRequest != null) { support5gBand = configRequest.mSupport5gBand; support6gBand = configRequest.mSupport6gBand; @@ -5338,6 +5524,10 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe cr.mDiscoveryWindowInterval[band]); } } + + if (SdkLevel.isAtLeastV() && !cr.getVendorData().isEmpty()) { + vendorData = cr.getVendorData(); + } } ConfigRequest.Builder builder = new ConfigRequest.Builder().setSupport5gBand(support5gBand) .setMasterPreference(masterPreference).setClusterLow(clusterLow) @@ -5347,6 +5537,16 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe builder.setDiscoveryWindowInterval(band, discoveryWindowInterval[band]); } } + if (SdkLevel.isAtLeastV()) { + // Always use the vendor data from the incoming ConfigRequest if provided. + // Otherwise, use the most recent vendor data in the mClients list. + if (configRequest != null && !configRequest.getVendorData().isEmpty()) { + vendorData = configRequest.getVendorData(); + } + if (vendorData != null) { + builder.setVendorData(vendorData); + } + } return builder.build(); } diff --git a/service/java/com/android/server/wifi/b2b/WifiRoamingModeManager.java b/service/java/com/android/server/wifi/b2b/WifiRoamingModeManager.java new file mode 100644 index 0000000000..acbefb4305 --- /dev/null +++ b/service/java/com/android/server/wifi/b2b/WifiRoamingModeManager.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2024 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.b2b; + +import android.hardware.wifi.WifiStatusCode; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiSsid; +import android.util.Log; + +import com.android.server.wifi.ActiveModeWarden; +import com.android.server.wifi.WifiNative; +import com.android.server.wifi.WifiRoamingConfigStore; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Map; + +public class WifiRoamingModeManager { + private static final String TAG = "WifiRoamingModeManager"; + private final WifiNative mWifiNative; + private final WifiRoamingConfigStore mWifiRoamingConfigStore; + private final ActiveModeWarden mActiveModeWarden; + private boolean mVerboseLoggingEnabled = false; + + public WifiRoamingModeManager(WifiNative wifiNative, + ActiveModeWarden activeModeWarden, + WifiRoamingConfigStore wifiRoamingConfigStore) { + this.mWifiNative = wifiNative; + this.mWifiRoamingConfigStore = wifiRoamingConfigStore; + this.mActiveModeWarden = activeModeWarden; + } + + /** + * To handle policy updates when device is already in connected state + * and also when policy get removed in connected state. + */ + private void checkAndUpdatePolicy(String updatedSsid) { + String currentSsid = mActiveModeWarden.getConnectionInfo().getSSID(); + if (!updatedSsid.equals(currentSsid)) return; + String ifaceName = mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(); + if (currentSsid != null && ifaceName != null) { + if (mVerboseLoggingEnabled) { + Log.i(TAG, "Re-applying roaming policy as it updated"); + } + applyWifiRoamingMode(ifaceName, currentSsid); + } + } + + /** + * Add a new network roaming policy. + * + * @param ssid name of the network on which policy is to be added. + * @param roamingMode denotes roaming mode value configured. + * @param isDeviceOwner flag denoting whether API is called by the device owner. + */ + public void setPerSsidRoamingMode(WifiSsid ssid, @WifiManager.RoamingMode int roamingMode, + boolean isDeviceOwner) { + mWifiRoamingConfigStore.addRoamingMode(ssid.toString(), roamingMode, isDeviceOwner); + checkAndUpdatePolicy(ssid.toString()); + } + + /** + * Remove the network roaming policy for the given ssid. + * + * @param ssid name of the network on which policy is to be removed. + * @param isDeviceOwner flag denoting whether API is called by the device owner. + */ + public void removePerSsidRoamingMode(WifiSsid ssid, boolean isDeviceOwner) { + mWifiRoamingConfigStore.removeRoamingMode(ssid.toString(), isDeviceOwner); + checkAndUpdatePolicy(ssid.toString()); + } + + /** + * Get all the network roaming policies configured. + * + * @param isDeviceOwner flag denoting whether API is called by the device owner. + * @return Map of corresponding policies for the API caller, + * where key is ssid and value is roaming mode/policy configured for that ssid. + */ + public Map<String, Integer> getPerSsidRoamingModes(boolean isDeviceOwner) { + return mWifiRoamingConfigStore.getPerSsidRoamingModes(isDeviceOwner); + } + + /** + * Apply roaming policy to the provided network. + * If policy does not exist, apply normal roaming policy. + * + * @param iface represents the name of the wifi interface. + * @param ssid represents the name of the network. + */ + public void applyWifiRoamingMode(String iface, String ssid) { + int roamingMode = mWifiRoamingConfigStore.getRoamingMode(ssid); + if (mVerboseLoggingEnabled) { + Log.i(TAG, "Applying roaming policy for network " + + ssid + " with value " + roamingMode); + } + @WifiStatusCode int errorCode = mWifiNative.setRoamingMode(iface, roamingMode); + switch (errorCode) { + case WifiStatusCode.SUCCESS: + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Roaming mode value successfully set to: " + roamingMode); + } + break; + case WifiStatusCode.ERROR_NOT_STARTED: + Log.e(TAG, "Failed to set roaming mode as WifiStaIfaceAidlImpl" + + " instance is not created."); + break; + case WifiStatusCode.ERROR_WIFI_IFACE_INVALID: + Log.e(TAG, "Failed to set roaming mode as interface is invalid."); + break; + case WifiStatusCode.ERROR_INVALID_ARGS: + Log.e(TAG, "Failed to set roaming mode due to invalid parameter " + + roamingMode); + break; + default: + Log.e(TAG, "Failed to set roaming mode due to unknown error."); + } + } + + /** + * Enable verbose logging. + */ + public void enableVerboseLogging(boolean verboseEnabled) { + mVerboseLoggingEnabled = verboseEnabled; + } + + /** + * Dump roaming policies for debugging. + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mWifiRoamingConfigStore.dump(fd, pw, args); + } +} diff --git a/service/java/com/android/server/wifi/hal/IWifiNanIface.java b/service/java/com/android/server/wifi/hal/IWifiNanIface.java index a975b9e3a5..3e0f544f19 100644 --- a/service/java/com/android/server/wifi/hal/IWifiNanIface.java +++ b/service/java/com/android/server/wifi/hal/IWifiNanIface.java @@ -276,21 +276,26 @@ public interface IWifiNanIface { * match indication). * @param peer The MAC address of the peer to create a connection with. * @param method the proposed bootstrapping method + * @param pubSubId ID of the publish/subscribe session - obtained when creating a session. + * @param isComeBack If the request is for a previous comeback response * @return True if the request send succeed. */ boolean initiateNanBootstrappingRequest(short transactionId, int peerId, MacAddress peer, - int method, byte[] cookie); + int method, byte[] cookie, byte pubSubId, boolean isComeBack); /** * Respond to a bootstrapping request - * @param transactionId Transaction ID for the transaction - used in the - * async callback to match with the original request. + * + * @param transactionId Transaction ID for the transaction - used in the + * async callback to match with the original request. * @param bootstrappingId the id of this bootstrapping session - * @param accept True if the proposed bootstrapping method is accepted. + * @param accept True if the proposed bootstrapping method is accepted. + * @param pubSubId ID of the publish/subscribe session - obtained when creating a + * session. * @return True if the request send succeed. */ boolean respondToNanBootstrappingRequest(short transactionId, int bootstrappingId, - boolean accept); + boolean accept, byte pubSubId); /** * Suspend the specified Aware session. During the suspend state, the Wi-Fi Aware device diff --git a/service/java/com/android/server/wifi/hal/IWifiStaIface.java b/service/java/com/android/server/wifi/hal/IWifiStaIface.java index da06ef7a9f..3e4078531a 100644 --- a/service/java/com/android/server/wifi/hal/IWifiStaIface.java +++ b/service/java/com/android/server/wifi/hal/IWifiStaIface.java @@ -17,8 +17,13 @@ package com.android.server.wifi.hal; import android.annotation.Nullable; +import android.hardware.wifi.WifiStatusCode; import android.net.MacAddress; import android.net.apf.ApfCapabilities; +import android.net.wifi.WifiManager.RoamingMode; +import android.net.wifi.WifiScanner; +import android.net.wifi.twt.TwtRequest; +import android.os.Bundle; import com.android.server.wifi.WifiLinkLayerStats; import com.android.server.wifi.WifiLoggerHal; @@ -123,6 +128,14 @@ public interface IWifiStaIface { MacAddress getFactoryMacAddress(); /** + * Retrieve the cached scan data. + * + * @return Instance of {@link ScanData}, or null on error. + */ + @Nullable + WifiScanner.ScanData getCachedScanData(); + + /** * Retrieve the latest link layer stats. * Note: will fail if link layer stats collection has not been explicitly enabled. * @@ -256,4 +269,54 @@ public interface IWifiStaIface { * @return true if successful, false otherwise. */ boolean setDtimMultiplier(int multiplier); + + /** + * Set the roaming mode. + * + * @param roamingMode {@link android.net.wifi.WifiManager.RoamingMode}. + * @return {@link WifiStatusCode#SUCCESS} if success, otherwise error code. + */ + @WifiStatusCode int setRoamingMode(@RoamingMode int roamingMode); + + /** + * Get target wake time (TWT) capabilities. + * + * @return TWT capabilities as Bundle + */ + default Bundle getTwtCapabilities() { + return null; + } + + /** + * Set up a TWT session + * + * @param cmdId Command ID to use for this invocation. + * @param twtRequest TWT request configuration to setup TWT session + * @return true if successful, false otherwise. + */ + default boolean setupTwtSession(int cmdId, TwtRequest twtRequest) { + return false; + } + + /** + * Teardown a TWT session. + * + * @param cmdId Command ID to use for this invocation. + * @param sessionId TWT session identifier + * @return true if successful, false otherwise. + */ + default boolean tearDownTwtSession(int cmdId, int sessionId) { + return false; + } + + /** + * Get stats for the TWT session. + * + * @param cmdId Command ID to use for this invocation. + * @param sessionId TWT session identifier + * @return true if successful, false otherwise. + */ + default boolean getStatsTwtSession(int cmdId, int sessionId) { + return false; + } } diff --git a/service/java/com/android/server/wifi/hal/WifiNanIface.java b/service/java/com/android/server/wifi/hal/WifiNanIface.java index 62541c90ee..9fcf9e2038 100644 --- a/service/java/com/android/server/wifi/hal/WifiNanIface.java +++ b/service/java/com/android/server/wifi/hal/WifiNanIface.java @@ -19,6 +19,7 @@ package com.android.server.wifi.hal; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; import android.net.wifi.aware.AwarePairingConfig; import android.net.wifi.aware.ConfigRequest; import android.net.wifi.aware.PublishConfig; @@ -513,22 +514,22 @@ public class WifiNanIface implements WifiHal.WifiInterface { cipherSuite)); } /** - * {@link IWifiNanIface#initiateNanBootstrappingRequest(short, int, MacAddress, int, byte[])} + * {@link IWifiNanIface#initiateNanBootstrappingRequest(short, int, MacAddress, int, byte[], byte, boolean)} */ public boolean initiateBootstrapping(short transactionId, int peerId, MacAddress peer, - int method, byte[] cookie) { + int method, byte[] cookie, byte pubSubId, boolean isComeBack) { return validateAndCall("initiateBootstrapping", false, () -> mWifiNanIface.initiateNanBootstrappingRequest(transactionId, peerId, peer, - method, cookie)); + method, cookie, pubSubId, isComeBack)); } /** - * {@link IWifiNanIface#respondToNanBootstrappingRequest(short, int, boolean)} + * {@link IWifiNanIface#respondToNanBootstrappingRequest(short, int, boolean, byte)} */ public boolean respondToBootstrappingRequest(short transactionId, int bootstrappingId, - boolean accept) { + boolean accept, byte pubSubId) { return validateAndCall("initiateBootstrapping", false, () -> mWifiNanIface.respondToNanBootstrappingRequest(transactionId, bootstrappingId, - accept)); + accept, pubSubId)); } /** @@ -741,11 +742,13 @@ public class WifiNanIface implements WifiHal.WifiInterface { * identifying the PMK used for setting up the Secure Data Path. * @param peerCipherType Cipher type for data-paths constructed in the context of this * discovery session. + * @param vendorData Additional vendor-specific parameters, or null if not provided. */ void eventMatch(byte discoverySessionId, int peerId, byte[] addr, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndicationType, int rangingMeasurementInMm, byte[] scid, int peerCipherType, byte[] nonce, - byte[] tag, AwarePairingConfig pairingConfig); + byte[] tag, AwarePairingConfig pairingConfig, + @Nullable List<OuiKeyedData> vendorData); /** * Indicates that a previously discovered match (service) has expired. diff --git a/service/java/com/android/server/wifi/hal/WifiNanIfaceAidlImpl.java b/service/java/com/android/server/wifi/hal/WifiNanIfaceAidlImpl.java index 0f10214a34..2b5a7da08a 100644 --- a/service/java/com/android/server/wifi/hal/WifiNanIfaceAidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiNanIfaceAidlImpl.java @@ -65,6 +65,7 @@ import android.util.Log; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.aware.Capabilities; +import com.android.server.wifi.util.HalAidlUtil; import java.nio.charset.StandardCharsets; @@ -173,7 +174,7 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { /** * See comments for {@link IWifiNanIface#enableAndConfigure(short, ConfigRequest, boolean, - * boolean, boolean, boolean, int, int, WifiNanIface.PowerParameters)} + * boolean, boolean, boolean, int, int, int, WifiNanIface.PowerParameters)} */ @Override public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest, @@ -512,10 +513,10 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { @Override public boolean initiateNanBootstrappingRequest(short transactionId, int peerId, MacAddress peer, - int method, byte[] cookie) { + int method, byte[] cookie, byte pubSubId, boolean isComeBack) { String methodStr = "initiateNanBootstrappingRequest"; NanBootstrappingRequest request = createNanBootstrappingRequest(peerId, peer, method, - cookie); + cookie, pubSubId, isComeBack); synchronized (mLock) { try { if (!checkIfaceAndLogFailure(methodStr)) return false; @@ -532,9 +533,10 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { @Override public boolean respondToNanBootstrappingRequest(short transactionId, int bootstrappingId, - boolean accept) { + boolean accept, byte pubSubId) { String methodStr = "respondToNanBootstrappingRequest"; - NanBootstrappingResponse request = createNanBootstrappingResponse(bootstrappingId, accept); + NanBootstrappingResponse request = createNanBootstrappingResponse(bootstrappingId, accept, + pubSubId); synchronized (mLock) { try { if (!checkIfaceAndLogFailure(methodStr)) return false; @@ -587,20 +589,23 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { // Utilities private static NanBootstrappingResponse createNanBootstrappingResponse(int bootstrappingId, - boolean accept) { + boolean accept, byte pubSubId) { NanBootstrappingResponse request = new NanBootstrappingResponse(); request.acceptRequest = accept; request.bootstrappingInstanceId = bootstrappingId; + request.discoverySessionId = pubSubId; return request; } private static NanBootstrappingRequest createNanBootstrappingRequest(int peerId, - MacAddress peer, int method, byte[] cookie) { + MacAddress peer, int method, byte[] cookie, byte pubSubId, boolean isComeBack) { NanBootstrappingRequest request = new NanBootstrappingRequest(); request.peerId = peerId; request.peerDiscMacAddr = peer.toByteArray(); request.requestBootstrappingMethod = method; request.cookie = copyArray(cookie); + request.discoverySessionId = pubSubId; + request.isComeback = isComeBack; return request; } @@ -727,6 +732,7 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_6GHZ] = true; updateConfigForPowerSettings(req.configParams, configSupplemental, powerParameters); + updateConfigRequestVendorData(req.configParams, configRequest); return req; } @@ -754,6 +760,7 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = nanBandSpecificConfigs[1]; req.bandSpecificConfig[NanBandIndex.NAN_BAND_6GHZ] = nanBandSpecificConfigs[2]; updateConfigForPowerSettings(req, configSupplemental, powerParameters); + updateConfigRequestVendorData(req, configRequest); return req; } @@ -785,6 +792,15 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { } } + private static void updateConfigRequestVendorData( + NanConfigRequest halReq, ConfigRequest frameworkReq) { + if (SdkLevel.isAtLeastV() && WifiHalAidlImpl.isServiceVersionAtLeast(2) + && !frameworkReq.getVendorData().isEmpty()) { + halReq.vendorData = + HalAidlUtil.frameworkToHalOuiKeyedDataList(frameworkReq.getVendorData()); + } + } + private static NanPublishRequest createNanPublishRequest( byte publishId, PublishConfig publishConfig, byte[] nik) { NanPublishRequest req = new NanPublishRequest(); @@ -852,6 +868,12 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { req.txType = NanTxType.BROADCAST; req.pairingConfig = createAidlPairingConfig(publishConfig.getPairingConfig()); req.identityKey = copyArray(nik, 16); + + if (SdkLevel.isAtLeastV() && !publishConfig.getVendorData().isEmpty()) { + req.vendorData = + HalAidlUtil.frameworkToHalOuiKeyedDataList(publishConfig.getVendorData()); + } + return req; } @@ -915,6 +937,12 @@ public class WifiNanIfaceAidlImpl implements IWifiNanIface { req.pairingConfig = createAidlPairingConfig(subscribeConfig.getPairingConfig()); req.identityKey = copyArray(nik, 16); req.intfAddr = new android.hardware.wifi.MacAddress[0]; + + if (SdkLevel.isAtLeastV() && !subscribeConfig.getVendorData().isEmpty()) { + req.vendorData = + HalAidlUtil.frameworkToHalOuiKeyedDataList(subscribeConfig.getVendorData()); + } + return req; } diff --git a/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackAidlImpl.java b/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackAidlImpl.java index 648b344b93..bb1a2e1bf2 100644 --- a/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackAidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackAidlImpl.java @@ -47,10 +47,8 @@ import android.hardware.wifi.NanStatus; import android.hardware.wifi.NanStatusCode; import android.hardware.wifi.NanSuspensionModeChangeInd; import android.hardware.wifi.NpkSecurityAssociation; -import android.hardware.wifi.WifiChannelWidthInMhz; import android.net.MacAddress; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiAnnotations; +import android.net.wifi.OuiKeyedData; import android.net.wifi.aware.AwarePairingConfig; import android.net.wifi.aware.Characteristics; import android.net.wifi.aware.WifiAwareChannelInfo; @@ -61,6 +59,7 @@ import com.android.server.wifi.aware.Capabilities; import com.android.server.wifi.aware.PairingConfigManager.PairingSecurityAssociationInfo; import com.android.server.wifi.hal.WifiNanIface.NanClusterEventType; import com.android.server.wifi.hal.WifiNanIface.NanRangingIndication; +import com.android.server.wifi.util.HalAidlUtil; import java.util.ArrayList; import java.util.Arrays; @@ -399,6 +398,10 @@ public class WifiNanIfaceCallbackAidlImpl extends IWifiNanIfaceEventCallback.Stu serviceSpecificInfo = event.extendedServiceSpecificInfo; isExtendedServiceSpecificInfo = true; } + List<OuiKeyedData> vendorData = null; + if (WifiHalAidlImpl.isServiceVersionAtLeast(2) && event.vendorData != null) { + vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList(event.vendorData); + } if (mVerboseLoggingEnabled) { Log.v( TAG, @@ -440,7 +443,8 @@ public class WifiNanIfaceCallbackAidlImpl extends IWifiNanIfaceEventCallback.Stu toPublicDataPathCipherSuites(event.peerCipherType), event.peerNira.nonce, event.peerNira.tag, - createPublicPairingConfig(event.peerPairingConfig)); + createPublicPairingConfig(event.peerPairingConfig), + vendorData); } private AwarePairingConfig createPublicPairingConfig(NanPairingConfig nativePairingConfig) { @@ -773,26 +777,6 @@ public class WifiNanIfaceCallbackAidlImpl extends IWifiNanIfaceEventCallback.Stu return sb.toString(); } - /** - * Convert HAL channelBandwidth to framework enum - */ - @WifiAnnotations.ChannelWidth - private int getChannelBandwidthFromHal(int channelBandwidth) { - switch (channelBandwidth) { - case WifiChannelWidthInMhz.WIDTH_40: - return ScanResult.CHANNEL_WIDTH_40MHZ; - case WifiChannelWidthInMhz.WIDTH_80: - return ScanResult.CHANNEL_WIDTH_80MHZ; - case WifiChannelWidthInMhz.WIDTH_160: - return ScanResult.CHANNEL_WIDTH_160MHZ; - case WifiChannelWidthInMhz.WIDTH_80P80: - return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ; - case WifiChannelWidthInMhz.WIDTH_320: - return ScanResult.CHANNEL_WIDTH_320MHZ; - default: - return ScanResult.CHANNEL_WIDTH_20MHZ; - } - } /** * Convert HAL NanDataPathChannelInfo to WifiAwareChannelInfo @@ -805,7 +789,7 @@ public class WifiNanIfaceCallbackAidlImpl extends IWifiNanIfaceEventCallback.Stu } for (android.hardware.wifi.NanDataPathChannelInfo channelInfo : channelInfos) { wifiAwareChannelInfos.add(new WifiAwareChannelInfo(channelInfo.channelFreq, - getChannelBandwidthFromHal(channelInfo.channelBandwidth), + HalAidlUtil.getChannelBandwidthFromHal(channelInfo.channelBandwidth), channelInfo.numSpatialStreams)); } return wifiAwareChannelInfos; diff --git a/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackHidlImpl.java b/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackHidlImpl.java index 2d2dc28760..800362a760 100644 --- a/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackHidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiNanIfaceCallbackHidlImpl.java @@ -343,7 +343,7 @@ public class WifiNanIfaceCallbackHidlImpl extends IWifiNanIfaceEventCallback.Stu event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo), convertArrayListToNativeByteArray(event.matchFilter), NanRangingIndication.fromHidl(event.rangingIndicationType), - event.rangingMeasurementInCm * 10, new byte[0], 0, null, null, null); + event.rangingMeasurementInCm * 10, new byte[0], 0, null, null, null, null); } @Override @@ -368,7 +368,7 @@ public class WifiNanIfaceCallbackHidlImpl extends IWifiNanIfaceEventCallback.Stu convertArrayListToNativeByteArray(event.matchFilter), NanRangingIndication.fromHidl(event.rangingIndicationType), event.rangingMeasurementInMm, convertArrayListToNativeByteArray(event.scid), - toPublicCipherSuites(event.peerCipherType), null, null, null); + toPublicCipherSuites(event.peerCipherType), null, null, null, null); } @Override diff --git a/service/java/com/android/server/wifi/hal/WifiNanIfaceHidlImpl.java b/service/java/com/android/server/wifi/hal/WifiNanIfaceHidlImpl.java index 038fc1775d..c5b9776fbe 100644 --- a/service/java/com/android/server/wifi/hal/WifiNanIfaceHidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiNanIfaceHidlImpl.java @@ -259,13 +259,13 @@ public class WifiNanIfaceHidlImpl implements IWifiNanIface { @Override public boolean initiateNanBootstrappingRequest(short transactionId, int peerId, MacAddress peer, - int method, byte[] cookie) { + int method, byte[] cookie, byte pubSubId, boolean isComeBack) { return false; } @Override public boolean respondToNanBootstrappingRequest(short transactionId, int bootstrappingId, - boolean accept) { + boolean accept, byte pubSubId) { return false; } diff --git a/service/java/com/android/server/wifi/hal/WifiRttController.java b/service/java/com/android/server/wifi/hal/WifiRttController.java index 2a0f7a6281..9061a01515 100644 --- a/service/java/com/android/server/wifi/hal/WifiRttController.java +++ b/service/java/com/android/server/wifi/hal/WifiRttController.java @@ -108,6 +108,14 @@ public class WifiRttController { public byte mcVersion; // Whether ftm rtt data collection is supported. public boolean rttFtmSupported; + // IEEE 802.11az preamble supported, see bit mask definition above. + public int azPreambleSupported; + // IEE 802.11az RTT bandwidth supported. + public int azBwSupported; + // Whether IEEE 802.11az Non-Trigger-based (non-TB) responder mode is supported. + public boolean ntbInitiatorSupported; + // Whether IEEE 802.11az Non-Trigger-based (non-TB) responder mode is supported. + public boolean ntbResponderSupported; public Capabilities() { } @@ -154,6 +162,10 @@ public class WifiRttController { mcVersion = rttHalCapabilities.mcVersion; bwSupported = rttHalCapabilities.bwSupport; rttFtmSupported = rttHalCapabilities.rttFtmSupported; + azPreambleSupported = rttHalCapabilities.azPreambleSupport; + azBwSupported = rttHalCapabilities.azBwSupport; + ntbInitiatorSupported = rttHalCapabilities.ntbInitiatorSupported; + ntbResponderSupported = rttHalCapabilities.ntbResponderSupported; } } diff --git a/service/java/com/android/server/wifi/hal/WifiRttControllerAidlImpl.java b/service/java/com/android/server/wifi/hal/WifiRttControllerAidlImpl.java index 1201a84a14..9c10ee0937 100644 --- a/service/java/com/android/server/wifi/hal/WifiRttControllerAidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiRttControllerAidlImpl.java @@ -29,7 +29,10 @@ import android.hardware.wifi.RttStatus; import android.hardware.wifi.RttType; import android.hardware.wifi.WifiChannelInfo; import android.hardware.wifi.WifiChannelWidthInMhz; +import android.hardware.wifi.common.OuiKeyedData; import android.net.MacAddress; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiAnnotations; import android.net.wifi.rtt.RangingRequest; import android.net.wifi.rtt.RangingResult; import android.net.wifi.rtt.ResponderConfig; @@ -38,6 +41,9 @@ import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Log; +import com.android.modules.utils.build.SdkLevel; +import com.android.server.wifi.util.HalAidlUtil; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; @@ -269,19 +275,57 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { } rttResult.distanceSdInMm = 0; } - rangingResults.add(new RangingResult( - halToFrameworkRttStatus(rttResult.status), - MacAddress.fromBytes(rttResult.addr), - rttResult.distanceInMm, rttResult.distanceSdInMm, - rttResult.rssi / -2, rttResult.numberPerBurstPeer, - rttResult.successNumber, lci, lcr, responderLocation, - rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS, - rttResult.type == RttType.TWO_SIDED, rttResult.channelFreqMHz, - rttResult.packetBw)); + RangingResult.Builder resultBuilder = new RangingResult.Builder() + .setStatus(halToFrameworkRttStatus(rttResult.status)) + .setMacAddress(MacAddress.fromBytes(rttResult.addr)) + .setDistanceMm(rttResult.distanceInMm) + .setDistanceStdDevMm(rttResult.distanceSdInMm) + .setRssi(rttResult.rssi / -2) + .setNumAttemptedMeasurements(rttResult.numberPerBurstPeer) + .setNumSuccessfulMeasurements(rttResult.successNumber) + .setLci(lci) + .setLcr(lcr) + .setUnverifiedResponderLocation(responderLocation) + .setRangingTimestampMillis( + rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS) + .set80211mcMeasurement(rttResult.type == RttType.TWO_SIDED_11MC) + .setMeasurementChannelFrequencyMHz(rttResult.channelFreqMHz) + .setMeasurementBandwidth(halToFrameworkChannelBandwidth(rttResult.packetBw)) + .set80211azNtbMeasurement(rttResult.type == RttType.TWO_SIDED_11AZ_NTB) + .setMinTimeBetweenNtbMeasurementsMicros(rttResult.ntbMinMeasurementTime) + .setMaxTimeBetweenNtbMeasurementsMicros(rttResult.ntbMaxMeasurementTime) + .set80211azInitiatorTxLtfRepetitionsCount(rttResult.i2rTxLtfRepetitionCount) + .set80211azResponderTxLtfRepetitionsCount(rttResult.r2iTxLtfRepetitionCount) + .set80211azNumberOfTxSpatialStreams(rttResult.numTxSpatialStreams) + .set80211azNumberOfRxSpatialStreams(rttResult.numRxSpatialStreams); + if (SdkLevel.isAtLeastV() && WifiHalAidlImpl.isServiceVersionAtLeast(2) + && rttResult.vendorData != null) { + resultBuilder.setVendorData( + HalAidlUtil.halToFrameworkOuiKeyedDataList(rttResult.vendorData)); + } + rangingResults.add(resultBuilder.build()); } return rangingResults; } + private static @WifiAnnotations.ChannelWidth int halToFrameworkChannelBandwidth( + @RttBw int packetBw) { + switch (packetBw) { + case RttBw.BW_20MHZ: + return ScanResult.CHANNEL_WIDTH_20MHZ; + case RttBw.BW_40MHZ: + return ScanResult.CHANNEL_WIDTH_40MHZ; + case RttBw.BW_80MHZ: + return ScanResult.CHANNEL_WIDTH_80MHZ; + case RttBw.BW_160MHZ: + return ScanResult.CHANNEL_WIDTH_160MHZ; + case RttBw.BW_320MHZ: + return ScanResult.CHANNEL_WIDTH_320MHZ; + default: + return RangingResult.UNSPECIFIED; + } + } + private static @WifiRttController.FrameworkRttStatus int halToFrameworkRttStatus( int halStatus) { switch (halStatus) { @@ -343,6 +387,53 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { } } + /** + * Get optimum burst duration corresponding to a burst size. + * + * IEEE 802.11 spec, Section 11.21.6.3 Fine timing measurement procedure negotiation, burst + * duration is defined as + * + * Burst duration = (N_FTMPB * (K + 1)) – 1) * T_MDFTM + T_FTM + aSIFSTime + T_Ack, where + * - N_FTMPB is the value of the FTMs Per Burst subfield + * - K is the maximum number of Fine Timing Measurement frame retransmissions the + * responding STA might attempt + * - T_MDFTM is the duration indicated by the Min Delta FTM subfield of the Fine Timing + * Measurement Parameters field of the initial Fine Timing Measurement frame (FTM_1) + * - T_FTM is the duration of the initial Fine Timing Measurement frame if the FTMs Per Burst + * subfield of the Fine Timing Measurement Parameters field of FTM_1 is set to 1, + * and the duration of the non-initial Fine Timing Measurement frame otherwise + * T_Ack is the duration of the Ack frame expected as a response + * + * Since many of the parameters are dependent on the chip and the vendor software, framework is + * doing a simple conversion with experimented values. Vendor Software may override the burst + * duration with more optimal values. + * + * Section '9.4.2.167 Fine Timing Measurement Parameters element' defines Burst Duration + * subfield encoding as, + * +--------------------+ + * |Value| Represents | + * +--------------------+ + * | 0-1 | Reserved | + * | 2 | 250 us | + * | 3 | 500 us | + * | 4 | 1 ms | + * | 5 | 2 ms | + * | 6 | 4 ms | + * | 7 | 8 ms | + * | 8 | 16 ms | + * | 9 | 32 ms | + * | 10 | 64 ms | + * | 11 | 128 ms | + * |12-14| Reserved | + * | 15 | No Preference| + * +-----+--------------+ + */ + private static int getOptimumBurstDuration(int burstSize) { + if (burstSize <= 8) return 9; // 32 ms + if (burstSize <= 24) return 10; // 64 ms + return 11; // 128 ms + } + private static RttConfig[] convertRangingRequestToRttConfigs(RangingRequest request, WifiRttController.Capabilities cap) { ArrayList<RttConfig> rttConfigs = new ArrayList<>(); @@ -353,11 +444,32 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { RttConfig config = new RttConfig(); config.addr = responder.macAddress.toByteArray(); + OuiKeyedData[] vendorData = null; + if (SdkLevel.isAtLeastV() && request.getVendorData() != null + && !request.getVendorData().isEmpty()) { + vendorData = HalAidlUtil.frameworkToHalOuiKeyedDataList(request.getVendorData()); + } + try { - config.type = responder.supports80211mc ? RttType.TWO_SIDED : RttType.ONE_SIDED; - if (config.type == RttType.ONE_SIDED && cap != null && !cap.oneSidedRttSupported) { - Log.w(TAG, "Device does not support one-sided RTT"); - continue; + if (cap != null) { + if (responder.supports80211azNtb && cap.ntbInitiatorSupported) { + config.type = RttType.TWO_SIDED_11AZ_NTB; + } else if (responder.supports80211mc) { + // IEEE 802.11mc is supported by the device + config.type = RttType.TWO_SIDED_11MC; + } else if (cap.oneSidedRttSupported) { + config.type = RttType.ONE_SIDED; + } else { + Log.w(TAG, "Device does not support one-sided RTT"); + continue; + } + } else { + if (responder.supports80211mc) { + // IEEE 802.11mc is supported by the device + config.type = RttType.TWO_SIDED_11MC; + } else { + config.type = RttType.ONE_SIDED; + } } config.peer = frameworkToHalRttPeerType(responder.responderType); @@ -369,7 +481,16 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { config.channel.centerFreq1 = responder.centerFreq1; config.bw = frameworkToHalChannelBandwidth(responder.channelWidth); config.preamble = frameworkToHalResponderPreamble(responder.preamble); + if (WifiHalAidlImpl.isServiceVersionAtLeast(2) && vendorData != null) { + config.vendorData = vendorData; + } validateBwAndPreambleCombination(config.bw, config.preamble); + // ResponderConfig#ntbMaxMeasurementTime is in units of 10 milliseconds + config.ntbMaxMeasurementTime = + responder.getNtbMaxTimeBetweenMeasurementsMicros() / 10000; + // ResponderConfig#ntbMinMeasurementTime is in units of 100 microseconds + config.ntbMinMeasurementTime = + responder.getNtbMinTimeBetweenMeasurementsMicros() / 100; if (config.peer == RttPeerType.NAN_TYPE) { config.mustRequestLci = false; @@ -379,7 +500,7 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { config.numFramesPerBurst = request.mRttBurstSize; config.numRetriesPerRttFrame = 0; // irrelevant for 2-sided RTT config.numRetriesPerFtmr = 3; - config.burstDuration = 9; + config.burstDuration = getOptimumBurstDuration(request.mRttBurstSize); } else { // AP + all non-NAN requests config.mustRequestLci = true; config.mustRequestLcr = true; @@ -388,13 +509,15 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { config.numFramesPerBurst = request.mRttBurstSize; config.numRetriesPerRttFrame = (config.type == RttType.TWO_SIDED ? 0 : 3); config.numRetriesPerFtmr = 3; - config.burstDuration = 9; + config.burstDuration = getOptimumBurstDuration(request.mRttBurstSize); if (cap != null) { // constrain parameters per device capabilities config.mustRequestLci = config.mustRequestLci && cap.lciSupported; config.mustRequestLcr = config.mustRequestLcr && cap.lcrSupported; - config.bw = halRttChannelBandwidthCapabilityLimiter(config.bw, cap); - config.preamble = halRttPreambleCapabilityLimiter(config.preamble, cap); + config.bw = halRttChannelBandwidthCapabilityLimiter(config.bw, cap, + config.type); + config.preamble = halRttPreambleCapabilityLimiter(config.preamble, cap, + config.type); } } } catch (IllegalArgumentException e) { @@ -515,9 +638,12 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { * Note: the halRttChannelBandwidth is a single bit flag from the HAL RttBw type. */ private static int halRttChannelBandwidthCapabilityLimiter(int halRttChannelBandwidth, - WifiRttController.Capabilities cap) throws IllegalArgumentException { + WifiRttController.Capabilities cap, @RttType int rttType) + throws IllegalArgumentException { int requestedBandwidth = halRttChannelBandwidth; - while ((halRttChannelBandwidth != 0) && ((halRttChannelBandwidth & cap.bwSupported) == 0)) { + int bwSupported = + (rttType == RttType.TWO_SIDED_11AZ_NTB) ? cap.azBwSupported : cap.bwSupported; + while ((halRttChannelBandwidth != 0) && ((halRttChannelBandwidth & bwSupported) == 0)) { halRttChannelBandwidth >>= 1; } @@ -539,9 +665,12 @@ public class WifiRttControllerAidlImpl implements IWifiRttController { * Note: the halRttPreamble is a single bit flag from the HAL RttPreamble type. */ private static int halRttPreambleCapabilityLimiter(int halRttPreamble, - WifiRttController.Capabilities cap) throws IllegalArgumentException { + WifiRttController.Capabilities cap, @RttType int rttType) + throws IllegalArgumentException { int requestedPreamble = halRttPreamble; - while ((halRttPreamble != 0) && ((halRttPreamble & cap.preambleSupported) == 0)) { + int preambleSupported = (rttType == RttType.TWO_SIDED_11AZ_NTB) ? cap.azPreambleSupported + : cap.preambleSupported; + while ((halRttPreamble != 0) && ((halRttPreamble & preambleSupported) == 0)) { halRttPreamble >>= 1; } diff --git a/service/java/com/android/server/wifi/hal/WifiRttControllerHidlImpl.java b/service/java/com/android/server/wifi/hal/WifiRttControllerHidlImpl.java index 6ef2eaabff..cce8bb1372 100644 --- a/service/java/com/android/server/wifi/hal/WifiRttControllerHidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiRttControllerHidlImpl.java @@ -396,14 +396,21 @@ public class WifiRttControllerHidlImpl implements IWifiRttController { } rttResult.distanceSdInMm = 0; } - rangingResults.add(new RangingResult( - convertHalStatusToFrameworkStatus(rttResult.status), - MacAddress.fromBytes(rttResult.addr), - rttResult.distanceInMm, rttResult.distanceSdInMm, - rttResult.rssi / -2, rttResult.numberPerBurstPeer, - rttResult.successNumber, lci, lcr, responderLocation, - rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS, - rttResult.type == RttType.TWO_SIDED)); + rangingResults.add(new RangingResult.Builder() + .setStatus(convertHalStatusToFrameworkStatus(rttResult.status)) + .setMacAddress(MacAddress.fromBytes(rttResult.addr)) + .setDistanceMm(rttResult.distanceInMm) + .setDistanceStdDevMm(rttResult.distanceSdInMm) + .setRssi(rttResult.rssi / -2) + .setNumAttemptedMeasurements(rttResult.numberPerBurstPeer) + .setNumSuccessfulMeasurements(rttResult.successNumber) + .setLci(lci) + .setLcr(lcr) + .setUnverifiedResponderLocation(responderLocation) + .setRangingTimestampMillis( + rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS) + .set80211mcMeasurement(rttResult.type == RttType.TWO_SIDED) + .build()); } return rangingResults; } @@ -432,14 +439,21 @@ public class WifiRttControllerHidlImpl implements IWifiRttController { } rttResult.distanceSdInMm = 0; } - rangingResults.add(new RangingResult( - convertHalStatusToFrameworkStatus(rttResult.status), - MacAddress.fromBytes(rttResult.addr), - rttResult.distanceInMm, rttResult.distanceSdInMm, - rttResult.rssi / -2, rttResult.numberPerBurstPeer, - rttResult.successNumber, lci, lcr, responderLocation, - rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS, - rttResult.type == RttType.TWO_SIDED)); + rangingResults.add(new RangingResult.Builder() + .setStatus(convertHalStatusToFrameworkStatus(rttResult.status)) + .setMacAddress(MacAddress.fromBytes(rttResult.addr)) + .setDistanceMm(rttResult.distanceInMm) + .setDistanceStdDevMm(rttResult.distanceSdInMm) + .setRssi(rttResult.rssi / -2) + .setNumAttemptedMeasurements(rttResult.numberPerBurstPeer) + .setNumSuccessfulMeasurements(rttResult.successNumber) + .setLci(lci) + .setLcr(lcr) + .setUnverifiedResponderLocation(responderLocation) + .setRangingTimestampMillis( + rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS) + .set80211mcMeasurement(rttResult.type == RttType.TWO_SIDED) + .build()); } return rangingResults; } @@ -468,14 +482,21 @@ public class WifiRttControllerHidlImpl implements IWifiRttController { } rttResult.distanceSdInMm = 0; } - rangingResults.add(new RangingResult( - convertHalStatusToFrameworkStatus(rttResult.status), - MacAddress.fromBytes(rttResult.addr), - rttResult.distanceInMm, rttResult.distanceSdInMm, - rttResult.rssi / -2, rttResult.numberPerBurstPeer, - rttResult.successNumber, lci, lcr, responderLocation, - rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS, - rttResult.type == RttType.TWO_SIDED)); + rangingResults.add(new RangingResult.Builder() + .setStatus(convertHalStatusToFrameworkStatus(rttResult.status)) + .setMacAddress(MacAddress.fromBytes(rttResult.addr)) + .setDistanceMm(rttResult.distanceInMm) + .setDistanceStdDevMm(rttResult.distanceSdInMm) + .setRssi(rttResult.rssi / -2) + .setNumAttemptedMeasurements(rttResult.numberPerBurstPeer) + .setNumSuccessfulMeasurements(rttResult.successNumber) + .setLci(lci) + .setLcr(lcr) + .setUnverifiedResponderLocation(responderLocation) + .setRangingTimestampMillis( + rttResult.timeStampInUs / WifiRttController.CONVERSION_US_TO_MS) + .set80211mcMeasurement(rttResult.type == RttType.TWO_SIDED) + .build()); } return rangingResults; } diff --git a/service/java/com/android/server/wifi/hal/WifiStaIface.java b/service/java/com/android/server/wifi/hal/WifiStaIface.java index e847bd832a..ca4cd785d1 100644 --- a/service/java/com/android/server/wifi/hal/WifiStaIface.java +++ b/service/java/com/android/server/wifi/hal/WifiStaIface.java @@ -16,13 +16,20 @@ package com.android.server.wifi.hal; +import static android.net.wifi.WifiManager.ROAMING_MODE_NORMAL; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.hardware.wifi.WifiStatusCode; import android.net.MacAddress; import android.net.apf.ApfCapabilities; import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager.RoamingMode; import android.net.wifi.WifiScanner; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSessionCallback; +import android.os.Bundle; import android.util.Log; import com.android.server.wifi.SsidTranslator; @@ -110,6 +117,47 @@ public class WifiStaIface implements WifiHal.WifiInterface { * @param currRssi RSSI of the currently connected access point. */ void onRssiThresholdBreached(int cmdId, byte[] currBssid, int currRssi); + + /** + * Called when TWT operation fails. + * + * @param cmdId Unique command id which is failed + * @param twtErrorCode Error code + */ + void onTwtFailure(int cmdId, @TwtSessionCallback.TwtErrorCode int twtErrorCode); + + /** + * Called when {@link WifiStaIface#setupTwtSession(int, TwtRequest)} succeeds. + * + * @param cmdId Unique command id used in + * {@link WifiStaIface#setupTwtSession(int, TwtRequest)} + * @param wakeDurationUs TWT wake duration for the session in microseconds + * @param wakeIntervalUs TWT wake interval for the session in microseconds + * @param linkId Multi link operation link id + * @param sessionId TWT session id + */ + void onTwtSessionCreate(int cmdId, int wakeDurationUs, long wakeIntervalUs, int linkId, + int sessionId); + + /** + * Called when TWT session is torndown by {@link WifiStaIface#tearDownTwtSession(int, int)}. + * Can also be called unsolicitedly by the vendor software with proper reason code. + * + * @param cmdId Unique command id used in {@link WifiStaIface#tearDownTwtSession(int, int)} + * @param twtSessionId TWT session Id + * @param twtReasonCode Reason code for teardown + */ + void onTwtSessionTeardown(int cmdId, int twtSessionId, + @TwtSessionCallback.TwtReasonCode int twtReasonCode); + + /** + * Called as a response to {@link WifiStaIface#getStatsTwtSession(int, int)} + * + * @param cmdId Unique command id used in {@link WifiStaIface#getStatsTwtSession(int, int)} + * @param twtSessionId TWT session Id + * @param twtStats TWT stats bundle + */ + void onTwtSessionStats(int cmdId, int twtSessionId, Bundle twtStats); } public WifiStaIface(@NonNull android.hardware.wifi.V1_0.IWifiStaIface staIface, @@ -236,6 +284,16 @@ public class WifiStaIface implements WifiHal.WifiInterface { } /** + * See comments for {@link IWifiStaIface#getCachedScanData()} + */ + @Nullable + public WifiScanner.ScanData getCachedScanData() { + return validateAndCall("getCachedScanData", null, + () -> mWifiStaIface.getCachedScanData()); + } + + + /** * See comments for {@link IWifiStaIface#getLinkLayerStats()} */ @Nullable @@ -361,4 +419,45 @@ public class WifiStaIface implements WifiHal.WifiInterface { return validateAndCall("setDtimMultiplier", false, () -> mWifiStaIface.setDtimMultiplier(multiplier)); } + + /** + * See comments for {@link IWifiStaIface#setRoamingMode(int)} + */ + public @WifiStatusCode int setRoamingMode(@RoamingMode int roamingMode) { + return validateAndCall("setRoamingMode", ROAMING_MODE_NORMAL, + () -> mWifiStaIface.setRoamingMode(roamingMode)); + } + + /** + * See {@link IWifiStaIface#getTwtCapabilities()} + */ + public Bundle getTwtCapabilities() { + return validateAndCall("getTwtCapabilities", null, + () -> mWifiStaIface.getTwtCapabilities()); + } + + /** + * See {@link IWifiStaIface#setupTwtSession(int, TwtRequest)} + */ + public boolean setupTwtSession(int cmdId, TwtRequest twtRequest) { + return validateAndCall("setupTwtSession", false, + () -> mWifiStaIface.setupTwtSession(cmdId, twtRequest)); + } + + /** + * See {@link IWifiStaIface#tearDownTwtSession(int, int)} + */ + public boolean tearDownTwtSession(int commandId, int sessionId) { + return validateAndCall("tearDownTwtSession", false, + () -> mWifiStaIface.tearDownTwtSession(commandId, sessionId)); + } + + /** + * See {@link IWifiStaIface#getStatsTwtSession(int, int)} + */ + public boolean getStatsTwtSession(int commandId, int sessionId) { + return validateAndCall("getStatsTwtSession", false, + () -> mWifiStaIface.getStatsTwtSession(commandId, sessionId)); + } } + diff --git a/service/java/com/android/server/wifi/hal/WifiStaIfaceAidlImpl.java b/service/java/com/android/server/wifi/hal/WifiStaIfaceAidlImpl.java index 0950ecfe79..628bfc5918 100644 --- a/service/java/com/android/server/wifi/hal/WifiStaIfaceAidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiStaIfaceAidlImpl.java @@ -16,9 +16,13 @@ package com.android.server.wifi.hal; +import static com.android.server.wifi.hal.WifiHalAidlImpl.isServiceVersionAtLeast; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.hardware.wifi.CachedScanData; +import android.hardware.wifi.CachedScanResult; import android.hardware.wifi.IWifiStaIfaceEventCallback; import android.hardware.wifi.Ssid; import android.hardware.wifi.StaApfPacketFilterCapabilities; @@ -47,14 +51,20 @@ import android.hardware.wifi.WifiDebugRxPacketFate; import android.hardware.wifi.WifiDebugRxPacketFateReport; import android.hardware.wifi.WifiDebugTxPacketFate; import android.hardware.wifi.WifiDebugTxPacketFateReport; +import android.hardware.wifi.WifiRatePreamble; import android.hardware.wifi.WifiStatusCode; import android.net.MacAddress; import android.net.apf.ApfCapabilities; import android.net.wifi.ScanResult; +import android.net.wifi.WifiAnnotations; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.RoamingMode; import android.net.wifi.WifiScanner; import android.net.wifi.WifiSsid; import android.net.wifi.WifiUsabilityStatsEntry; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSessionCallback; +import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Log; @@ -65,6 +75,7 @@ import com.android.server.wifi.WifiLinkLayerStats; import com.android.server.wifi.WifiLoggerHal; import com.android.server.wifi.WifiNative; import com.android.server.wifi.util.BitMask; +import com.android.server.wifi.util.HalAidlUtil; import com.android.server.wifi.util.NativeUtil; import com.android.wifi.resources.R; @@ -369,6 +380,28 @@ public class WifiStaIfaceAidlImpl implements IWifiStaIface { } /** + * See comments for {@link IWifiStaIface#getCachedScanData()} + */ + @Override + @Nullable + public WifiScanner.ScanData getCachedScanData() { + final String methodStr = "getCachedScanData"; + synchronized (mLock) { + try { + if (!checkIfaceAndLogFailure(methodStr)) return null; + CachedScanData scanData = mWifiStaIface.getCachedScanData(); + return halToFrameworkCachedScanData(scanData); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return null; + } + } + + + /** * See comments for {@link IWifiStaIface#getLinkLayerStats()} */ @Override @@ -384,6 +417,9 @@ public class WifiStaIfaceAidlImpl implements IWifiStaIface { handleRemoteException(e, methodStr); } catch (ServiceSpecificException e) { handleServiceSpecificException(e, methodStr); + } catch (IllegalArgumentException e) { + // May indicate a malformed return value in the HAL. + Log.wtf(TAG, methodStr + " encountered IllegalArgumentException: " + e); } return null; } @@ -688,6 +724,172 @@ public class WifiStaIfaceAidlImpl implements IWifiStaIface { } } + /** + * See comments for {@link IWifiStaIface#setRoamingMode(int)} + */ + public @WifiStatusCode int setRoamingMode(@RoamingMode int roamingMode) { + final String methodStr = "setRoamingMode"; + @WifiStatusCode int errorCode = WifiStatusCode.ERROR_UNKNOWN; + synchronized (mLock) { + try { + if (checkIfaceAndLogFailure(methodStr)) { + mWifiStaIface.setRoamingState(frameworkToHalRoamingMode(roamingMode)); + errorCode = WifiStatusCode.SUCCESS; + } + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + errorCode = WifiStatusCode.ERROR_NOT_STARTED; + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + errorCode = e.errorCode; + } catch (IllegalArgumentException e) { + handleIllegalArgumentException(e, methodStr); + errorCode = WifiStatusCode.ERROR_INVALID_ARGS; + } + return errorCode; + } + } + + private static byte frameworkToHalRoamingMode( + @WifiManager.RoamingMode int mode) { + switch (mode) { + case WifiManager.ROAMING_MODE_NONE: + return StaRoamingState.DISABLED; + case WifiManager.ROAMING_MODE_NORMAL: + return StaRoamingState.ENABLED; + case WifiManager.ROAMING_MODE_AGGRESSIVE: + return StaRoamingState.AGGRESSIVE; + default: + throw new IllegalArgumentException("frameworkToHalRoamingMode Invalid mode: " + + mode); + } + } + + /** + * Get target wake time (TWT) capabilities. + * + * @return TWT capabilities as Bundle + */ + @Override + public Bundle getTwtCapabilities() { + final String methodStr = "getTwtCapabilities"; + synchronized (mLock) { + try { + if (!isServiceVersionAtLeast(2) || !checkIfaceAndLogFailure(methodStr)) { + return null; + } + android.hardware.wifi.TwtCapabilities halTwtCapabilities = + mWifiStaIface.twtGetCapabilities(); + if (halTwtCapabilities == null) return null; + Bundle twtCapabilities = new Bundle(); + twtCapabilities.putBoolean(WifiManager.TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER, + halTwtCapabilities.isTwtRequesterSupported); + twtCapabilities.putInt( + WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS, + halTwtCapabilities.minWakeDurationUs); + twtCapabilities.putInt( + WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS, + halTwtCapabilities.maxWakeDurationUs); + twtCapabilities.putLong( + WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS, + halTwtCapabilities.minWakeIntervalUs); + twtCapabilities.putLong( + WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS, + halTwtCapabilities.maxWakeIntervalUs); + return twtCapabilities; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return null; + } + } + + /** + * Set up a TWT session + * + * @param cmdId Command ID to use for this invocation. + * @param twtRequest TWT request configuration to setup TWT session + * @return true if successful, false otherwise. + */ + @Override + public boolean setupTwtSession(int cmdId, TwtRequest twtRequest) { + final String methodStr = "setupTwtSession"; + synchronized (mLock) { + try { + if (!isServiceVersionAtLeast(2) || !checkIfaceAndLogFailure(methodStr)) { + return false; + } + android.hardware.wifi.TwtRequest halTwtRequest = + new android.hardware.wifi.TwtRequest(); + halTwtRequest.maxWakeDurationUs = twtRequest.getMaxWakeDurationMicros(); + halTwtRequest.minWakeDurationUs = twtRequest.getMinWakeDurationMicros(); + halTwtRequest.maxWakeIntervalUs = twtRequest.getMaxWakeIntervalMicros(); + halTwtRequest.minWakeIntervalUs = twtRequest.getMinWakeIntervalMicros(); + mWifiStaIface.twtSessionSetup(cmdId, halTwtRequest); + return true; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return false; + } + } + + /** + * Teardown a TWT session. + * + * @param cmdId Command ID to use for this invocation. + * @param sessionId TWT session identifier + * @return true if successful, false otherwise. + */ + @Override + public boolean tearDownTwtSession(int cmdId, int sessionId) { + final String methodStr = "tearDownTwtSession"; + synchronized (mLock) { + try { + if (!isServiceVersionAtLeast(2) || !checkIfaceAndLogFailure(methodStr)) { + return false; + } + mWifiStaIface.twtSessionTeardown(cmdId, sessionId); + return true; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return false; + } + } + + /** + * Get stats for the TWT session. + * + * @param cmdId Command ID to use for this invocation. + * @param sessionId TWT session identifier + * @return true if successful, false otherwise. + */ + @Override + public boolean getStatsTwtSession(int cmdId, int sessionId) { + final String methodStr = "getStatsTwtSession"; + synchronized (mLock) { + try { + if (!isServiceVersionAtLeast(2) || !checkIfaceAndLogFailure(methodStr)) { + return false; + } + mWifiStaIface.twtSessionGetStats(cmdId, sessionId); + return true; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return false; + } + } + private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub { @Override public void onBackgroundScanFailure(int cmdId) { @@ -733,12 +935,44 @@ public class WifiStaIfaceAidlImpl implements IWifiStaIface { @Override public void onTwtFailure(int cmdId, byte twtErrorCode) { - //TODO: Implementation + if (mFrameworkCallback == null) return; + @TwtErrorCode int errorCode; + switch (twtErrorCode) { + case TwtErrorCode.INVALID_PARAMS: + errorCode = TwtSessionCallback.TWT_ERROR_CODE_INVALID_PARAMS; + break; + case TwtErrorCode.MAX_SESSION_REACHED: + errorCode = TwtSessionCallback.TWT_ERROR_CODE_MAX_SESSIONS_REACHED; + break; + case TwtErrorCode.NOT_AVAILABLE: + errorCode = TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE; + break; + case TwtErrorCode.NOT_SUPPORTED: + errorCode = TwtSessionCallback.TWT_ERROR_CODE_NOT_SUPPORTED; + break; + case TwtErrorCode.PEER_NOT_SUPPORTED: + errorCode = TwtSessionCallback.TWT_ERROR_CODE_AP_NOT_SUPPORTED; + break; + case TwtErrorCode.PEER_REJECTED: + errorCode = TwtSessionCallback.TWT_ERROR_CODE_AP_REJECTED; + break; + case TwtErrorCode.TIMEOUT: + errorCode = TwtSessionCallback.TWT_ERROR_CODE_TIMEOUT; + break; + case TwtErrorCode.ALREADY_RESUMED: + case TwtErrorCode.ALREADY_SUSPENDED: + case TwtErrorCode.FAILURE_UNKNOWN: + default: + errorCode = TwtSessionCallback.TWT_REASON_CODE_UNKNOWN; + } + mFrameworkCallback.onTwtFailure(cmdId, errorCode); } @Override public void onTwtSessionCreate(int cmdId, TwtSession twtSession) { - //TODO: Implementation + if (mFrameworkCallback == null || twtSession == null) return; + mFrameworkCallback.onTwtSessionCreate(cmdId, twtSession.wakeDurationUs, + twtSession.wakeDurationUs, twtSession.mloLinkId, twtSession.sessionId); } @Override @@ -758,17 +992,52 @@ public class WifiStaIfaceAidlImpl implements IWifiStaIface { @Override public void onTwtSessionTeardown(int cmdId, int twtSessionId, byte twtReasonCode) { - //TODO: Implementation + if (mFrameworkCallback == null) return; + @TwtTeardownReasonCode int reasonCode; + switch (twtReasonCode) { + case TwtTeardownReasonCode.INTERNALLY_INITIATED: + reasonCode = TwtSessionCallback.TWT_REASON_CODE_INTERNALLY_INITIATED; + break; + case TwtTeardownReasonCode.LOCALLY_REQUESTED: + reasonCode = TwtSessionCallback.TWT_REASON_CODE_LOCALLY_REQUESTED; + break; + case TwtTeardownReasonCode.PEER_INITIATED: + reasonCode = TwtSessionCallback.TWT_REASON_CODE_PEER_INITIATED; + break; + case TwtTeardownReasonCode.UNKNOWN: + default: + reasonCode = TwtSessionCallback.TWT_REASON_CODE_UNKNOWN; + } + mFrameworkCallback.onTwtSessionTeardown(cmdId, twtSessionId, reasonCode); } @Override public void onTwtSessionStats(int cmdId, int twtSessionId, TwtSessionStats twtSessionStats) { - //TODO: Implementation + if (mFrameworkCallback == null) return; + Bundle twtStats = new Bundle(); + twtStats.putInt( + android.net.wifi.twt.TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT, + twtSessionStats.avgTxPktCount); + twtStats.putInt( + android.net.wifi.twt.TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE, + twtSessionStats.avgTxPktSize); + twtStats.putInt( + android.net.wifi.twt.TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT, + twtSessionStats.avgRxPktCount); + twtStats.putInt( + android.net.wifi.twt.TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE, + twtSessionStats.avgRxPktSize); + twtStats.putInt( + android.net.wifi.twt.TwtSession.TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS, + twtSessionStats.avgEospDurationUs); + twtStats.putInt( + android.net.wifi.twt.TwtSession.TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS, + twtSessionStats.eospCount); + mFrameworkCallback.onTwtSessionStats(cmdId, twtSessionId, twtStats); } } - // Utilities // Only sets the fields of ScanResult used by Gscan clients. @@ -830,6 +1099,76 @@ public class WifiStaIfaceAidlImpl implements IWifiStaIface { return frameworkScanDatas; } + @WifiAnnotations.WifiStandard + private static int wifiRatePreambleToWifiStandard(int wifiRatePreamble) { + switch (wifiRatePreamble) { + case WifiRatePreamble.CCK: + case WifiRatePreamble.OFDM: + return ScanResult.WIFI_STANDARD_LEGACY; + case WifiRatePreamble.HT: + return ScanResult.WIFI_STANDARD_11N; + case WifiRatePreamble.VHT: + return ScanResult.WIFI_STANDARD_11AC; + case WifiRatePreamble.HE: + return ScanResult.WIFI_STANDARD_11AX; + case WifiRatePreamble.EHT: + return ScanResult.WIFI_STANDARD_11BE; + default: + return ScanResult.WIFI_STANDARD_UNKNOWN; + } + } + + private ScanResult halToFrameworkCachedScanResult(CachedScanResult scanResult) { + if (scanResult == null) return null; + WifiSsid originalSsid = WifiSsid.fromBytes(scanResult.ssid); + MacAddress bssid; + try { + bssid = MacAddress.fromString(NativeUtil.macAddressFromByteArray(scanResult.bssid)); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to get BSSID of scan result: " + e); + return null; + } + ScanResult frameworkScanResult = new ScanResult(); + frameworkScanResult.setWifiSsid(mSsidTranslator.getTranslatedSsidAndRecordBssidCharset( + originalSsid, bssid)); + frameworkScanResult.BSSID = bssid.toString(); + frameworkScanResult.level = scanResult.rssiDbm; + frameworkScanResult.frequency = scanResult.frequencyMhz; + frameworkScanResult.timestamp = scanResult.timeStampInUs; + frameworkScanResult.channelWidth = HalAidlUtil + .getChannelBandwidthFromHal(scanResult.channelWidthMhz); + frameworkScanResult.setWifiStandard( + wifiRatePreambleToWifiStandard(scanResult.preambleType)); + return frameworkScanResult; + } + + private ScanResult[] aidlToFrameworkCachedScanResults(CachedScanResult[] cachedScanResults) { + if (cachedScanResults == null) return new ScanResult[0]; + List<ScanResult> frameworkScanResults = new ArrayList<>(); + for (CachedScanResult cachedScanResult : cachedScanResults) { + ScanResult frameworkScanResult = halToFrameworkCachedScanResult(cachedScanResult); + if (frameworkScanResult == null) { + Log.e(TAG, "aidlToFrameworkCachedScanResults: unable to convert aidl to framework " + + "scan result!"); + continue; + } + frameworkScanResults.add(frameworkScanResult); + } + return frameworkScanResults.toArray(new ScanResult[0]); + } + + private WifiScanner.ScanData halToFrameworkCachedScanData(CachedScanData cachedScanData) { + if (cachedScanData == null) return null; + ScanResult[] scanResults = aidlToFrameworkCachedScanResults( + cachedScanData.cachedScanResults); + + // Todo b/319658055: map cachedScanData.scannedFrequenciesMhz to WifiScanner.WifiBand + WifiScanner.ScanData frameworkScanData = new WifiScanner.ScanData(0, 0, + 0, WifiScanner.WIFI_BAND_UNSPECIFIED, scanResults); + + return frameworkScanData; + } + private static StaRoamingConfig frameworkToHalStaRoamingConfig(List<MacAddress> bssidBlocklist, List<byte[]> ssidAllowlist) { StaRoamingConfig config = new StaRoamingConfig(); @@ -972,6 +1311,10 @@ public class WifiStaIfaceAidlImpl implements IWifiStaIface { android.hardware.wifi.IWifiStaIface.FeatureSetMask.SCAN_RAND)) { features |= WifiManager.WIFI_FEATURE_SCAN_RAND; } + if (hasCapability(halFeatureSet, + android.hardware.wifi.IWifiStaIface.FeatureSetMask.ROAMING_MODE_CONTROL)) { + features |= WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT; + } return features; } diff --git a/service/java/com/android/server/wifi/hal/WifiStaIfaceHidlImpl.java b/service/java/com/android/server/wifi/hal/WifiStaIfaceHidlImpl.java index b44d6e0739..0472f89ef9 100644 --- a/service/java/com/android/server/wifi/hal/WifiStaIfaceHidlImpl.java +++ b/service/java/com/android/server/wifi/hal/WifiStaIfaceHidlImpl.java @@ -191,6 +191,15 @@ public class WifiStaIfaceHidlImpl implements IWifiStaIface { } /** + * See comments for {@link IWifiStaIface#getCachedScanData()} + */ + @Nullable + public WifiScanner.ScanData getCachedScanData() { + Log.d(TAG, "getCachedScanData is not implemented by HIDL"); + return null; + } + + /** * See comments for {@link IWifiStaIface#getLinkLayerStats()} */ @Nullable @@ -333,6 +342,14 @@ public class WifiStaIfaceHidlImpl implements IWifiStaIface { return false; } + /** + * See comments for {@link IWifiStaIface#setRoamingMode(int)} + */ + public int setRoamingMode(int roamingMode) { + Log.d(TAG, "setRoamingMode is not implemented by HIDL"); + return 0; + } + // Internal Implementations private boolean registerFrameworkCallbackInternal(String methodStr, diff --git a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java index 407240d1cb..e2facfe698 100644 --- a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java +++ b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java @@ -161,8 +161,9 @@ public class NetworkDetail { // 6 GHz Access Point Type private final InformationElementUtil.ApType6GHz mApType6GHz; - // IEEE 802.11az - private final boolean mIs11azSupported; + // IEEE 802.11az non-trigger based & trigger based + private final boolean mIs11azNtbResponder; + private final boolean mIs11azTbResponder; // MLO Attributes private MacAddress mMldMacAddress = null; @@ -372,31 +373,35 @@ public class NetworkDetail { mEpcsPriorityAccessSupported = ehtCapabilities.isEpcsPriorityAccessSupported(); mFilsCapable = extendedCapabilities.isFilsCapable(); mApType6GHz = heOperation.getApType6GHz(); - mIs11azSupported = extendedCapabilities.isTriggerBasedRangingRespSupported() - || extendedCapabilities.isNonTriggerBasedRangingRespSupported(); + mIs11azNtbResponder = extendedCapabilities.is80211azNtbResponder(); + mIs11azTbResponder = extendedCapabilities.is80211azTbResponder(); int channelWidth = ScanResult.UNSPECIFIED; int centerFreq0 = mPrimaryFreq; int centerFreq1 = 0; - if (ehtOperation.isPresent()) { - //TODO: include parsing of EHT_Operation to collect BW and center freq. + // Check if EHT Operation Info is present in EHT operation IE. + if (ehtOperation.isEhtOperationInfoPresent()) { + int operatingBand = ScanResult.toBand(mPrimaryFreq); + channelWidth = ehtOperation.getChannelWidth(); + centerFreq0 = ehtOperation.getCenterFreq0(operatingBand); + centerFreq1 = ehtOperation.getCenterFreq1(operatingBand); mDisabledSubchannelBitmap = ehtOperation.getDisabledSubchannelBitmap(); } - if (ehtOperation.isPresent()) { - //TODO Add impact for using info from EHT capabilities and EHT operation IEs - } - - // Check if HE Operation IE is present - if (heOperation.isPresent()) { - // If 6GHz info is present, then parameters should be acquired from HE Operation IE - if (heOperation.is6GhzInfoPresent()) { - channelWidth = heOperation.getChannelWidth(); - centerFreq0 = heOperation.getCenterFreq0(); - centerFreq1 = heOperation.getCenterFreq1(); - } else if (heOperation.isVhtInfoPresent()) { - // VHT Operation Info could be included inside the HE Operation IE - vhtOperation.from(heOperation.getVhtInfoElement()); + // Proceed to HE Operation IE if channel width and center frequencies were not obtained + // from EHT Operation IE + if (channelWidth == ScanResult.UNSPECIFIED) { + // Check if HE Operation IE is present + if (heOperation.isPresent()) { + // If 6GHz info is present, then parameters should be acquired from HE Operation IE + if (heOperation.is6GhzInfoPresent()) { + channelWidth = heOperation.getChannelWidth(); + centerFreq0 = heOperation.getCenterFreq0(); + centerFreq1 = heOperation.getCenterFreq1(); + } else if (heOperation.isVhtInfoPresent()) { + // VHT Operation Info could be included inside the HE Operation IE + vhtOperation.from(heOperation.getVhtInfoElement()); + } } } @@ -560,7 +565,8 @@ public class NetworkDetail { mEpcsPriorityAccessSupported = base.mEpcsPriorityAccessSupported; mFilsCapable = base.mFilsCapable; mApType6GHz = base.mApType6GHz; - mIs11azSupported = base.mIs11azSupported; + mIs11azNtbResponder = base.mIs11azNtbResponder; + mIs11azTbResponder = base.mIs11azTbResponder; } public NetworkDetail complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements) { @@ -790,10 +796,16 @@ public class NetworkDetail { return mOceSupported; } - /** Return whether the AP supports IEEE 802.11az **/ - public boolean is11azSupported() { - return mIs11azSupported; + /** Return whether the AP supports IEEE 802.11az non-trigger based ranging **/ + public boolean is80211azNtbResponder() { + return mIs11azNtbResponder; } + + /** Return whether the AP supports IEEE 802.11az trigger based ranging **/ + public boolean is80211azTbResponder() { + return mIs11azTbResponder; + } + /** * Return whether the AP requires HE stations to participate either in individual TWT * agreements or Broadcast TWT operation. diff --git a/service/java/com/android/server/wifi/mockwifi/MockWifiServiceUtil.java b/service/java/com/android/server/wifi/mockwifi/MockWifiServiceUtil.java index a36efab3b4..05948aadb2 100644 --- a/service/java/com/android/server/wifi/mockwifi/MockWifiServiceUtil.java +++ b/service/java/com/android/server/wifi/mockwifi/MockWifiServiceUtil.java @@ -121,8 +121,7 @@ public class MockWifiServiceUtil { intent.setComponent(new ComponentName(mPackageName, mServiceName)); intent.setAction(actionName); - status = mContext.createContextAsUser(CURRENT, 0) - .bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + status = mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); return status; } diff --git a/service/java/com/android/server/wifi/p2p/ExternalApproverManager.java b/service/java/com/android/server/wifi/p2p/ExternalApproverManager.java index bcb0414ba2..1fe58d9a54 100644 --- a/service/java/com/android/server/wifi/p2p/ExternalApproverManager.java +++ b/service/java/com/android/server/wifi/p2p/ExternalApproverManager.java @@ -138,7 +138,7 @@ public class ExternalApproverManager { private void logd(String s) { if (!mVerboseLoggingEnabled) return; - Log.d(TAG, s); + Log.d(TAG, s, null); } /** The approver data. */ diff --git a/service/java/com/android/server/wifi/p2p/ISupplicantP2pIfaceHal.java b/service/java/com/android/server/wifi/p2p/ISupplicantP2pIfaceHal.java index 1634fb87a5..72f669bb53 100644 --- a/service/java/com/android/server/wifi/p2p/ISupplicantP2pIfaceHal.java +++ b/service/java/com/android/server/wifi/p2p/ISupplicantP2pIfaceHal.java @@ -17,14 +17,19 @@ package com.android.server.wifi.p2p; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.ScanResult; import android.net.wifi.p2p.WifiP2pConfig; +import android.net.wifi.p2p.WifiP2pDiscoveryConfig; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; +import com.android.server.wifi.WifiNative; + import java.util.List; import java.util.Set; @@ -108,6 +113,19 @@ interface ISupplicantP2pIfaceHal { boolean find(@WifiP2pManager.WifiP2pScanType int type, int freq, int timeout); /** + * Initiate P2P device discovery with config params. + * + * @param config The config parameters to initiate P2P discovery. + * @param timeout The maximum amount of time to be spent in performing discovery. + * Set to 0 to indefinitely continue discovery until an explicit + * |stopFind| is sent. + * @return boolean value indicating whether the operation was successful. + */ + default boolean findWithParams(@NonNull WifiP2pDiscoveryConfig config, int timeout) { + return false; + } + + /** * Stop an ongoing P2P service discovery. * * @return boolean value indicating whether operation was successful. @@ -317,10 +335,12 @@ interface ISupplicantP2pIfaceHal { * @param enable Enables or disables listening. * @param periodInMillis Period in milliseconds. * @param intervalInMillis Interval in milliseconds. + * @param extListenParams Additional parameter struct for this request. * * @return true, if operation was successful. */ - boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis); + boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis, + @Nullable WifiP2pExtListenParams extListenParams); /** * Set P2P Listen channel. @@ -585,4 +605,30 @@ interface ISupplicantP2pIfaceHal { */ boolean configureEapolIpAddressAllocationParams(int ipAddressGo, int ipAddressMask, int ipAddressStart, int ipAddressEnd); + + /** + * Terminate the supplicant daemon & wait for its death. + * Note: Aidl only since it was added from HIDL 1.1 + */ + default void terminate() {}; + + /** + * Registers a death notification for supplicant. + * @return Returns true on success. + * + * Note: Aidl only. + */ + default boolean registerDeathHandler(@NonNull WifiNative.SupplicantDeathEventHandler handler) { + return true; + }; + + /** + * Deregisters a death notification for supplicant. + * @return Returns true on success. + * + * Note: Aidl only. + */ + default boolean deregisterDeathHandler() { + return true; + }; } diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImpl.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImpl.java index d6747552d5..e3eabad46c 100644 --- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImpl.java +++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImpl.java @@ -23,7 +23,9 @@ import android.annotation.Nullable; import android.hardware.wifi.supplicant.ISupplicantP2pIfaceCallback; import android.hardware.wifi.supplicant.P2pClientEapolIpAddressInfo; import android.hardware.wifi.supplicant.P2pDeviceFoundEventParams; +import android.hardware.wifi.supplicant.P2pGoNegotiationReqEventParams; import android.hardware.wifi.supplicant.P2pGroupStartedEventParams; +import android.hardware.wifi.supplicant.P2pInvitationEventParams; import android.hardware.wifi.supplicant.P2pPeerClientDisconnectedEventParams; import android.hardware.wifi.supplicant.P2pPeerClientJoinedEventParams; import android.hardware.wifi.supplicant.P2pProvDiscStatusCode; @@ -31,6 +33,8 @@ import android.hardware.wifi.supplicant.P2pProvisionDiscoveryCompletedEventParam import android.hardware.wifi.supplicant.P2pStatusCode; import android.hardware.wifi.supplicant.WpsConfigMethods; import android.hardware.wifi.supplicant.WpsDevPasswordId; +import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; @@ -43,10 +47,12 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.util.HexDump; +import com.android.modules.utils.build.SdkLevel; +import com.android.server.wifi.util.HalAidlUtil; import com.android.server.wifi.util.NativeUtil; import java.io.ByteArrayInputStream; -import java.net.Inet4Address; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -60,11 +66,13 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb private final String mInterface; private final WifiP2pMonitor mMonitor; + private final int mServiceVersion; public SupplicantP2pIfaceCallbackAidlImpl( - @NonNull String iface, @NonNull WifiP2pMonitor monitor) { + @NonNull String iface, @NonNull WifiP2pMonitor monitor, int serviceVersion) { mInterface = iface; mMonitor = monitor; + mServiceVersion = serviceVersion; } /** @@ -76,7 +84,7 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb protected static void logd(String msg) { if (sVerboseLoggingEnabled) { - Log.d(TAG, msg); + Log.d(TAG, msg, null); } } @@ -104,7 +112,7 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb byte[] wfdDeviceInfo) { handleDeviceFound(srcAddress, p2pDeviceAddress, primaryDeviceType, deviceName, configMethods, deviceCapabilities, groupCapabilities, wfdDeviceInfo, - null, null); + null, null, null); } /** @@ -147,6 +155,33 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb */ @Override public void onGoNegotiationRequest(byte[] srcAddress, int passwordId) { + handleGoNegotiationRequestEvent(srcAddress, passwordId, null); + } + + /** + * Used to indicate the reception of a P2P Group Owner negotiation request. + * + * @param goNegotiationReqEventParams Parameters associated with + * GO negotiation request. + */ + @Override + public void onGoNegotiationRequestWithParams( + P2pGoNegotiationReqEventParams goNegotiationReqEventParams) { + List<OuiKeyedData> vendorData = null; + if (mServiceVersion >= 3 && goNegotiationReqEventParams.vendorData != null) { + vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( + goNegotiationReqEventParams.vendorData); + } + handleGoNegotiationRequestEvent( + goNegotiationReqEventParams.srcAddress, + goNegotiationReqEventParams.passwordId, + vendorData); + } + + private void handleGoNegotiationRequestEvent( + byte[] srcAddress, + int passwordId, + @Nullable List<OuiKeyedData> vendorData) { WifiP2pConfig config = new WifiP2pConfig(); try { @@ -156,6 +191,10 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb return; } + if (SdkLevel.isAtLeastV() && vendorData != null) { + config.setVendorData(vendorData); + } + config.wps = new WpsInfo(); switch (passwordId) { @@ -231,7 +270,8 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb int frequency, byte[] psk, String passphrase, byte[] goDeviceAddress, boolean isPersistent) { onGroupStarted(groupIfName, isGroupOwner, ssid, frequency, psk, passphrase, goDeviceAddress, - isPersistent, /* goInterfaceAddress */ null, /*p2pClientIpInfo */ null); + isPersistent, /* goInterfaceAddress */ null, /*p2pClientIpInfo */ null, + /* vendorData */ null); } /** @@ -241,19 +281,26 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb */ @Override public void onGroupStartedWithParams(P2pGroupStartedEventParams groupStartedEventParams) { + List<OuiKeyedData> vendorData = null; + if (mServiceVersion >= 3 && groupStartedEventParams.vendorData != null) { + vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( + groupStartedEventParams.vendorData); + } onGroupStarted(groupStartedEventParams.groupInterfaceName, groupStartedEventParams.isGroupOwner, groupStartedEventParams.ssid, groupStartedEventParams.frequencyMHz, groupStartedEventParams.psk, groupStartedEventParams.passphrase, groupStartedEventParams.goDeviceAddress, groupStartedEventParams.isPersistent, groupStartedEventParams.goInterfaceAddress, groupStartedEventParams.isP2pClientEapolIpAddressInfoPresent - ? groupStartedEventParams.p2pClientIpInfo : null); + ? groupStartedEventParams.p2pClientIpInfo : null, + vendorData); } private void onGroupStarted(String groupIfName, boolean isGroupOwner, byte[] ssid, int frequency, byte[] psk, String passphrase, byte[] goDeviceAddress, boolean isPersistent, byte[] goInterfaceAddress, - P2pClientEapolIpAddressInfo p2pClientIpInfo) { + P2pClientEapolIpAddressInfo p2pClientIpInfo, + @Nullable List<OuiKeyedData> vendorData) { if (groupIfName == null) { Log.e(TAG, "Missing group interface name."); return; @@ -309,6 +356,11 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb } else { group.p2pClientEapolIpInfo = null; } + + if (SdkLevel.isAtLeastV() && vendorData != null) { + group.setVendorData(vendorData); + } + mMonitor.broadcastP2pGroupStarted(mInterface, group); } @@ -344,6 +396,39 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb @Override public void onInvitationReceived(byte[] srcAddress, byte[] goDeviceAddress, byte[] bssid, int persistentNetworkId, int operatingFrequency) { + handleInvitationReceivedEvent(srcAddress, goDeviceAddress, bssid, + persistentNetworkId, operatingFrequency, null); + } + + /** + * Used to indicate the reception of a P2P invitation. + * + * @param invitationEventParams Parameters of the invitation event. + */ + @Override + public void onInvitationReceivedWithParams( + P2pInvitationEventParams invitationEventParams) { + List<OuiKeyedData> vendorData = null; + if (mServiceVersion >= 3 && invitationEventParams.vendorData != null) { + vendorData = + HalAidlUtil.halToFrameworkOuiKeyedDataList(invitationEventParams.vendorData); + } + handleInvitationReceivedEvent( + invitationEventParams.srcAddress, + invitationEventParams.goDeviceAddress, + invitationEventParams.bssid, + invitationEventParams.persistentNetworkId, + invitationEventParams.operatingFrequencyMHz, + vendorData); + } + + private void handleInvitationReceivedEvent( + byte[] srcAddress, + byte[] goDeviceAddress, + byte[] bssid, + int persistentNetworkId, + int operatingFrequency, + List<OuiKeyedData> vendorData) { WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(persistentNetworkId); @@ -369,6 +454,10 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb group.setOwner(owner); + if (SdkLevel.isAtLeastV() && vendorData != null) { + group.setVendorData(vendorData); + } + logd("Invitation received on " + mInterface + ": " + group); mMonitor.broadcastP2pInvitationReceived(mInterface, group); } @@ -417,7 +506,7 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb public void onProvisionDiscoveryCompleted(byte[] p2pDeviceAddress, boolean isRequest, byte status, int configMethods, String generatedPin) { handleProvisionDiscoveryCompletedEvent( - p2pDeviceAddress, isRequest, status, configMethods, generatedPin, null); + p2pDeviceAddress, isRequest, status, configMethods, generatedPin, null, null); } /** @@ -429,13 +518,19 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb @Override public void onProvisionDiscoveryCompletedEvent( P2pProvisionDiscoveryCompletedEventParams provisionDiscoveryCompletedEventParams) { + List<OuiKeyedData> vendorData = null; + if (mServiceVersion >= 3 && provisionDiscoveryCompletedEventParams.vendorData != null) { + vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( + provisionDiscoveryCompletedEventParams.vendorData); + } handleProvisionDiscoveryCompletedEvent( provisionDiscoveryCompletedEventParams.p2pDeviceAddress, provisionDiscoveryCompletedEventParams.isRequest, provisionDiscoveryCompletedEventParams.status, provisionDiscoveryCompletedEventParams.configMethods, provisionDiscoveryCompletedEventParams.generatedPin, - provisionDiscoveryCompletedEventParams.groupInterfaceName); + provisionDiscoveryCompletedEventParams.groupInterfaceName, + vendorData); } private void handleProvisionDiscoveryCompletedEvent( @@ -444,7 +539,8 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb byte status, int configMethods, String generatedPin, - String groupIfName) { + String groupIfName, + @Nullable List<OuiKeyedData> vendorData) { logd( "Provision discovery " + (isRequest ? "request" : "response") @@ -474,6 +570,10 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb if (TextUtils.isEmpty(event.device.deviceAddress)) return; + if (SdkLevel.isAtLeastV() && vendorData != null) { + event.setVendorData(vendorData); + } + if ((configMethods & WpsConfigMethods.PUSHBUTTON) != 0) { if (isRequest) { event.event = WifiP2pProvDiscEvent.PBC_REQ; @@ -527,22 +627,25 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb mMonitor.broadcastP2pServiceDiscoveryResponse(mInterface, response); } - private WifiP2pDevice createStaEventDevice(byte[] srcAddress, byte[] p2pDeviceAddress) { + private WifiP2pDevice createStaEventDevice(byte[] interfaceAddress, byte[] p2pDeviceAddress, + InetAddress ipAddress) { WifiP2pDevice device = new WifiP2pDevice(); byte[] deviceAddressBytes; // Legacy STAs may not supply a p2pDeviceAddress (signaled by a zero'd p2pDeviceAddress) - // In this case, use srcAddress instead + // In this case, use interfaceAddress instead if (!Arrays.equals(NativeUtil.ANY_MAC_BYTES, p2pDeviceAddress)) { deviceAddressBytes = p2pDeviceAddress; } else { - deviceAddressBytes = srcAddress; + deviceAddressBytes = interfaceAddress; } try { device.deviceAddress = NativeUtil.macAddressFromByteArray(deviceAddressBytes); + device.setInterfaceMacAddress(MacAddress.fromBytes(interfaceAddress)); } catch (Exception e) { Log.e(TAG, "Could not decode MAC address", e); return null; } + device.setIpAddress(ipAddress); return device; } @@ -554,7 +657,7 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb */ @Override public void onStaAuthorized(byte[] srcAddress, byte[] p2pDeviceAddress) { - onP2pApStaConnected(null, srcAddress, p2pDeviceAddress, 0); + onP2pApStaConnected(null, srcAddress, p2pDeviceAddress, 0, null); } /** @@ -564,24 +667,35 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb */ @Override public void onPeerClientJoined(P2pPeerClientJoinedEventParams clientJoinedEventParams) { + List<OuiKeyedData> vendorData = null; + if (mServiceVersion >= 3 && clientJoinedEventParams.vendorData != null) { + vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( + clientJoinedEventParams.vendorData); + } onP2pApStaConnected( clientJoinedEventParams.groupInterfaceName, clientJoinedEventParams.clientInterfaceAddress, clientJoinedEventParams.clientDeviceAddress, - clientJoinedEventParams.clientIpAddress); + clientJoinedEventParams.clientIpAddress, + vendorData); } private void onP2pApStaConnected( - String groupIfName, byte[] srcAddress, byte[] p2pDeviceAddress, int ipAddress) { + String groupIfName, byte[] srcAddress, byte[] p2pDeviceAddress, int ipAddress, + @Nullable List<OuiKeyedData> vendorData) { + InetAddress ipAddressClient = null; logd("STA authorized on " + (TextUtils.isEmpty(groupIfName) ? mInterface : groupIfName)); if (ipAddress != 0) { - Inet4Address ipAddressClient = intToInet4AddressHTL(ipAddress); + ipAddressClient = intToInet4AddressHTL(ipAddress); logd("IP Address of Client: " + ipAddressClient.getHostAddress()); } - WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress); + WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress, ipAddressClient); if (device == null) { return; } + if (SdkLevel.isAtLeastV() && vendorData != null) { + device.setVendorData(vendorData); + } mMonitor.broadcastP2pApStaConnected(mInterface, device); } @@ -593,7 +707,7 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb */ @Override public void onStaDeauthorized(byte[] srcAddress, byte[] p2pDeviceAddress) { - onP2pApStaDisconnected(null, srcAddress, p2pDeviceAddress); + onP2pApStaDisconnected(null, srcAddress, p2pDeviceAddress, null); } /** @@ -605,19 +719,29 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb @Override public void onPeerClientDisconnected( P2pPeerClientDisconnectedEventParams clientDisconnectedEventParams) { + List<OuiKeyedData> vendorData = null; + if (mServiceVersion >= 3 && clientDisconnectedEventParams.vendorData != null) { + vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( + clientDisconnectedEventParams.vendorData); + } onP2pApStaDisconnected( clientDisconnectedEventParams.groupInterfaceName, clientDisconnectedEventParams.clientInterfaceAddress, - clientDisconnectedEventParams.clientDeviceAddress); + clientDisconnectedEventParams.clientDeviceAddress, + vendorData); } private void onP2pApStaDisconnected( - String groupIfName, byte[] srcAddress, byte[] p2pDeviceAddress) { + String groupIfName, byte[] srcAddress, byte[] p2pDeviceAddress, + @Nullable List<OuiKeyedData> vendorData) { logd("STA deauthorized on " + (TextUtils.isEmpty(groupIfName) ? mInterface : groupIfName)); - WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress); + WifiP2pDevice device = createStaEventDevice(srcAddress, p2pDeviceAddress, null); if (device == null) { return; } + if (SdkLevel.isAtLeastV() && vendorData != null) { + device.setVendorData(vendorData); + } mMonitor.broadcastP2pApStaDisconnected(mInterface, device); } @@ -733,7 +857,7 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb byte[] wfdR2DeviceInfo, byte[] vendorElemBytes) { handleDeviceFound(srcAddress, p2pDeviceAddress, primaryDeviceType, deviceName, configMethods, deviceCapabilities, groupCapabilities, wfdDeviceInfo, - wfdR2DeviceInfo, vendorElemBytes); + wfdR2DeviceInfo, vendorElemBytes, null); } /** @@ -743,6 +867,11 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb */ @Override public void onDeviceFoundWithParams(P2pDeviceFoundEventParams deviceFoundEventParams) { + List<OuiKeyedData> vendorData = null; + if (mServiceVersion >= 3 && deviceFoundEventParams.vendorData != null) { + vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList( + deviceFoundEventParams.vendorData); + } handleDeviceFound( deviceFoundEventParams.srcAddress, deviceFoundEventParams.p2pDeviceAddress, @@ -753,13 +882,15 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb deviceFoundEventParams.groupCapabilities, deviceFoundEventParams.wfdDeviceInfo, deviceFoundEventParams.wfdR2DeviceInfo, - deviceFoundEventParams.vendorElemBytes); + deviceFoundEventParams.vendorElemBytes, + vendorData); } private void handleDeviceFound(byte[] srcAddress, byte[] p2pDeviceAddress, byte[] primaryDeviceType, String deviceName, int configMethods, byte deviceCapabilities, int groupCapabilities, byte[] wfdDeviceInfo, - @Nullable byte[] wfdR2DeviceInfo, @Nullable byte[] vendorElemBytes) { + @Nullable byte[] wfdR2DeviceInfo, @Nullable byte[] vendorElemBytes, + @Nullable List<OuiKeyedData> vendorData) { WifiP2pDevice device = new WifiP2pDevice(); device.deviceName = deviceName; if (deviceName == null) { @@ -820,6 +951,10 @@ public class SupplicantP2pIfaceCallbackAidlImpl extends ISupplicantP2pIfaceCallb device.setVendorElements(vendorElements); } + if (SdkLevel.isAtLeastV() && vendorData != null) { + device.setVendorData(vendorData); + } + logd("Device discovered on " + mInterface + ": " + device); mMonitor.broadcastP2pDeviceFound(mInterface, device); } diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlImpl.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlImpl.java index 4bdbe4487d..e1d9499287 100644 --- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlImpl.java +++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlImpl.java @@ -63,7 +63,7 @@ public class SupplicantP2pIfaceCallbackHidlImpl extends ISupplicantP2pIfaceCallb } protected static void logd(String s) { - if (sVerboseLoggingEnabled) Log.d(TAG, s); + if (sVerboseLoggingEnabled) Log.d(TAG, s, null); } /** diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlV1_4Impl.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlV1_4Impl.java index bacb5c7cba..7f965104c9 100644 --- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlV1_4Impl.java +++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackHidlV1_4Impl.java @@ -58,7 +58,7 @@ public class SupplicantP2pIfaceCallbackHidlV1_4Impl } protected static void logd(String s) { - if (sVerboseLoggingEnabled) Log.d(TAG, s); + if (sVerboseLoggingEnabled) Log.d(TAG, s, null); } /** diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java index 34f20d279c..b621e76f6a 100644 --- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java +++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java @@ -17,9 +17,12 @@ package com.android.server.wifi.p2p; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.ScanResult; import android.net.wifi.p2p.WifiP2pConfig; +import android.net.wifi.p2p.WifiP2pDiscoveryConfig; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pManager; @@ -29,6 +32,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wifi.WifiGlobals; import com.android.server.wifi.WifiInjector; +import com.android.server.wifi.WifiNative; import java.util.List; import java.util.Set; @@ -237,6 +241,21 @@ public class SupplicantP2pIfaceHal { } /** + * Initiate P2P device discovery with config params. + * + * See comments for {@link ISupplicantP2pIfaceHal#findWithParams(WifiP2pDiscoveryConfig, int)}. + */ + public boolean findWithParams(WifiP2pDiscoveryConfig config, int timeout) { + synchronized (mLock) { + String methodStr = "findWithParams"; + if (mP2pIfaceHal == null) { + return handleNullHal(methodStr); + } + return mP2pIfaceHal.findWithParams(config, timeout); + } + } + + /** * Stop an ongoing P2P service discovery. * * @return boolean value indicating whether operation was successful. @@ -599,27 +618,20 @@ public class SupplicantP2pIfaceHal { } /** - * Configure Extended Listen Timing. - * - * If enabled, listen state must be entered every |intervalInMillis| for at - * least |periodInMillis|. Both values have acceptable range of 1-65535 - * (with interval obviously having to be larger than or equal to duration). - * If the P2P module is not idle at the time the Extended Listen Timing - * timeout occurs, the Listen State operation must be skipped. - * - * @param enable Enables or disables listening. - * @param periodInMillis Period in milliseconds. - * @param intervalInMillis Interval in milliseconds. + * Configure Extended Listen Timing. See comments for + * {@link ISupplicantP2pIfaceHal#configureExtListen(boolean, int, int, WifiP2pExtListenParams)} * * @return true, if operation was successful. */ - public boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis) { + public boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis, + @Nullable WifiP2pExtListenParams extListenParams) { synchronized (mLock) { String methodStr = "configureExtListen"; if (mP2pIfaceHal == null) { return handleNullHal(methodStr); } - return mP2pIfaceHal.configureExtListen(enable, periodInMillis, intervalInMillis); + return mP2pIfaceHal.configureExtListen( + enable, periodInMillis, intervalInMillis, extListenParams); } } @@ -1147,4 +1159,46 @@ public class SupplicantP2pIfaceHal { ipAddressStart, ipAddressEnd); } } + + /** + * Terminate the supplicant daemon & wait for its death. + */ + public void terminate() { + synchronized (mLock) { + String methodStr = "terminate"; + if (mP2pIfaceHal == null) { + handleNullHal(methodStr); + return; + } + mP2pIfaceHal.terminate(); + } + } + + /** + * Registers a death notification for supplicant. + * @return Returns true on success. + */ + public boolean registerDeathHandler(@NonNull WifiNative.SupplicantDeathEventHandler handler) { + synchronized (mLock) { + String methodStr = "registerDeathHandler"; + if (mP2pIfaceHal == null) { + return handleNullHal(methodStr); + } + return mP2pIfaceHal.registerDeathHandler(handler); + } + } + + /** + * Deregisters a death notification for supplicant. + * @return Returns true on success. + */ + public boolean deregisterDeathHandler() { + synchronized (mLock) { + String methodStr = "deregisterDeathHandler"; + if (mP2pIfaceHal == null) { + return handleNullHal(methodStr); + } + return mP2pIfaceHal.deregisterDeathHandler(); + } + } } diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImpl.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImpl.java index 1d2ce2a123..f186e0b560 100644 --- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImpl.java +++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImpl.java @@ -17,6 +17,7 @@ package com.android.server.wifi.p2p; import android.annotation.NonNull; +import android.annotation.Nullable; import android.hardware.wifi.supplicant.DebugLevel; import android.hardware.wifi.supplicant.FreqRange; import android.hardware.wifi.supplicant.ISupplicant; @@ -26,7 +27,11 @@ import android.hardware.wifi.supplicant.ISupplicantP2pNetwork; import android.hardware.wifi.supplicant.IfaceInfo; import android.hardware.wifi.supplicant.IfaceType; import android.hardware.wifi.supplicant.MiracastMode; +import android.hardware.wifi.supplicant.P2pConnectInfo; +import android.hardware.wifi.supplicant.P2pDiscoveryInfo; +import android.hardware.wifi.supplicant.P2pExtListenInfo; import android.hardware.wifi.supplicant.P2pFrameTypeMask; +import android.hardware.wifi.supplicant.P2pScanType; import android.hardware.wifi.supplicant.WpsConfigMethods; import android.hardware.wifi.supplicant.WpsProvisionMethod; import android.net.wifi.CoexUnsafeChannel; @@ -34,6 +39,8 @@ import android.net.wifi.ScanResult; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; +import android.net.wifi.p2p.WifiP2pDiscoveryConfig; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pManager; @@ -49,8 +56,10 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.WifiInjector; +import com.android.server.wifi.WifiNative; import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.util.ArrayUtils; +import com.android.server.wifi.util.HalAidlUtil; import com.android.server.wifi.util.NativeUtil; import java.io.ByteArrayOutputStream; @@ -60,6 +69,8 @@ import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -75,6 +86,7 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { private boolean mInitializationStarted = false; private static final int RESULT_NOT_VALID = -1; private static final int DEFAULT_OPERATING_CLASS = 81; + public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L; /** * Regex pattern for extracting the wps device type bytes. * Matches a strings like the following: "<categ>-<OUI>-<subcateg>"; @@ -83,14 +95,19 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$"); private final Object mLock = new Object(); + private CountDownLatch mWaitForDeathLatch; + private WifiNative.SupplicantDeathEventHandler mDeathEventHandler; // Supplicant HAL AIDL interface objects private ISupplicant mISupplicant = null; private ISupplicantP2pIface mISupplicantP2pIface = null; private final DeathRecipient mSupplicantDeathRecipient = () -> { - Log.w(TAG, "ISupplicant/ISupplicantP2pIface died"); + Log.d(TAG, "ISupplicant/ISupplicantP2pIface died"); synchronized (mLock) { + if (mWaitForDeathLatch != null) { + mWaitForDeathLatch.countDown(); + } supplicantServiceDiedHandler(); } }; @@ -205,7 +222,8 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { if (mMonitor != null) { ISupplicantP2pIfaceCallback callback = - new SupplicantP2pIfaceCallbackAidlImpl(ifaceName, mMonitor); + new SupplicantP2pIfaceCallbackAidlImpl(ifaceName, mMonitor, + getCachedServiceVersion()); if (!registerCallback(callback)) { Log.e(TAG, "Unable to register callback for iface " + ifaceName); return false; @@ -270,6 +288,9 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { mISupplicant = null; mISupplicantP2pIface = null; mInitializationStarted = false; + if (mDeathEventHandler != null) { + mDeathEventHandler.onDeath(); + } } } @@ -523,6 +544,65 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { } } + private static int frameworkToHalScanType(@WifiP2pManager.WifiP2pScanType int scanType) { + switch (scanType) { + case WifiP2pManager.WIFI_P2P_SCAN_FULL: + return P2pScanType.FULL; + case WifiP2pManager.WIFI_P2P_SCAN_SOCIAL: + return P2pScanType.SOCIAL; + case WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ: + return P2pScanType.SPECIFIC_FREQ; + default: + Log.e(TAG, "Invalid discovery scan type: " + scanType); + return -1; + } + } + + /** + * Initiate P2P device discovery with config params. + * + * See comments for {@link ISupplicantP2pIfaceHal#findWithParams(WifiP2pDiscoveryConfig, int)}. + */ + public boolean findWithParams(WifiP2pDiscoveryConfig config, int timeout) { + synchronized (mLock) { + String methodStr = "findWithParams"; + if (!checkP2pIfaceAndLogFailure(methodStr)) { + return false; + } + if (getCachedServiceVersion() < 3) { + // HAL does not support findWithParams before V3. + return find(config.getScanType(), config.getFrequencyMhz(), timeout); + } + + P2pDiscoveryInfo halInfo = new P2pDiscoveryInfo(); + halInfo.scanType = frameworkToHalScanType(config.getScanType()); + halInfo.timeoutInSec = timeout; + halInfo.frequencyMhz = config.getFrequencyMhz(); + if (halInfo.scanType == -1) { + return false; + } + if (halInfo.frequencyMhz < 0) { + Log.e(TAG, "Invalid freq value: " + halInfo.frequencyMhz); + return false; + } + + if (!config.getVendorData().isEmpty()) { + halInfo.vendorData = + HalAidlUtil.frameworkToHalOuiKeyedDataList(config.getVendorData()); + } + + try { + mISupplicantP2pIface.findWithParams(halInfo); + return true; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return false; + } + } + /** * Stop an ongoing P2P service discovery. * @@ -694,6 +774,38 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { } } + private String connectWithParams(boolean joinExistingGroup, byte[] peerAddress, + int provisionMethod, String preSelectedPin, boolean persistent, int groupOwnerIntent, + WifiP2pConfig config) { + synchronized (mLock) { + String methodStr = "connectWithParams"; + + // Parameters should be pre-validated. + P2pConnectInfo info = new P2pConnectInfo(); + info.joinExistingGroup = joinExistingGroup; + info.peerAddress = peerAddress; + info.provisionMethod = provisionMethod; + info.preSelectedPin = preSelectedPin; + info.persistent = persistent; + info.goIntent = groupOwnerIntent; + + if (SdkLevel.isAtLeastV() && config.getVendorData() != null + && !config.getVendorData().isEmpty()) { + info.vendorData = + HalAidlUtil.frameworkToHalOuiKeyedDataList(config.getVendorData()); + } + + try { + return mISupplicantP2pIface.connectWithParams(info); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return null; + } + } + /** * Start P2P group formation with a discovered P2P peer. This includes * optional group owner negotiation, group interface setup, provisioning, @@ -710,7 +822,8 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { */ public String connect(WifiP2pConfig config, boolean joinExistingGroup) { synchronized (mLock) { - String methodStr = "setSsidPostfix"; + String methodStr = "connect"; + if (!checkP2pIfaceAndLogFailure(methodStr)) { return null; } @@ -749,6 +862,11 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { return null; } + if (getCachedServiceVersion() >= 3) { + return connectWithParams(joinExistingGroup, peerAddress, provisionMethod, + preSelectedPin, persistent, config.groupOwnerIntent, config); + } + try { return mISupplicantP2pIface.connect( peerAddress, provisionMethod, preSelectedPin, joinExistingGroup, @@ -1209,21 +1327,13 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { } /** - * Configure Extended Listen Timing. - * - * If enabled, listen state must be entered every |intervalInMillis| for at - * least |periodInMillis|. Both values have acceptable range of 1-65535 - * (with interval obviously having to be larger than or equal to duration). - * If the P2P module is not idle at the time the Extended Listen Timing - * timeout occurs, the Listen State operation must be skipped. - * - * @param enable Enables or disables listening. - * @param periodInMillis Period in milliseconds. - * @param intervalInMillis Interval in milliseconds. + * Configure Extended Listen Timing. See comments for + * {@link ISupplicantP2pIfaceHal#configureExtListen(boolean, int, int, WifiP2pExtListenParams)} * * @return true, if operation was successful. */ - public boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis) { + public boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis, + @Nullable WifiP2pExtListenParams extListenParams) { synchronized (mLock) { String methodStr = "configureExtListen"; if (!checkP2pIfaceAndLogFailure(methodStr)) { @@ -1247,6 +1357,11 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { return false; } + if (getCachedServiceVersion() >= 3) { + return configureExtListenWithParams( + periodInMillis, intervalInMillis, extListenParams); + } + try { mISupplicantP2pIface.configureExtListen(periodInMillis, intervalInMillis); return true; @@ -1259,6 +1374,32 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { } } + private boolean configureExtListenWithParams(int periodInMillis, int intervalInMillis, + @Nullable WifiP2pExtListenParams extListenParams) { + String methodStr = "configureExtListenWithParams"; + + // Expect that these parameters are already validated. + P2pExtListenInfo extListenInfo = new P2pExtListenInfo(); + extListenInfo.periodMs = periodInMillis; + extListenInfo.intervalMs = intervalInMillis; + + if (SdkLevel.isAtLeastV() && extListenParams != null + && extListenParams.getVendorData() != null) { + extListenInfo.vendorData = + HalAidlUtil.frameworkToHalOuiKeyedDataList(extListenParams.getVendorData()); + } + + try { + mISupplicantP2pIface.configureExtListenWithParams(extListenInfo); + return true; + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } catch (ServiceSpecificException e) { + handleServiceSpecificException(e, methodStr); + } + return false; + } + /** * Set P2P Listen channel. * @@ -2559,4 +2700,64 @@ public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { "Invalid WPS config method: " + configMethod); } } + + /** + * Terminate the supplicant daemon & wait for its death. + */ + public void terminate() { + synchronized (mLock) { + final String methodStr = "terminate"; + if (!checkSupplicantAndLogFailure(methodStr)) { + return; + } + Log.i(TAG, "Terminate supplicant service"); + try { + mWaitForDeathLatch = new CountDownLatch(1); + mISupplicant.terminate(); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + } + } + + // Wait for death recipient to confirm the service death. + try { + if (!mWaitForDeathLatch.await(WAIT_FOR_DEATH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + Log.w(TAG, "Timed out waiting for confirmation of supplicant death"); + supplicantServiceDiedHandler(); + } else { + Log.d(TAG, "Got service death confirmation"); + } + } catch (InterruptedException e) { + Log.w(TAG, "Failed to wait for supplicant death"); + } + } + + /** + * Registers a death notification for supplicant. + * @return Returns true on success. + */ + public boolean registerDeathHandler(@NonNull WifiNative.SupplicantDeathEventHandler handler) { + synchronized (mLock) { + if (mDeathEventHandler != null) { + Log.e(TAG, "Death handler already present"); + } + mDeathEventHandler = handler; + return true; + } + } + + /** + * Deregisters a death notification for supplicant. + * @return Returns true on success. + */ + public boolean deregisterDeathHandler() { + synchronized (mLock) { + if (mDeathEventHandler == null) { + Log.e(TAG, "No Death handler present"); + } + mDeathEventHandler = null; + return true; + } + } + } diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImpl.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImpl.java index 2aa45f36f1..7f28476699 100644 --- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImpl.java +++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImpl.java @@ -17,6 +17,7 @@ package com.android.server.wifi.p2p; import android.annotation.NonNull; +import android.annotation.Nullable; import android.hardware.wifi.supplicant.V1_0.ISupplicant; import android.hardware.wifi.supplicant.V1_0.ISupplicantIface; import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork; @@ -34,6 +35,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pManager; @@ -586,11 +588,11 @@ public class SupplicantP2pIfaceHalHidlImpl implements ISupplicantP2pIfaceHal { } protected static void logd(String s) { - if (sVerboseLoggingEnabled) Log.d(TAG, s); + if (sVerboseLoggingEnabled) Log.d(TAG, s, null); } protected static void logw(String s) { - Log.w(TAG, s); + Log.w(TAG, s, null); } protected static <S> void logCompletion(String operation, int code, String debugMessage) { @@ -1472,21 +1474,13 @@ public class SupplicantP2pIfaceHalHidlImpl implements ISupplicantP2pIfaceHal { /** - * Configure Extended Listen Timing. - * - * If enabled, listen state must be entered every |intervalInMillis| for at - * least |periodInMillis|. Both values have acceptable range of 1-65535 - * (with interval obviously having to be larger than or equal to duration). - * If the P2P module is not idle at the time the Extended Listen Timing - * timeout occurs, the Listen State operation must be skipped. - * - * @param enable Enables or disables listening. - * @param periodInMillis Period in milliseconds. - * @param intervalInMillis Interval in milliseconds. + * Configure Extended Listen Timing. See comments for + * {@link ISupplicantP2pIfaceHal#configureExtListen(boolean, int, int, WifiP2pExtListenParams)} * * @return true, if operation was successful. */ - public boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis) { + public boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis, + @Nullable WifiP2pExtListenParams extListenParams) { if (enable && intervalInMillis < periodInMillis) { return false; } diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pMetrics.java b/service/java/com/android/server/wifi/p2p/WifiP2pMetrics.java index 0ae1bf76fd..b2d2ea740d 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pMetrics.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pMetrics.java @@ -190,24 +190,8 @@ public class WifiP2pMetrics { } else { sb.append(StringUtil.calendarToString(c)); } - sb.append(", connectionType="); - switch (event.connectionType) { - case P2pConnectionEvent.CONNECTION_FRESH: - sb.append("FRESH"); - break; - case P2pConnectionEvent.CONNECTION_REINVOKE: - sb.append("REINVOKE"); - break; - case P2pConnectionEvent.CONNECTION_LOCAL: - sb.append("LOCAL"); - break; - case P2pConnectionEvent.CONNECTION_FAST: - sb.append("FAST"); - break; - default: - sb.append("UNKNOWN"); - break; - } + sb.append(", connectionType=").append( + getconnectionTypeToString(event.connectionType)); sb.append(", wpsMethod="); switch (event.wpsMethod) { case P2pConnectionEvent.WPS_NA: @@ -231,19 +215,7 @@ public class WifiP2pMetrics { } sb.append(", durationTakenToConnectMillis="); sb.append(event.durationTakenToConnectMillis); - sb.append(", groupRole="); - switch (event.groupRole) { - case GroupEvent.GROUP_OWNER: - sb.append("OWNER"); - break; - case GroupEvent.GROUP_CLIENT: - sb.append("CLIENT"); - break; - default: - sb.append("UNKNOWN DURING CONNECT"); - break; - } - + sb.append(", groupRole=").append(getGroupRoleToString(event.groupRole)); sb.append(", tryCount="); sb.append(event.tryCount); sb.append(", inviteToNeg="); @@ -258,40 +230,9 @@ public class WifiP2pMetrics { sb.append(event.staFrequencyMhz); sb.append(", uid="); sb.append(event.uid); - sb.append(", connectivityLevelFailureCode="); - switch (event.connectivityLevelFailureCode) { - case P2pConnectionEvent.CLF_NONE: - sb.append("NONE"); - break; - case P2pConnectionEvent.CLF_TIMEOUT: - sb.append("TIMEOUT"); - break; - case P2pConnectionEvent.CLF_CANCEL: - sb.append("CANCEL"); - break; - case P2pConnectionEvent.CLF_PROV_DISC_FAIL: - sb.append("PROV_DISC_FAIL"); - break; - case P2pConnectionEvent.CLF_INVITATION_FAIL: - sb.append("INVITATION_FAIL"); - break; - case P2pConnectionEvent.CLF_USER_REJECT: - sb.append("USER_REJECT"); - break; - case P2pConnectionEvent.CLF_NEW_CONNECTION_ATTEMPT: - sb.append("NEW_CONNECTION_ATTEMPT"); - break; - case P2pConnectionEvent.CLF_GROUP_REMOVED: - sb.append("GROUP_REMOVED"); - break; - case P2pConnectionEvent.CLF_CREATE_GROUP_FAILED: - sb.append("CREATE_GROUP_FAILED"); - break; - case P2pConnectionEvent.CLF_UNKNOWN: - default: - sb.append("UNKNOWN"); - break; - } + sb.append(", connectivityLevelFailureCode=").append( + getConnectivityLevelFailureCodeToString( + event.connectivityLevelFailureCode)); if (event == mCurrentConnectionEvent) { sb.append(" CURRENTLY OPEN EVENT"); } @@ -342,6 +283,58 @@ public class WifiP2pMetrics { } } + private String getconnectionTypeToString(int connectionType) { + switch (connectionType) { + case P2pConnectionEvent.CONNECTION_FRESH: + return "FRESH"; + case P2pConnectionEvent.CONNECTION_REINVOKE: + return "REINVOKE"; + case P2pConnectionEvent.CONNECTION_LOCAL: + return "LOCAL"; + case P2pConnectionEvent.CONNECTION_FAST: + return "FAST"; + default: + return "UNKNOWN"; + } + } + + private String getGroupRoleToString(int groupRole) { + switch (groupRole) { + case GroupEvent.GROUP_OWNER: + return "OWNER"; + case GroupEvent.GROUP_CLIENT: + return "CLIENT"; + default: + return "UNKNOWN DURING CONNECT"; + } + } + + private String getConnectivityLevelFailureCodeToString(int connectivityLevelFailureCode) { + switch (connectivityLevelFailureCode) { + case P2pConnectionEvent.CLF_NONE: + return "NONE"; + case P2pConnectionEvent.CLF_TIMEOUT: + return "TIMEOUT"; + case P2pConnectionEvent.CLF_CANCEL: + return "CANCEL"; + case P2pConnectionEvent.CLF_PROV_DISC_FAIL: + return "PROV_DISC_FAIL"; + case P2pConnectionEvent.CLF_INVITATION_FAIL: + return "INVITATION_FAIL"; + case P2pConnectionEvent.CLF_USER_REJECT: + return "USER_REJECT"; + case P2pConnectionEvent.CLF_NEW_CONNECTION_ATTEMPT: + return "NEW_CONNECTION_ATTEMPT"; + case P2pConnectionEvent.CLF_GROUP_REMOVED: + return "GROUP_REMOVED"; + case P2pConnectionEvent.CLF_CREATE_GROUP_FAILED: + return "CREATE_GROUP_FAILED"; + case P2pConnectionEvent.CLF_UNKNOWN: + default: + return "UNKNOWN"; + } + } + /** Increment total number of peer scans */ public void incrementPeerScans() { synchronized (mLock) { @@ -392,6 +385,24 @@ public class WifiP2pMetrics { public void startConnectionEvent(int connectionType, WifiP2pConfig config, int groupRole, int uid) { synchronized (mLock) { + StringBuilder stringBuilder = new StringBuilder("Start connection event"); + if (mCurrentConnectionEvent == null) { + stringBuilder.append(", mCurrentConnectionEvent:null"); + } else { + stringBuilder.append(", curConnectionType:") + .append(getconnectionTypeToString(mCurrentConnectionEvent.connectionType)) + .append(", curGroupRole:") + .append(getGroupRoleToString(mCurrentConnectionEvent.groupRole)) + .append(", curUid:").append(mCurrentConnectionEvent.uid) + .append(", curConnectivityLevelFailureCode:") + .append(getConnectivityLevelFailureCodeToString( + mCurrentConnectionEvent.connectivityLevelFailureCode)); + } + stringBuilder.append(", startConnectionType:") + .append(getconnectionTypeToString(connectionType)) + .append(", startGroupRole:").append(getGroupRoleToString(groupRole)) + .append(", startUid:").append(uid); + Log.d(TAG, stringBuilder.toString()); // handle overlapping connection event first. if (mCurrentConnectionEvent != null) { endConnectionEvent(P2pConnectionEvent.CLF_NEW_CONNECTION_ATTEMPT); @@ -443,6 +454,23 @@ public class WifiP2pMetrics { */ public void endConnectionEvent(int failure) { synchronized (mLock) { + StringBuilder stringBuilder = new StringBuilder("End connection event"); + if (mCurrentConnectionEvent == null) { + stringBuilder.append(", mCurrentConnectionEvent:null"); + } else { + stringBuilder.append(", curConnectionType:") + .append(getconnectionTypeToString(mCurrentConnectionEvent.connectionType)) + .append(", curGroupRole:") + .append(getGroupRoleToString(mCurrentConnectionEvent.groupRole)) + .append(", curUid:") + .append(mCurrentConnectionEvent.uid) + .append(", curConnectivityLevelFailureCode:") + .append(getConnectivityLevelFailureCodeToString( + mCurrentConnectionEvent.connectivityLevelFailureCode)); + } + stringBuilder.append(", endConnectivityLevelFailureCode:") + .append(getConnectivityLevelFailureCodeToString(failure)); + Log.d(TAG, stringBuilder.toString()); if (mCurrentConnectionEvent == null) { // Reinvoking a group with invitation will be handled in supplicant. // There won't be a connection starting event in framework. diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pNative.java b/service/java/com/android/server/wifi/p2p/WifiP2pNative.java index 89284e9c1b..c32d593836 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pNative.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pNative.java @@ -24,6 +24,8 @@ import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.ScanResult; import android.net.wifi.nl80211.WifiNl80211Manager; import android.net.wifi.p2p.WifiP2pConfig; +import android.net.wifi.p2p.WifiP2pDiscoveryConfig; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pManager; @@ -35,9 +37,11 @@ import android.util.Log; import com.android.server.wifi.HalDeviceManager; import com.android.server.wifi.PropertyService; +import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiMetrics; import com.android.server.wifi.WifiNative; import com.android.server.wifi.WifiVendorHal; +import com.android.wifi.flags.FeatureFlags; import java.util.HashSet; import java.util.List; @@ -57,9 +61,26 @@ public class WifiP2pNative { private final HalDeviceManager mHalDeviceManager; private final PropertyService mPropertyService; private final WifiVendorHal mWifiVendorHal; + private final WifiInjector mWifiInjector; + private final FeatureFlags mFeatureFlags; + private final Object mLock = new Object(); + private WifiNative.Iface mP2pIface; private String mP2pIfaceName; private InterfaceDestroyedListenerInternal mInterfaceDestroyedListener; + /** + * Death handler for the supplicant daemon. + */ + private class SupplicantDeathHandlerInternal implements WifiNative.SupplicantDeathEventHandler { + @Override + public void onDeath() { + if (mP2pIface != null) { + Log.i(TAG, "wpa_supplicant died. Cleaning up internal state."); + mInterfaceDestroyedListener.teardownAndInvalidate(mP2pIface.name); + mWifiMetrics.incrementNumSupplicantCrashes(); + } + } + } // Internal callback registered to HalDeviceManager. private class InterfaceDestroyedListenerInternal implements @@ -74,22 +95,35 @@ public class WifiP2pNative { } public void teardownAndInvalidate(@Nullable String ifaceName) { - if (!TextUtils.isEmpty(ifaceName)) { - mSupplicantP2pIfaceHal.teardownIface(ifaceName); + synchronized (mLock) { + if (mFeatureFlags.d2dWhenInfraStaOff() + && !mSupplicantP2pIfaceHal.deregisterDeathHandler()) { + Log.i(TAG, "Failed to deregister p2p supplicant death handler"); + } + if (!TextUtils.isEmpty(ifaceName)) { + mSupplicantP2pIfaceHal.teardownIface(ifaceName); + if (mP2pIface != null) { + mWifiNative.teardownP2pIface(mP2pIface.id); + } + } + mP2pIfaceName = null; + mP2pIface = null; + mValid = false; + Log.i(TAG, "teardownAndInvalidate is completed"); } - mP2pIfaceName = null; - mValid = false; } @Override public void onDestroyed(String ifaceName) { - Log.d(TAG, "P2P InterfaceDestroyedListener " + ifaceName); - if (!mValid) { - Log.d(TAG, "Ignoring stale interface destroyed listener"); - return; + synchronized (mLock) { + Log.d(TAG, "P2P InterfaceDestroyedListener " + ifaceName); + if (!mValid) { + Log.d(TAG, "Ignoring stale interface destroyed listener"); + return; + } + teardownAndInvalidate(ifaceName); + mExternalListener.onDestroyed(ifaceName); } - teardownAndInvalidate(ifaceName); - mExternalListener.onDestroyed(ifaceName); } } @@ -100,7 +134,8 @@ public class WifiP2pNative { WifiVendorHal wifiVendorHal, SupplicantP2pIfaceHal p2pIfaceHal, HalDeviceManager halDeviceManager, - PropertyService propertyService) { + PropertyService propertyService, + WifiInjector wifiInjector) { mWifiNative = wifiNative; mWifiMetrics = wifiMetrics; mWifiNl80211Manager = wifiNl80211Manager; @@ -108,6 +143,8 @@ public class WifiP2pNative { mSupplicantP2pIfaceHal = p2pIfaceHal; mHalDeviceManager = halDeviceManager; mPropertyService = propertyService; + mWifiInjector = wifiInjector; + mFeatureFlags = wifiInjector.getDeviceConfigFacade().getFeatureFlags(); } /** @@ -148,8 +185,11 @@ public class WifiP2pNative { /** * Close supplicant connection. */ - public void closeSupplicantConnection() { - // Nothing to do for HAL. + public void stopP2pSupplicantIfNecessary() { + if (mFeatureFlags.d2dWhenInfraStaOff() + && mSupplicantP2pIfaceHal.isInitializationStarted()) { + mSupplicantP2pIfaceHal.terminate(); + } } /** @@ -159,8 +199,8 @@ public class WifiP2pNative { return mHalDeviceManager.isSupported(); } - private static final String P2P_IFACE_NAME = "p2p0"; - private static final String P2P_INTERFACE_PROPERTY = "wifi.direct.interface"; + public static final String P2P_IFACE_NAME = "p2p0"; + public static final String P2P_INTERFACE_PROPERTY = "wifi.direct.interface"; /** * Helper function to handle creation of P2P iface. @@ -192,39 +232,58 @@ public class WifiP2pNative { public String setupInterface( @Nullable HalDeviceManager.InterfaceDestroyedListener destroyedListener, @NonNull Handler handler, @NonNull WorkSource requestorWs) { - Log.d(TAG, "Setup P2P interface"); - if (mP2pIfaceName == null) { - mInterfaceDestroyedListener = (null == destroyedListener) - ? null - : new InterfaceDestroyedListenerInternal(destroyedListener); - String ifaceName = createP2pIface(handler, requestorWs); - if (ifaceName == null) { - Log.e(TAG, "Failed to create P2p iface"); - if (mHalDeviceManager.isItPossibleToCreateIface(HDM_CREATE_IFACE_P2P, - requestorWs)) { - mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToHal(); + synchronized (mLock) { + Log.d(TAG, "Setup P2P interface"); + if (mP2pIfaceName == null) { + mInterfaceDestroyedListener = (null == destroyedListener) + ? null + : new InterfaceDestroyedListenerInternal(destroyedListener); + if (mFeatureFlags.d2dWhenInfraStaOff()) { + mP2pIface = mWifiNative.createP2pIface(mInterfaceDestroyedListener, handler, + requestorWs); + if (mP2pIface != null) { + mP2pIfaceName = mP2pIface.name; + } + } else { + mP2pIfaceName = createP2pIface(handler, requestorWs); } - return null; - } - if (!waitForSupplicantConnection()) { - Log.e(TAG, "Failed to connect to supplicant"); - teardownInterface(); - mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToSupplicant(); - return null; - } - if (!mSupplicantP2pIfaceHal.setupIface(ifaceName)) { - Log.e(TAG, "Failed to setup P2p iface in supplicant"); - teardownInterface(); - mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToSupplicant(); - return null; + if (mP2pIfaceName == null) { + Log.e(TAG, "Failed to create P2p iface"); + if (mHalDeviceManager.isItPossibleToCreateIface(HDM_CREATE_IFACE_P2P, + requestorWs)) { + mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToHal(); + } + return null; + } + if (!waitForSupplicantConnection()) { + Log.e(TAG, "Failed to connect to supplicant"); + teardownInterface(); + mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToSupplicant(); + return null; + } + if (!mSupplicantP2pIfaceHal.setupIface(mP2pIfaceName)) { + Log.e(TAG, "Failed to setup P2p iface in supplicant"); + teardownInterface(); + mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToSupplicant(); + return null; + } + if (mFeatureFlags.d2dWhenInfraStaOff() + && !mSupplicantP2pIfaceHal.registerDeathHandler( + new SupplicantDeathHandlerInternal())) { + Log.e(TAG, "Failed to register supplicant death handler" + + "(because hidl supplicant?)"); + teardownInterface(); + mWifiMetrics.incrementNumSetupP2pInterfaceFailureDueToSupplicant(); + return null; + } + Log.i(TAG, "P2P interface setup completed"); + return mP2pIfaceName; + } else { + Log.i(TAG, "P2P interface already exists"); + return mHalDeviceManager.isSupported() + ? mP2pIfaceName + : mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); } - Log.i(TAG, "P2P interface setup completed"); - return ifaceName; - } else { - Log.i(TAG, "P2P interface already exists"); - return mHalDeviceManager.isSupported() - ? mP2pIfaceName - : mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); } } @@ -232,20 +291,25 @@ public class WifiP2pNative { * Teardown P2p interface. */ public void teardownInterface() { - Log.d(TAG, "Teardown P2P interface"); - if (mHalDeviceManager.isSupported()) { - if (mP2pIfaceName != null) { - mHalDeviceManager.removeP2pIface(mP2pIfaceName); + synchronized (mLock) { + Log.d(TAG, "Teardown P2P interface:" + mP2pIfaceName); + if (mHalDeviceManager.isSupported()) { + if (mP2pIfaceName != null) { + mHalDeviceManager.removeP2pIface(mP2pIfaceName); + Log.i(TAG, "P2P interface teardown completed"); + if (!mFeatureFlags.d2dWhenInfraStaOff()) { + if (null != mInterfaceDestroyedListener) { + mInterfaceDestroyedListener.teardownAndInvalidate(mP2pIfaceName); + } + } + } + } else { + Log.i(TAG, "HAL is not supported. Destroy listener for the interface."); + String ifaceName = mPropertyService.getString(P2P_INTERFACE_PROPERTY, + P2P_IFACE_NAME); if (null != mInterfaceDestroyedListener) { - mInterfaceDestroyedListener.teardownAndInvalidate(mP2pIfaceName); + mInterfaceDestroyedListener.teardownAndInvalidate(ifaceName); } - Log.i(TAG, "P2P interface teardown completed"); - } - } else { - Log.i(TAG, "HAL is not supported. Destroy listener for the interface."); - String ifaceName = mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); - if (null != mInterfaceDestroyedListener) { - mInterfaceDestroyedListener.teardownAndInvalidate(ifaceName); } } } @@ -254,12 +318,14 @@ public class WifiP2pNative { * Replace requestorWs in-place when iface is already enabled. */ public boolean replaceRequestorWs(WorkSource requestorWs) { - if (mHalDeviceManager.isSupported()) { - if (mP2pIfaceName == null) return false; - return mHalDeviceManager.replaceRequestorWsForP2pIface(mP2pIfaceName, requestorWs); - } else { - Log.i(TAG, "HAL is not supported. Ignore replace requestorWs"); - return true; + synchronized (mLock) { + if (mHalDeviceManager.isSupported()) { + if (mP2pIfaceName == null) return false; + return mHalDeviceManager.replaceRequestorWsForP2pIface(mP2pIfaceName, requestorWs); + } else { + Log.i(TAG, "HAL is not supported. Ignore replace requestorWs"); + return true; + } } } @@ -469,6 +535,19 @@ public class WifiP2pNative { } /** + * Initiate a P2P service discovery with config parameters. + * + * @param config The config parameters to initiate P2P discovery. + * @param timeout The maximum amount of time to be spent in performing discovery. + * Set to 0 to indefinitely continue discovery until an explicit + * |stopFind| is sent. + * @return boolean value indicating whether the operation was successful. + */ + public boolean p2pFindWithParams(@NonNull WifiP2pDiscoveryConfig config, int timeout) { + return mSupplicantP2pIfaceHal.findWithParams(config, timeout); + } + + /** * Stop an ongoing P2P service discovery. * * @return boolean value indicating whether operation was successful. @@ -489,11 +568,13 @@ public class WifiP2pNative { * @param enable Enables or disables listening. * @param period Period in milliseconds. * @param interval Interval in milliseconds. + * @param extListenParams Additional parameter struct for this request. * * @return true, if operation was successful. */ - public boolean p2pExtListen(boolean enable, int period, int interval) { - return mSupplicantP2pIfaceHal.configureExtListen(enable, period, interval); + public boolean p2pExtListen(boolean enable, int period, int interval, + @Nullable WifiP2pExtListenParams extListenParams) { + return mSupplicantP2pIfaceHal.configureExtListen(enable, period, interval, extListenParams); } /** @@ -919,9 +1000,11 @@ public class WifiP2pNative { /** Indicate whether or not 5GHz/6GHz DBS is supported. */ public boolean is5g6gDbsSupported() { - if (mP2pIfaceName == null) return false; - if (!mHalDeviceManager.isSupported()) return false; - return mHalDeviceManager.is5g6gDbsSupportedOnP2pIface(mP2pIfaceName); + synchronized (mLock) { + if (mP2pIfaceName == null) return false; + if (!mHalDeviceManager.isSupported()) return false; + return mHalDeviceManager.is5g6gDbsSupportedOnP2pIface(mP2pIfaceName); + } } /** diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java index f16e1e249f..dd50fff514 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java @@ -21,6 +21,7 @@ import static android.net.wifi.p2p.WifiP2pConfig.GROUP_CLIENT_IP_PROVISIONING_MO import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL; import static com.android.net.module.util.Inet4AddressUtils.netmaskToPrefixLength; +import static com.android.server.wifi.WifiSettingsConfigStore.D2D_ALLOWED_WHEN_INFRA_STA_DISABLED; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_DEVICE_ADDRESS; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_DEVICE_NAME; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_PENDING_FACTORY_RESET; @@ -50,6 +51,7 @@ import android.net.MacAddress; import android.net.NetworkInfo; import android.net.NetworkStack; import android.net.StaticIpConfiguration; +import android.net.TetheredClient; import android.net.TetheringInterface; import android.net.TetheringManager; import android.net.TetheringManager.TetheringEventCallback; @@ -63,10 +65,13 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WpsInfo; +import android.net.wifi.p2p.IWifiP2pListener; import android.net.wifi.p2p.IWifiP2pManager; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pDeviceList; +import android.net.wifi.p2p.WifiP2pDiscoveryConfig; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener; @@ -89,6 +94,7 @@ import android.os.Message; import android.os.Messenger; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -96,6 +102,7 @@ import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; import android.text.TextUtils; +import android.util.LocalLog; import android.util.Log; import android.util.SparseArray; import android.view.Display; @@ -121,6 +128,7 @@ import com.android.server.wifi.Clock; import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.HalDeviceManager; import com.android.server.wifi.InterfaceConflictManager; +import com.android.server.wifi.RunnerState; import com.android.server.wifi.WifiDialogManager; import com.android.server.wifi.WifiGlobals; import com.android.server.wifi.WifiInjector; @@ -137,6 +145,7 @@ import com.android.server.wifi.util.StringUtil; import com.android.server.wifi.util.WaitingState; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; +import com.android.wifi.flags.FeatureFlags; import com.android.wifi.resources.R; import java.io.FileDescriptor; @@ -154,6 +163,7 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; @@ -164,6 +174,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.stream.Collectors; /** @@ -181,6 +192,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { @VisibleForTesting public static final String P2P_IDLE_SHUTDOWN_MESSAGE_TIMEOUT_TAG = TAG + " Idle Shutdown Message Timeout"; + private final LocalLog mThreadLocalLog; + private final int mThreshold; private boolean mVerboseLoggingEnabled = false; private boolean mVerboseHalLoggingEnabled = false; private static final String NETWORK_TYPE = "WIFI_P2P"; @@ -234,6 +247,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { private final WifiP2pNative mWifiNative; private final LastCallerInfoManager mLastCallerInfoManager; private HalDeviceManager mHalDeviceManager; + private final FeatureFlags mFeatureFlags; private static final Boolean JOIN_GROUP = true; private static final Boolean FORM_GROUP = false; @@ -252,7 +266,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { android.Manifest.permission.ACCESS_WIFI_STATE }; - private static final String[] RECEIVER_PERMISSIONS_FOR_TETHERING = { + private static final String[] RECEIVER_PERMISSIONS_MAINLINE_NETWORK_STACK = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK }; @@ -338,6 +352,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { // Delayed message to timeout group creation public static final int P2P_REJECTION_RESUME_AFTER_DELAY = BASE + 37; + + static final int TETHER_INTERFACE_CLIENTS_CHANGED = BASE + 38; + public static final int ENABLED = 1; public static final int DISABLED = 0; @@ -444,6 +461,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { @VisibleForTesting static final String GO_EAPOL_IP_RANGE_DEFAULT_END_ADDRESS = "192.168.49.254"; + private final RemoteCallbackList<IWifiP2pListener> mWifiP2pListeners = + new RemoteCallbackList<>(); + /** * Error code definition. * see the Table.8 in the WiFi Direct specification for the detail. @@ -657,6 +677,19 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { private final Clock mClock; + private class D2DAllowWhenInfraStaDisabledValueListener + implements WifiSettingsConfigStore.OnSettingsChangedListener<Boolean> { + @Override + public void onSettingsChanged(@NonNull WifiSettingsConfigStore.Key<Boolean> key, + @Nullable Boolean newValue) { + if (!mP2pStateMachine.isWifiP2pAvailable()) { + Log.i(TAG, "D2d isn't allowed anymore when infra sta is disabled"); + mP2pStateMachine.sendMessage(DISABLE_P2P); + mP2pStateMachine.checkAndSendP2pStateChangedBroadcast(); + } + } + } + public WifiP2pServiceImpl(Context context, WifiInjector wifiInjector) { mContext = context; mWifiInjector = wifiInjector; @@ -670,17 +703,20 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mUserManager = mWifiInjector.getUserManager(); mInterfaceConflictManager = mWifiInjector.getInterfaceConflictManager(); mClock = mWifiInjector.getClock(); + mThreadLocalLog = mWifiInjector.getWifiHandlerLocalLog(); + mThreshold = mContext.getResources().getInteger( + R.integer.config_wifiConfigurationWifiRunnerThresholdInMs); mDetailedState = NetworkInfo.DetailedState.IDLE; mP2pSupported = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_WIFI_DIRECT); - HandlerThread wifiP2pThread = mWifiInjector.getWifiP2pServiceHandlerThread(); mClientHandler = new ClientHandler(TAG, wifiP2pThread.getLooper()); mWifiNative = mWifiInjector.getWifiP2pNative(); mLastCallerInfoManager = mWifiInjector.getLastCallerInfoManager(); mHalDeviceManager = mWifiInjector.getHalDeviceManager(); + mFeatureFlags = mWifiInjector.getDeviceConfigFacade().getFeatureFlags(); mP2pStateMachine = new P2pStateMachine(TAG, wifiP2pThread.getLooper(), mP2pSupported); mP2pStateMachine.setDbg(false); // can enable for very verbose logs mP2pStateMachine.start(); @@ -1064,6 +1100,208 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return mWifiNative.getSupportedFeatures(); } + /** + * See {@link WifiP2pManager#registerWifiP2pListener(Executor, WifiP2pManager.WifiP2pListener)} + */ + @Override + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public void registerWifiP2pListener(IWifiP2pListener listener, String packageName, + Bundle extras) { + if (!SdkLevel.isAtLeastT()) { + throw new UnsupportedOperationException(); + } + if (listener == null) { + throw new IllegalArgumentException("listener should not be null"); + } + mWifiPermissionsUtil.enforceNearbyDevicesPermission( + extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE), false, + TAG + " registerWifiP2pListener"); + Log.i(TAG, "registerWifiP2pListener uid=" + Binder.getCallingUid()); + mWifiP2pListeners.register(listener); + } + + /** + * See {@link WifiP2pManager#unregisterWifiP2pListener(WifiP2pManager.WifiP2pListener)} + */ + @Override + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public void unregisterWifiP2pListener(IWifiP2pListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + Log.i(TAG, "unregisterWifiP2pListener uid=" + Binder.getCallingUid()); + mWifiP2pListeners.unregister(listener); + } + + private void onP2pStateChanged(@WifiP2pManager.WifiP2pState int state) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onP2pStateChanged(state); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onP2pStateChanged" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onDiscoveryStateChanged(@WifiP2pManager.WifiP2pDiscoveryState int state) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onDiscoveryStateChanged(state); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onDiscoveryStateChanged" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onListenStateChanged(@WifiP2pManager.WifiP2pListenState int state) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onListenStateChanged(state); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onListenStateChanged" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onDeviceConfigurationChanged(WifiP2pDevice p2pDevice) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onDeviceConfigurationChanged(p2pDevice); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onDeviceConfigurationChanged" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onPeerListChanged(WifiP2pDeviceList p2pDeviceList) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onPeerListChanged(p2pDeviceList); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onPeerListChanged" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onPersistentGroupsChanged(WifiP2pGroupList p2pGroupList) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onPersistentGroupsChanged(p2pGroupList); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onPersistentGroupsChanged" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onGroupCreating() { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onGroupCreating(); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onGroupCreating" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onGroupNegotiationRejectedByUser() { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onGroupNegotiationRejectedByUser(); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onGroupNegotiationRejectedByUser" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onGroupCreationFailed(@WifiP2pManager.GroupCreationFailureReason int reason) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onGroupCreationFailed(reason); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onGroupCreationFailed" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onGroupCreated(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onGroupCreated(p2pInfo, p2pGroup); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onGroupCreated" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onPeerClientJoined(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onPeerClientJoined(p2pInfo, p2pGroup); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onPeerClientJoined" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onPeerClientDisconnected(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onPeerClientDisconnected(p2pInfo, + p2pGroup); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onPeerClientDisconnected" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onFrequencyChanged(WifiP2pInfo p2pInfo, WifiP2pGroup p2pGroup) { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onFrequencyChanged(p2pInfo, p2pGroup); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onFrequencyChanged" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + + private void onGroupRemoved() { + int numCallbacks = mWifiP2pListeners.beginBroadcast(); + for (int i = 0; i < numCallbacks; i++) { + try { + mWifiP2pListeners.getBroadcastItem(i).onGroupRemoved(); + } catch (RemoteException e) { + Log.e(TAG, "Failure calling onGroupRemoved" + e); + } + } + mWifiP2pListeners.finishBroadcast(); + } + private boolean getWfdPermission(int uid) { WifiPermissionsWrapper wifiPermissionsWrapper = mWifiInjector.getWifiPermissionsWrapper(); return wifiPermissionsWrapper.getUidPermission( @@ -1122,35 +1360,45 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { */ private class P2pStateMachine extends StateMachine { - private final DefaultState mDefaultState = new DefaultState(); - private final P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState(); - private final P2pDisablingState mP2pDisablingState = new P2pDisablingState(); + private final DefaultState mDefaultState = new DefaultState(mThreshold, mThreadLocalLog); + private final P2pNotSupportedState mP2pNotSupportedState = + new P2pNotSupportedState(mThreshold, mThreadLocalLog); + private final P2pDisablingState mP2pDisablingState = + new P2pDisablingState(mThreshold, mThreadLocalLog); private final P2pDisabledContainerState mP2pDisabledContainerState = - new P2pDisabledContainerState(); - private final P2pDisabledState mP2pDisabledState = new P2pDisabledState(); + new P2pDisabledContainerState(mThreshold, mThreadLocalLog); + private final P2pDisabledState mP2pDisabledState = + new P2pDisabledState(mThreshold, mThreadLocalLog); private final WaitingState mWaitingState = new WaitingState(this); - private final P2pEnabledState mP2pEnabledState = new P2pEnabledState(); + private final P2pEnabledState mP2pEnabledState = + new P2pEnabledState(mThreshold, mThreadLocalLog); // Inactive is when p2p is enabled with no connectivity - private final InactiveState mInactiveState = new InactiveState(); - private final GroupCreatingState mGroupCreatingState = new GroupCreatingState(); + private final InactiveState mInactiveState = new InactiveState(mThreshold, mThreadLocalLog); + private final GroupCreatingState mGroupCreatingState = + new GroupCreatingState(mThreshold, mThreadLocalLog); private final UserAuthorizingInviteRequestState mUserAuthorizingInviteRequestState = - new UserAuthorizingInviteRequestState(); + new UserAuthorizingInviteRequestState(mThreshold, mThreadLocalLog); private final UserAuthorizingNegotiationRequestState mUserAuthorizingNegotiationRequestState = - new UserAuthorizingNegotiationRequestState(); + new UserAuthorizingNegotiationRequestState(mThreshold, mThreadLocalLog); private final ProvisionDiscoveryState mProvisionDiscoveryState = - new ProvisionDiscoveryState(); - private final GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState(); - private final FrequencyConflictState mFrequencyConflictState = new FrequencyConflictState(); - - private final GroupCreatedState mGroupCreatedState = new GroupCreatedState(); + new ProvisionDiscoveryState(mThreshold, mThreadLocalLog); + private final GroupNegotiationState mGroupNegotiationState = + new GroupNegotiationState(mThreshold, mThreadLocalLog); + private final FrequencyConflictState mFrequencyConflictState = + new FrequencyConflictState(mThreshold, mThreadLocalLog); + + private final GroupCreatedState mGroupCreatedState = + new GroupCreatedState(mThreshold, mThreadLocalLog); private final UserAuthorizingJoinState mUserAuthorizingJoinState = - new UserAuthorizingJoinState(); + new UserAuthorizingJoinState(mThreshold, mThreadLocalLog); private final OngoingGroupRemovalState mOngoingGroupRemovalState = - new OngoingGroupRemovalState(); - private final P2pRejectWaitState mP2pRejectWaitState = new P2pRejectWaitState(); + new OngoingGroupRemovalState(mThreshold, mThreadLocalLog); + private final P2pRejectWaitState mP2pRejectWaitState = + new P2pRejectWaitState(mThreshold, mThreadLocalLog); private final WifiP2pMonitor mWifiMonitor = mWifiInjector.getWifiP2pMonitor(); + private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList(); private String mInterfaceName; private TetheringEventCallback mTetheringEventCallback = @@ -1164,6 +1412,12 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { + " callback for ifaceList: " + ifaceList); sendMessage(TETHER_INTERFACE_STATE_CHANGED, ifaceList); } + @Override + public void onClientsChanged(Collection<TetheredClient> clients) { + synchronized (mLock) { + sendMessage(TETHER_INTERFACE_CLIENTS_CHANGED, clients); + } + } }; private final List<CoexUnsafeChannel> mCoexUnsafeChannels = new ArrayList<>(); @@ -1249,8 +1503,17 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mIsWifiEnabled = true; } else { mIsWifiEnabled = false; - // Teardown P2P if it's up already. - sendMessage(DISABLE_P2P); + // P2P can be established even when infra STA is disabled. + // This implies that STA might be torn down by P2P + // (e.g., if STA was active initially). + // Check availability to determine whether to stop P2P + // upon receiving a Wi-Fi off signal. + if (!isWifiP2pAvailable()) { + sendMessage(DISABLE_P2P); + } else { + Log.i(TAG, "Infra STA is disabled but keep P2P on since" + + " d2d is allowed when infra sta is disabled"); + } } if (wifistate == WifiManager.WIFI_STATE_ENABLED || wifistate == WifiManager.WIFI_STATE_DISABLING) { @@ -1258,6 +1521,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } } }, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); + mSettingsConfigStore.registerChangeListener(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED, + new D2DAllowWhenInfraStaDisabledValueListener(), this.getHandler()); // Register for location mode on/off broadcasts mContext.registerReceiver(new BroadcastReceiver() { @Override @@ -1398,6 +1663,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return "SET_MIRACAST_MODE"; case TETHER_INTERFACE_STATE_CHANGED: return "TETHER_INTERFACE_STATE_CHANGED"; + case TETHER_INTERFACE_CLIENTS_CHANGED: + return "TETHER_INTERFACE_CLIENTS_CHANGED"; case UPDATE_P2P_DISALLOWED_CHANNELS: return "UPDATE_P2P_DISALLOWED_CHANNELS"; case WifiP2pManager.ADD_EXTERNAL_APPROVER: @@ -1538,6 +1805,10 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return "WifiP2pManager.SET_VENDOR_ELEMENTS"; case P2P_REJECTION_RESUME_AFTER_DELAY: return "P2P_REJECTION_RESUME_AFTER_DELAY"; + case RunnerState.STATE_ENTER_CMD: + return "Enter"; + case RunnerState.STATE_EXIT_CMD: + return "Exit"; default: return "what:" + what; } @@ -1783,9 +2054,17 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } } - class DefaultState extends State { + class DefaultState extends RunnerState { + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + DefaultState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: @@ -2085,6 +2364,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { case IPC_PROVISIONING_SUCCESS: case IPC_PROVISIONING_FAILURE: case TETHER_INTERFACE_STATE_CHANGED: + case TETHER_INTERFACE_CLIENTS_CHANGED: case UPDATE_P2P_DISALLOWED_CHANNELS: case WifiP2pMonitor.P2P_PROV_DISC_FAILURE_EVENT: case SET_MIRACAST_MODE: @@ -2319,11 +2599,37 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public void enterImpl() { + + } + + @Override + public void exitImpl() { + + } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class P2pNotSupportedState extends State { + class P2pNotSupportedState extends RunnerState { + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + P2pNotSupportedState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case WifiP2pManager.DISCOVER_PEERS: @@ -2432,11 +2738,37 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public void enterImpl() { + + } + + @Override + public void exitImpl() { + + } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class P2pDisablingState extends State { + class P2pDisablingState extends RunnerState { + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + P2pDisablingState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT, @@ -2444,7 +2776,12 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case WifiP2pMonitor.SUP_DISCONNECTION_EVENT: @@ -2467,11 +2804,27 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class P2pDisabledContainerState extends State { // split due to b/220588514 + class P2pDisabledContainerState extends RunnerState { + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + P2pDisabledContainerState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); mInterfaceName = null; // reset iface name on disable. @@ -2483,9 +2836,36 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { resetWifiP2pInfo(); mGroup = null; } + + @Override + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message msg) { + return false; + } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class P2pDisabledState extends State { + class P2pDisabledState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + P2pDisabledState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + private void setupInterfaceFeatures() { if (mWifiGlobals.isP2pMacRandomizationSupported()) { Log.i(TAG, "Supported feature: P2P MAC randomization"); @@ -2535,7 +2915,17 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public void enterImpl() { + + } + + @Override + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); boolean wasInWaitingState = WaitingState.wasMessageInWaitingState(message); switch (message.what) { @@ -2654,11 +3044,28 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class P2pEnabledState extends State { + class P2pEnabledState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + P2pEnabledState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); @@ -2677,7 +3084,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case WifiP2pMonitor.SUP_DISCONNECTION_EVENT: @@ -2760,6 +3167,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { int freq = extras.getInt( WifiP2pManager.EXTRA_PARAM_KEY_PEER_DISCOVERY_FREQ, WifiP2pManager.WIFI_P2P_SCAN_FREQ_UNSPECIFIED); + WifiP2pDiscoveryConfig discoveryConfig = (WifiP2pDiscoveryConfig) + extras.getParcelable( + WifiP2pManager.EXTRA_PARAM_KEY_DISCOVERY_CONFIG); boolean hasPermission = false; if (scanType != WifiP2pManager.WIFI_P2P_SCAN_FULL && !isFeatureSupported(WifiP2pManager.FEATURE_FLEXIBLE_DISCOVERY)) { @@ -2792,12 +3202,14 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { apiType = WifiManager.API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS; } else if (scanType == WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ) { apiType = WifiManager.API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY; + } else if (scanType == WifiP2pManager.WIFI_P2P_SCAN_WITH_CONFIG_PARAMS) { + apiType = WifiManager.API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS; } mLastCallerInfoManager.put(apiType, Process.myTid(), uid, 0, packageName, true); // do not send service discovery request while normal find operation. clearSupplicantServiceRequest(); - if (p2pFind(scanType, freq, DISCOVER_TIMEOUT_S)) { + if (p2pFind(scanType, freq, DISCOVER_TIMEOUT_S, discoveryConfig)) { mWifiP2pMetrics.incrementPeerScans(); replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED); sendP2pDiscoveryChangedBroadcast(true); @@ -2997,8 +3409,20 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { break; } int uid = message.sendingUid; + int listenType = message.arg1; + if (listenType == WifiP2pManager.WIFI_P2P_EXT_LISTEN_WITH_PARAMS + && !SdkLevel.isAtLeastV()) { + replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); + break; + } Bundle extras = message.getData() .getBundle(WifiP2pManager.EXTRA_PARAM_KEY_BUNDLE); + WifiP2pExtListenParams extListenParams = SdkLevel.isAtLeastV() + && (listenType == WifiP2pManager.WIFI_P2P_EXT_LISTEN_WITH_PARAMS) + ? extras.getParcelable( + WifiP2pManager.EXTRA_PARAM_KEY_EXT_LISTEN_PARAMS, + WifiP2pExtListenParams.class) + : null; boolean hasPermission; if (isPlatformOrTargetSdkLessThanT(packageName, uid)) { hasPermission = mWifiPermissionsUtil.checkCanAccessWifiDirect( @@ -3021,7 +3445,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mContext.getResources().getInteger( R.integer.config_wifiP2pExtListenPeriodMs), mContext.getResources().getInteger( - R.integer.config_wifiP2pExtListenIntervalMs))) { + R.integer.config_wifiP2pExtListenIntervalMs), + extListenParams)) { replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); sendP2pListenChangedBroadcast(true); } else { @@ -3033,7 +3458,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { Process.myTid(), message.sendingUid, 0, getCallingPkgName(message.sendingUid, message.replyTo), true); if (mVerboseLoggingEnabled) logd(getName() + " stop listen mode"); - if (mWifiNative.p2pExtListen(false, 0, 0)) { + if (mWifiNative.p2pExtListen(false, 0, 0, null)) { replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); sendP2pListenChangedBroadcast(false); } else { @@ -3095,7 +3520,14 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public void exit() { + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } + + @Override + public void exitImpl() { sendP2pDiscoveryChangedBroadcast(false); sendP2pListenChangedBroadcast(false); mUserListenChannel = 0; @@ -3107,9 +3539,19 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } } - class InactiveState extends State { + class InactiveState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + InactiveState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); mPeerAuthorizingTimestamp.clear(); @@ -3119,12 +3561,12 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public void exit() { + public void exitImpl() { cancelIdleShutdown(); } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); // Re-schedule the shutdown timer since we got the new operation. // only handle commands from clients. @@ -3317,6 +3759,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; mSavedPeerConfig.deviceAddress = device.deviceAddress; mSavedPeerConfig.wps.pin = provDisc.pin; + if (SdkLevel.isAtLeastV() && provDisc.getVendorData() != null) { + mSavedPeerConfig.setVendorData(provDisc.getVendorData()); + } notifyP2pProvDiscShowPinRequest(provDisc.pin, device.deviceAddress); mPeers.updateStatus(device.deviceAddress, WifiP2pDevice.INVITED); @@ -3437,8 +3882,20 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { break; } int uid = message.sendingUid; + int listenType = message.arg1; + if (listenType == WifiP2pManager.WIFI_P2P_EXT_LISTEN_WITH_PARAMS + && !SdkLevel.isAtLeastV()) { + replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); + break; + } Bundle extras = message.getData() .getBundle(WifiP2pManager.EXTRA_PARAM_KEY_BUNDLE); + WifiP2pExtListenParams extListenParams = SdkLevel.isAtLeastV() + && (listenType == WifiP2pManager.WIFI_P2P_EXT_LISTEN_WITH_PARAMS) + ? extras.getParcelable( + WifiP2pManager.EXTRA_PARAM_KEY_EXT_LISTEN_PARAMS, + WifiP2pExtListenParams.class) + : null; boolean hasPermission; if (isPlatformOrTargetSdkLessThanT(packageName, uid)) { hasPermission = mWifiPermissionsUtil.checkCanAccessWifiDirect( @@ -3461,7 +3918,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mContext.getResources().getInteger( R.integer.config_wifiP2pExtListenPeriodMs), mContext.getResources().getInteger( - R.integer.config_wifiP2pExtListenIntervalMs))) { + R.integer.config_wifiP2pExtListenIntervalMs), + extListenParams)) { replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); sendP2pListenChangedBroadcast(true); } else { @@ -3473,7 +3931,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { Process.myTid(), message.sendingUid, 0, getCallingPkgName(message.sendingUid, message.replyTo), true); if (mVerboseLoggingEnabled) logd(getName() + " stop listen mode"); - if (mWifiNative.p2pExtListen(false, 0, 0)) { + if (mWifiNative.p2pExtListen(false, 0, 0, null)) { replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); sendP2pListenChangedBroadcast(false); } else { @@ -3544,16 +4002,38 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class P2pRejectWaitState extends State { + class P2pRejectWaitState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + P2pRejectWaitState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { if (mVerboseLoggingEnabled) logd(getName()); } @Override - public boolean processMessage(Message message) { + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message message) { boolean ret = HANDLED; switch (message.what) { case P2P_REJECTION_RESUME_AFTER_DELAY: @@ -3562,7 +4042,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { "P2p rejection resume after delay - originated from " + getWhatToString(message.what)); if (message.arg2 == WifiP2pManager.CANCEL_CONNECT) { - handleGroupCreationFailure(); + handleGroupCreationFailure(WifiP2pManager + .GROUP_CREATION_FAILURE_REASON_CONNECTION_CANCELLED); if (message.obj != null) { replyToMessage( (Message) message.obj, @@ -3583,13 +4064,31 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return ret; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class GroupCreatingState extends State { + class GroupCreatingState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + GroupCreatingState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); + onGroupCreating(); if (SdkLevel.isAtLeastT()) { mDetailedState = NetworkInfo.DetailedState.CONNECTING; sendP2pConnectionChangedBroadcast(); @@ -3599,7 +4098,12 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); boolean ret = HANDLED; switch (message.what) { @@ -3614,7 +4118,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } mWifiP2pMetrics.endConnectionEvent( P2pConnectionEvent.CLF_TIMEOUT); - handleGroupCreationFailure(); + handleGroupCreationFailure( + WifiP2pManager.GROUP_CREATION_FAILURE_REASON_TIMED_OUT); smTransition(this, mInactiveState); } break; @@ -3655,7 +4160,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { if (mVerboseLoggingEnabled) { logd(getName() + " stop listen mode"); } - if (mWifiNative.p2pExtListen(false, 0, 0)) { + if (mWifiNative.p2pExtListen(false, 0, 0, null)) { replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); } else { replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED); @@ -3675,7 +4180,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { P2pConnectionEvent.CLF_CANCEL); // Notify the peer about the rejection. int delay = 0; - if (mSavedPeerConfig != null) { + if (!TextUtils.isEmpty(mSavedPeerConfig.deviceAddress)) { mWifiNative.p2pStopFind(); delay = sendP2pRejection(); } @@ -3685,7 +4190,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { P2P_REJECTION_RESUME_AFTER_DELAY, ++sP2pRejectionResumeAfterDelayIndex, WifiP2pManager.CANCEL_CONNECT, - message), + Message.obtain(message)), delay); break; case WifiP2pMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: @@ -3698,11 +4203,29 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return ret; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class UserAuthorizingNegotiationRequestState extends State { + class UserAuthorizingNegotiationRequestState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + UserAuthorizingNegotiationRequestState(int threshold, + @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); if (mSavedPeerConfig.wps.setup == WpsInfo.PBC @@ -3714,7 +4237,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case PEER_CONNECTION_USER_ACCEPT: @@ -3729,7 +4252,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { if (mVerboseLoggingEnabled) { logd("User rejected negotiation " + mSavedPeerConfig); } - if (mSavedPeerConfig != null) { + if (!TextUtils.isEmpty(mSavedPeerConfig.deviceAddress)) { WifiP2pDevice dev = fetchCurrentDeviceDetails(mSavedPeerConfig); boolean join = (dev != null && dev.isGroupOwner()) || mJoinExistingGroup; @@ -3745,6 +4268,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { int delay = sendP2pRejection(); mDetailedState = NetworkInfo.DetailedState.DISCONNECTED; + onGroupNegotiationRejectedByUser(); sendP2pConnectionChangedBroadcast(); mSavedPeerConfig.invalidate(); transitionTo(mP2pRejectWaitState); @@ -3756,7 +4280,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { delay); } else { mWifiNative.p2pCancelConnect(); - handleGroupCreationFailure(); + handleGroupCreationFailure( + WifiP2pManager.GROUP_CREATION_FAILURE_REASON_USER_REJECTED); smTransition(this, mInactiveState); } break; @@ -3769,7 +4294,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { break; case WifiP2pMonitor.P2P_PROV_DISC_FAILURE_EVENT: loge("provision discovery failed status: " + message.arg1); - handleGroupCreationFailure(); + handleGroupCreationFailure(WifiP2pManager + .GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED); smTransition(this, mInactiveState); break; case WifiP2pManager.SET_CONNECTION_REQUEST_RESULT: { @@ -3792,7 +4318,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public void exit() { + public void exitImpl() { if (null != mInvitationDialogHandle) { mInvitationDialogHandle.dismissDialog(); mInvitationDialogHandle = null; @@ -3802,11 +4328,29 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mLegacyInvitationDialog = null; } } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class UserAuthorizingInviteRequestState extends State { + class UserAuthorizingInviteRequestState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + UserAuthorizingInviteRequestState(int threshold, + @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); notifyInvitationReceived( @@ -3814,7 +4358,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case PEER_CONNECTION_USER_ACCEPT: @@ -3836,7 +4380,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { break; case WifiP2pMonitor.P2P_PROV_DISC_FAILURE_EVENT: loge("provision discovery failed status: " + message.arg1); - handleGroupCreationFailure(); + handleGroupCreationFailure(WifiP2pManager + .GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED); smTransition(this, mInactiveState); break; case WifiP2pManager.SET_CONNECTION_REQUEST_RESULT: @@ -3858,7 +4403,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public void exit() { + public void exitImpl() { if (null != mInvitationDialogHandle) { mInvitationDialogHandle.dismissDialog(); mInvitationDialogHandle = null; @@ -3868,18 +4413,40 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mLegacyInvitationDialog = null; } } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class ProvisionDiscoveryState extends State { + class ProvisionDiscoveryState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + ProvisionDiscoveryState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig); } @Override - public boolean processMessage(Message message) { + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); WifiP2pProvDiscEvent provDisc = null; WifiP2pDevice device = null; @@ -3970,7 +4537,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mWifiNative.p2pCancelConnect(); mWifiP2pMetrics.endConnectionEvent( P2pConnectionEvent.CLF_PROV_DISC_FAIL); - handleGroupCreationFailure(); + handleGroupCreationFailure(WifiP2pManager + .GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED); smTransition(this, mInactiveState); break; default: @@ -3978,17 +4546,39 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class GroupNegotiationState extends State { + class GroupNegotiationState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + GroupNegotiationState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); } @Override - public boolean processMessage(Message message) { + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { // We ignore these right now, since we get a GROUP_STARTED notification @@ -4004,7 +4594,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } mGroup = (WifiP2pGroup) message.obj; if (mVerboseLoggingEnabled) logd(getName() + " group started"); - if (mWifiNative.p2pExtListen(false, 0, 0)) { + if (mWifiNative.p2pExtListen(false, 0, 0, null)) { sendP2pListenChangedBroadcast(false); } mWifiNative.p2pStopFind(); @@ -4041,7 +4631,10 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { // As a result, P2P sends a unicast intent to tether service to trigger // the whole flow before entering GroupCreatedState. setWifiP2pInfoOnGroupFormation(null); - if (!sendP2pTetherRequestBroadcast()) { + boolean isSendSuccessful = SdkLevel.isAtLeastU() + ? sendP2pTetherRequestBroadcastPostU() + : sendP2pTetherRequestBroadcastPreU(); + if (!isSendSuccessful) { loge("Cannot start tethering, remove " + mGroup); mWifiNative.p2pGroupRemove(mGroup.getInterface()); } @@ -4053,10 +4646,15 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mSavedPeerConfig.getGroupClientIpProvisioningMode(), mGroup.p2pClientEapolIpInfo); WifiP2pDevice groupOwner = mGroup.getOwner(); - WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress); - if (peer != null) { - // update group owner details with peer details found at discovery - groupOwner.updateSupplicantDetails(peer); + if (!EMPTY_DEVICE_ADDRESS.equals(groupOwner.deviceAddress)) { + WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress); + if (peer != null) { + // update group owner details with peer details found at discovery + groupOwner.updateSupplicantDetails(peer); + } else { + logd("Add group owner into mPeers: " + groupOwner); + mPeers.updateSupplicantDetails(groupOwner); + } mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED); sendPeersChangedBroadcast(); @@ -4098,7 +4696,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } mWifiP2pMetrics.endConnectionEvent( P2pConnectionEvent.CLF_GROUP_REMOVED); - handleGroupCreationFailure(); + handleGroupCreationFailure( + WifiP2pManager.GROUP_CREATION_FAILURE_REASON_GROUP_REMOVED); smTransition(this, mInactiveState); break; case WifiP2pMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: @@ -4157,7 +4756,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mContext.getResources().getInteger( R.integer.config_wifiP2pExtListenPeriodMs), mContext.getResources().getInteger( - R.integer.config_wifiP2pExtListenIntervalMs))) { + R.integer.config_wifiP2pExtListenIntervalMs), + null)) { logd(" started listen to receive the invitation Request" + " frame from Peer device."); sendP2pListenChangedBroadcast(true); @@ -4168,7 +4768,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } else { mWifiP2pMetrics.endConnectionEvent( P2pConnectionEvent.CLF_INVITATION_FAIL); - handleGroupCreationFailure(); + handleGroupCreationFailure( + WifiP2pManager.GROUP_CREATION_FAILURE_REASON_INVITATION_FAILED); smTransition(this, mInactiveState); } break; @@ -4176,7 +4777,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { loge("Peer rejected the connection request - status: " + message.arg1); mWifiP2pMetrics.endConnectionEvent( P2pConnectionEvent.CLF_GROUP_REMOVED); - handleGroupCreationFailure(); + handleGroupCreationFailure(WifiP2pManager + .GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED); smTransition(this, mInactiveState); break; case WifiP2pMonitor.AP_STA_CONNECTED_EVENT: @@ -4207,14 +4809,30 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class FrequencyConflictState extends State { + class FrequencyConflictState extends RunnerState { private WifiDialogManager.DialogHandle mFrequencyConflictDialog; private AlertDialog mFrequencyConflictDialogPreT; + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + FrequencyConflictState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); notifyFrequencyConflict(); @@ -4287,7 +4905,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case WifiP2pMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: @@ -4310,7 +4928,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mFrequencyConflictDialogPreT = null; mWifiP2pMetrics.endConnectionEvent( P2pConnectionEvent.CLF_USER_REJECT); - handleGroupCreationFailure(); + handleGroupCreationFailure( + WifiP2pManager.GROUP_CREATION_FAILURE_REASON_USER_REJECTED); smTransition(this, mInactiveState); break; case DROP_WIFI_USER_ACCEPT: @@ -4333,7 +4952,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return HANDLED; } - public void exit() { + public void exitImpl() { if (mFrequencyConflictDialogPreT != null) { mFrequencyConflictDialogPreT.dismiss(); } @@ -4341,11 +4960,28 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mFrequencyConflictDialog.dismissDialog(); } } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class GroupCreatedState extends State { + class GroupCreatedState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + GroupCreatedState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); // Once connected, peer config details are invalid @@ -4369,6 +5005,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { // In case of a negotiation group, connection changed is sent // after a client joins. For autonomous, send now if (mAutonomousGroup) { + onGroupCreated(new WifiP2pInfo(mWifiP2pInfo), eraseOwnDeviceAddress(mGroup)); sendP2pConnectionChangedBroadcast(); } @@ -4378,18 +5015,19 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); WifiP2pDevice device; String deviceAddress; switch (message.what) { - case WifiP2pMonitor.AP_STA_CONNECTED_EVENT: + case WifiP2pMonitor.AP_STA_CONNECTED_EVENT: { if (message.obj == null) { Log.e(TAG, "Illegal argument(s)"); break; } device = (WifiP2pDevice) message.obj; deviceAddress = device.deviceAddress; + MacAddress interfaceMacAddress = device.getInterfaceMacAddress(); // Clear timeout that was set when group was started. mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0); if (deviceAddress != null) { @@ -4398,6 +5036,11 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } else { mGroup.addClient(deviceAddress); } + mGroup.setClientInterfaceMacAddress(deviceAddress, interfaceMacAddress); + if (SdkLevel.isAtLeastV() && device.getIpAddress() != null) { + mGroup.setClientIpAddress(interfaceMacAddress, + device.getIpAddress()); + } mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED); if (mVerboseLoggingEnabled) logd(getName() + " ap sta connected"); // When a peer is connected, flush it. @@ -4407,9 +5050,12 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } else { loge("Connect on null device address, ignore"); } + onPeerClientJoined(new WifiP2pInfo(mWifiP2pInfo), + eraseOwnDeviceAddress(mGroup)); sendP2pConnectionChangedBroadcast(); break; - case WifiP2pMonitor.AP_STA_DISCONNECTED_EVENT: + } + case WifiP2pMonitor.AP_STA_DISCONNECTED_EVENT: { if (message.obj == null) { Log.e(TAG, "Illegal argument(s)"); break; @@ -4428,6 +5074,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { // We end up sending connection changed broadcast // when this happens at exit() } else { + onPeerClientDisconnected(new WifiP2pInfo(mWifiP2pInfo), + eraseOwnDeviceAddress(mGroup)); // Notify when a client disconnects from group sendP2pConnectionChangedBroadcast(); } @@ -4448,6 +5096,34 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { loge("Disconnect on unknown device: " + device); } break; + } + case TETHER_INTERFACE_CLIENTS_CHANGED: { + if (mGroup == null) break; + if (!mGroup.isGroupOwner()) break; + if (TextUtils.isEmpty(mGroup.getInterface())) break; + + Collection<TetheredClient> connectedClients = + (Collection<TetheredClient>) message.obj; + if (connectedClients == null) break; + for (TetheredClient client : connectedClients) { + logd("TETHER_INTERFACE_CLIENTS_CHANGED - client: " + client); + if (client.getTetheringType() == TetheringManager.TETHERING_WIFI_P2P) { + if (client.getAddresses().size() == 0) { + continue; + } + TetheredClient.AddressInfo info = client.getAddresses().get(0); + MacAddress interfaceMacAddress = client.getMacAddress(); + LinkAddress linkAddressInfo = info.getAddress(); + InetAddress ipAddress = linkAddressInfo.getAddress(); + mGroup.setClientIpAddress(interfaceMacAddress, ipAddress); + } else { + loge("Received onClientsChanged cb from a non-p2p tether type: " + + client.getTetheringType()); + } + } + sendP2pConnectionChangedBroadcast(); + break; + } case IPC_PRE_DHCP_ACTION: mWifiNative.setP2pPowerSave(mGroup.getInterface(), false); try { @@ -4489,6 +5165,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } catch (Exception e) { loge("Failed to add iface to local network " + e); } + onGroupCreated(new WifiP2pInfo(mWifiP2pInfo), + eraseOwnDeviceAddress(mGroup)); sendP2pConnectionChangedBroadcast(); break; case IPC_PROVISIONING_SUCCESS: @@ -4513,6 +5191,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { byte[] goInterfaceMacAddress = mGroup.interfaceAddress; if (goInterfaceMacAddress == null) { setWifiP2pInfoOnGroupFormationWithInetAddress(null); + onGroupCreated(new WifiP2pInfo(mWifiP2pInfo), + eraseOwnDeviceAddress(mGroup)); sendP2pConnectionChangedBroadcast(); break; } @@ -4523,6 +5203,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { InetAddress goIp = Inet6Address.getByAddress(null, goIpv6Address, NetworkInterface.getByName(mGroup.getInterface())); setWifiP2pInfoOnGroupFormationWithInetAddress(goIp); + onGroupCreated(new WifiP2pInfo(mWifiP2pInfo), + eraseOwnDeviceAddress(mGroup)); sendP2pConnectionChangedBroadcast(); } catch (UnknownHostException | SocketException e) { loge("Unable to retrieve link-local IPv6 address of group owner " @@ -4691,6 +5373,10 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } newPeerConfig.deviceAddress = provDisc.device.deviceAddress; } + if (SdkLevel.isAtLeastV() && provDisc != null + && provDisc.getVendorData() != null) { + newPeerConfig.setVendorData(provDisc.getVendorData()); + } if (message.what == WifiP2pMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) { newPeerConfig.wps.setup = WpsInfo.KEYPAD; } else if (message.what == WifiP2pMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) { @@ -4745,6 +5431,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { case WifiP2pMonitor.P2P_FREQUENCY_CHANGED_EVENT: if (mGroup != null) { mGroup.setFrequency(message.arg1); + onFrequencyChanged(new WifiP2pInfo(mWifiP2pInfo), + eraseOwnDeviceAddress(mGroup)); sendP2pConnectionChangedBroadcast(); } break; @@ -4786,7 +5474,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return HANDLED; } - public void exit() { + public void exitImpl() { // The group is still there and handling incoming request, // no need to update P2P connection information. if (mGroup != null) return; @@ -4795,17 +5483,35 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { updateThisDevice(WifiP2pDevice.AVAILABLE); resetWifiP2pInfo(); mDetailedState = NetworkInfo.DetailedState.DISCONNECTED; + onGroupRemoved(); sendP2pConnectionChangedBroadcast(); if (!SdkLevel.isAtLeastU()) { // Ensure tethering service to stop tethering. - sendP2pTetherRequestBroadcast(); + sendP2pTetherRequestBroadcastPreU(); } } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class UserAuthorizingJoinState extends State { + class UserAuthorizingJoinState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + UserAuthorizingJoinState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); notifyInvitationReceived( @@ -4813,7 +5519,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public boolean processMessage(Message message) { + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { case WifiP2pMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: @@ -4831,7 +5537,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { break; case PEER_CONNECTION_USER_ACCEPT: // Stop discovery to avoid failure due to channel switch - mWifiNative.p2pStopFind(); + if (mDiscoveryStarted) { + mWifiNative.p2pStopFind(); + } if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { mWifiNative.startWpsPbc(mGroup.getInterface(), null); } else { @@ -4863,7 +5571,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } @Override - public void exit() { + public void exitImpl() { if (null != mInvitationDialogHandle) { mInvitationDialogHandle.dismissDialog(); mInvitationDialogHandle = null; @@ -4873,17 +5581,39 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mLegacyInvitationDialog = null; } } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } - class OngoingGroupRemovalState extends State { + class OngoingGroupRemovalState extends RunnerState { + + /** + * The Runner state Constructor + * + * @param threshold the running time threshold in milliseconds + */ + OngoingGroupRemovalState(int threshold, @NonNull LocalLog localLog) { + super(threshold, localLog); + } + @Override - public void enter() { + public void enterImpl() { logSmStateName(this.getName(), getCurrentState() != null ? getCurrentState().getName() : ""); } @Override - public boolean processMessage(Message message) { + public void exitImpl() { + + } + + @Override + public boolean processMessageImpl(Message message) { logSmMessage(getName(), message); switch (message.what) { // Group removal ongoing. Multiple calls @@ -4898,6 +5628,13 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } return HANDLED; } + + @Override + public String getMessageLogRec(int what) { + return P2pStateMachine.class.getSimpleName() + "." + + this.getClass().getSimpleName() + + "." + getWhatToString(what); + } } @Override @@ -4910,13 +5647,20 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { pw.println(); } - private boolean isWifiP2pAvailable() { - return mIsWifiEnabled && !mIsP2pDisallowedByAdmin; + public boolean isWifiP2pAvailable() { + if (mIsP2pDisallowedByAdmin) return false; + if (mFeatureFlags.d2dWhenInfraStaOff()) { + return mIsWifiEnabled + || (mSettingsConfigStore.get(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED) + && mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()); + } + return mIsWifiEnabled; } - private void checkAndSendP2pStateChangedBroadcast() { + public void checkAndSendP2pStateChangedBroadcast() { Log.d(TAG, "Wifi enabled=" + mIsWifiEnabled + ", P2P disallowed by admin=" - + mIsP2pDisallowedByAdmin); + + mIsP2pDisallowedByAdmin + ", D2D allowed when infra sta is disabled=" + + mSettingsConfigStore.get(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED)); boolean wifiP2pAvailable = isWifiP2pAvailable(); if (mLastP2pState != wifiP2pAvailable) { mLastP2pState = wifiP2pAvailable; @@ -4925,6 +5669,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } private void sendP2pStateChangedBroadcast(boolean enabled) { + onP2pStateChanged(enabled ? WifiP2pManager.WIFI_P2P_STATE_ENABLED + : WifiP2pManager.WIFI_P2P_STATE_DISABLED); final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); if (enabled) { @@ -4942,6 +5688,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mDiscoveryStarted = started; if (mVerboseLoggingEnabled) logd("discovery change broadcast " + started); + onDiscoveryStateChanged(started ? WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED + : WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); @@ -4956,6 +5704,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mListenStarted = started; if (mVerboseLoggingEnabled) logd("wifi p2p listen change broadcast " + started); + onListenStateChanged(started ? WifiP2pManager.WIFI_P2P_LISTEN_STARTED + : WifiP2pManager.WIFI_P2P_LISTEN_STOPPED); final Intent intent = new Intent(WifiP2pManager.ACTION_WIFI_P2P_LISTEN_STATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); @@ -5013,16 +5763,21 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } private void sendThisDeviceChangedBroadcast() { + WifiP2pDevice p2pDevice = eraseOwnDeviceAddress(mThisDevice); + onDeviceConfigurationChanged(p2pDevice); + final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, - eraseOwnDeviceAddress(mThisDevice)); + intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, p2pDevice); sendBroadcastWithExcludedPermissions(intent, null); } private void sendPeersChangedBroadcast() { + WifiP2pDeviceList p2pDeviceList = new WifiP2pDeviceList(mPeers); + onPeerListChanged(p2pDeviceList); + final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); - intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers)); + intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, p2pDeviceList); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); sendBroadcastWithExcludedPermissions(intent, null); } @@ -5040,10 +5795,13 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { if (mVerboseLoggingEnabled) logd("sending p2p connection changed broadcast"); Intent intent = getP2pConnectionChangedIntent(); if (SdkLevel.isAtLeastU()) { - // First send direct foreground broadcast to Tethering package - sendP2pTetherRequestBroadcast(); - // Then send the same broadcast to remaining apps excluding Tethering package - sendBroadcastWithExcludedPermissions(intent, RECEIVER_PERMISSIONS_FOR_TETHERING); + // First send direct foreground broadcast to Tethering package and system service + // with same android.permission.MAINLINE_NETWORK_STACK + sendBroadcastWithMainlineNetworkStackPermissionPostU(); + // Then send the same broadcast to remaining apps without + // android.permission.MAINLINE_NETWORK_STACK + sendBroadcastWithExcludedPermissions(intent, + RECEIVER_PERMISSIONS_MAINLINE_NETWORK_STACK); } else { sendBroadcastWithExcludedPermissions(intent, null); } @@ -5123,33 +5881,49 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return null; } - private boolean sendP2pTetherRequestBroadcast() { - String tetheringServicePackage = findTetheringServicePackage(); - if (TextUtils.isEmpty(tetheringServicePackage)) return false; - Log.i(TAG, "sending p2p tether request broadcast to " - + tetheringServicePackage); - + private boolean sendP2pTetherRequestBroadcastPreU() { String[] receiverPermissionsForTetheringRequest = { android.Manifest.permission.TETHER_PRIVILEGED }; - if (SdkLevel.isAtLeastU()) { - receiverPermissionsForTetheringRequest = RECEIVER_PERMISSIONS_FOR_TETHERING; - } + return sendP2pTetherRequestBroadcastCommon(receiverPermissionsForTetheringRequest, + false, 0); + } + + private boolean sendP2pTetherRequestBroadcastPostU() { + return sendP2pTetherRequestBroadcastCommon(RECEIVER_PERMISSIONS_MAINLINE_NETWORK_STACK, + true, Intent.FLAG_RECEIVER_FOREGROUND); + } + + private boolean sendP2pTetherRequestBroadcastCommon(String[] permissions, + boolean setAdditionalFlags, int flags) { + String tetheringServicePackage = findTetheringServicePackage(); + if (TextUtils.isEmpty(tetheringServicePackage)) return false; + Log.i(TAG, "sending p2p tether request broadcast to " + tetheringServicePackage + + " with permission " + Arrays.toString(permissions)); Intent intent = getP2pConnectionChangedIntent(); - intent.setPackage(tetheringServicePackage); - if (SdkLevel.isAtLeastU()) { - // Adding the flag to allow recipient to run at foreground priority with a shorter - // timeout interval. - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + if (setAdditionalFlags) { + intent.addFlags(flags); } - + intent.setPackage(tetheringServicePackage); Context context = mContext.createContextAsUser(UserHandle.ALL, 0); - context.sendBroadcastWithMultiplePermissions( - intent, receiverPermissionsForTetheringRequest); + context.sendBroadcastWithMultiplePermissions(intent, permissions); return true; } + private void sendBroadcastWithMainlineNetworkStackPermissionPostU() { + String[] receiverPermissions = RECEIVER_PERMISSIONS_MAINLINE_NETWORK_STACK; + Intent intent = getP2pConnectionChangedIntent(); + // Adding the flag to allow recipient to run at foreground priority with a shorter + // timeout interval. + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + Log.i(TAG, "sending p2p connection changed broadcast with permission " + + Arrays.toString(receiverPermissions)); + Context context = mContext.createContextAsUser(UserHandle.ALL, 0); + context.sendBroadcastWithMultiplePermissions(intent, receiverPermissions); + } + private void sendP2pPersistentGroupsChangedBroadcast() { + onPersistentGroupsChanged(new WifiP2pGroupList(mGroups, null)); if (mVerboseLoggingEnabled) logd("sending p2p persistent groups changed broadcast"); Intent intent = new Intent(WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); @@ -6170,7 +6944,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return true; } - private void handleGroupCreationFailure() { + private void handleGroupCreationFailure( + @WifiP2pManager.GroupCreationFailureReason int reason) { // A group is formed, but the tethering request is not proceed. if (null != mGroup) { // Clear any timeout that was set. This is essential for devices @@ -6181,6 +6956,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } resetWifiP2pInfo(); mDetailedState = NetworkInfo.DetailedState.FAILED; + onGroupCreationFailed(reason); sendP2pConnectionChangedBroadcast(); // Remove only the peer we failed to connect to so that other devices discovered @@ -6309,12 +7085,12 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { @Override protected void logd(String s) { - Log.d(TAG, s); + Log.d(TAG, s, null); } @Override protected void loge(String s) { - Log.e(TAG, s); + Log.e(TAG, s, null); } /** @@ -6688,11 +7464,11 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { private boolean p2pFind(int timeout) { return p2pFind( WifiP2pManager.WIFI_P2P_SCAN_FULL, - WifiP2pManager.WIFI_P2P_SCAN_FREQ_UNSPECIFIED, timeout); + WifiP2pManager.WIFI_P2P_SCAN_FREQ_UNSPECIFIED, timeout, null); } private boolean p2pFind(@WifiP2pManager.WifiP2pScanType int scanType, int freq, - int timeout) { + int timeout, @Nullable WifiP2pDiscoveryConfig discoveryConfig) { if (isFeatureSupported(WifiP2pManager.FEATURE_SET_VENDOR_ELEMENTS)) { Set<ScanResult.InformationElement> aggregatedVendorElements = new HashSet<>(); mVendorElements.forEach((k, v) -> aggregatedVendorElements.addAll(v)); @@ -6710,6 +7486,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } else if (scanType == WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ && freq != WifiP2pManager.WIFI_P2P_SCAN_FREQ_UNSPECIFIED) { return mWifiNative.p2pFind(scanType, freq, timeout); + } else if (scanType == WifiP2pManager.WIFI_P2P_SCAN_WITH_CONFIG_PARAMS + && discoveryConfig != null) { + return mWifiNative.p2pFindWithParams(discoveryConfig, timeout); } return false; } @@ -6903,6 +7682,11 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return false; } + if (TextUtils.isEmpty(mSavedPeerConfig.deviceAddress)) { + logd("Saved peer address is empty"); + return false; + } + if (!devAddr.equals(MacAddress.fromString(mSavedPeerConfig.deviceAddress))) { logd("Saved peer address is different from " + devAddr); return false; diff --git a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java index 99899c3f3b..85e5e65c50 100644 --- a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java +++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java @@ -19,6 +19,7 @@ package com.android.server.wifi.rtt; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_LCI; import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_LCR; +import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR; import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT; import static android.net.wifi.rtt.WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER; @@ -237,6 +238,8 @@ public class RttServiceImpl extends IWifiRttManager.Stub { j.put("lcrSupported", mCapabilities.lcrSupported); j.put("responderSupported", mCapabilities.responderSupported); j.put("mcVersion", mCapabilities.mcVersion); + j.put("ntbInitiatorSupported", mCapabilities.ntbInitiatorSupported); + j.put("ntbResponderSupported", mCapabilities.ntbResponderSupported); } catch (JSONException e) { Log.e(TAG, "onCommand: get_capabilities e=" + e); } @@ -478,10 +481,30 @@ public class RttServiceImpl extends IWifiRttManager.Stub { characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_LCR, capabilities.lcrSupported); characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER, capabilities.responderSupported); + characteristics.putBoolean(CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR, + capabilities.ntbInitiatorSupported); return characteristics; } /** + * Override IEEE 802.11az parameters with overlay values. + */ + private void override11azOverlays(RangingRequest rangingRequest) { + int minNtbTime = mContext.getResources().getInteger( + R.integer.config_wifi80211azMinTimeBetweenNtbMeasurementsMicros); + int maxNtbTime = mContext.getResources().getInteger( + R.integer.config_wifi80211azMaxTimeBetweenNtbMeasurementsMicros); + if (minNtbTime > 0 || maxNtbTime > 0) { + for (ResponderConfig peer : rangingRequest.mRttPeers) { + if (peer.is80211azNtbSupported()) { + if (maxNtbTime > 0) peer.setNtbMaxTimeBetweenMeasurementsMicros(maxNtbTime); + if (minNtbTime > 0) peer.setNtbMinTimeBetweenMeasurementsMicros(minNtbTime); + } + } + } + } + + /** * Binder interface API to start a ranging operation. Called on binder thread, operations needs * to be posted to handler thread. */ @@ -584,6 +607,8 @@ public class RttServiceImpl extends IWifiRttManager.Stub { return; } + override11azOverlays(request); + mRttServiceSynchronized.mHandler.post(() -> { WorkSource sourceToUse = ws; if (ws == null || ws.isEmpty()) { @@ -1166,11 +1191,24 @@ public class RttServiceImpl extends IWifiRttManager.Stub { + "address for peerId=" + rttPeer.peerHandle.peerId); continue; } - newRequestBuilder.addResponder(new ResponderConfig( - MacAddress.fromBytes(mac), - rttPeer.peerHandle, rttPeer.responderType, rttPeer.supports80211mc, - rttPeer.channelWidth, rttPeer.frequency, rttPeer.centerFreq0, - rttPeer.centerFreq1, rttPeer.preamble)); + // To create a ResponderConfig object with both a MAC address and peer + // handler, we're bypassing the standard Builder pattern and directly using + // the constructor. This is because the SDK's Builder.build() method has a + // built-in restriction that prevents setting both properties simultaneously. + // To avoid triggering this exception, we're directly invoking the + // constructor to accommodate both values. + ResponderConfig.Builder responderConfigBuilder = new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromBytes(mac)) + .setPeerHandle(rttPeer.peerHandle) + .setResponderType(rttPeer.getResponderType()) + .set80211mcSupported(rttPeer.is80211mcSupported()) + .set80211azNtbSupported(rttPeer.is80211azNtbSupported()) + .setChannelWidth(rttPeer.getChannelWidth()) + .setFrequencyMhz(rttPeer.getFrequencyMhz()) + .setCenterFreq1Mhz(rttPeer.getCenterFreq1Mhz()) + .setCenterFreq0Mhz(rttPeer.getCenterFreq0Mhz()) + .setPreamble(rttPeer.getPreamble()); + newRequestBuilder.addResponder(new ResponderConfig(responderConfigBuilder)); } else { newRequestBuilder.addResponder(rttPeer); } @@ -1271,32 +1309,15 @@ public class RttServiceImpl extends IWifiRttManager.Stub { if (mVerboseLoggingEnabled) { Log.v(TAG, "postProcessResults: missing=" + peer.macAddress); } - - int errorCode = RangingResult.STATUS_FAIL; - + RangingResult.Builder builder = new RangingResult.Builder() + .setStatus(RangingResult.STATUS_FAIL); if (peer.peerHandle == null) { - finalResults.add( - new RangingResult(errorCode, peer.macAddress, 0, 0, 0, 0, 0, null, - null, null, 0, false)); + builder.setMacAddress(peer.getMacAddress()); } else { - finalResults.add( - new RangingResult( - errorCode, - peer.peerHandle, - 0, - 0, - 0, - 0, - 0, - null, - null, - null, - 0, - RangingResult.UNSPECIFIED, - RangingResult.UNSPECIFIED)); + builder.setPeerHandle(peer.peerHandle); } + finalResults.add(builder.build()); } else { - int status = RangingResult.STATUS_SUCCESS; // Clear LCI and LCR data if the location data should not be retransmitted, // has a retention expiration time, contains no useful data, or did not parse, @@ -1309,40 +1330,46 @@ public class RttServiceImpl extends IWifiRttManager.Stub { lci = null; lcr = null; } - // Create external result with external RangResultStatus, cleared LCI and LCR. + RangingResult.Builder builder = new RangingResult.Builder(); + builder.setStatus(RangingResult.STATUS_SUCCESS) + .setDistanceMm(resultForRequest.getDistanceMm()) + .setDistanceStdDevMm(resultForRequest.getDistanceStdDevMm()) + .setRssi(resultForRequest.getRssi()) + .setNumAttemptedMeasurements( + resultForRequest.getNumAttemptedMeasurements()) + .setNumSuccessfulMeasurements( + resultForRequest.getNumSuccessfulMeasurements()) + .setLci(lci) + .setLcr(lcr) + .setUnverifiedResponderLocation(responderLocation) + .setRangingTimestampMillis(resultForRequest.getRangingTimestampMillis()) + .set80211mcMeasurement(resultForRequest.is80211mcMeasurement()) + .setMeasurementChannelFrequencyMHz( + resultForRequest.getMeasurementChannelFrequencyMHz()) + .setMeasurementBandwidth(resultForRequest.getMeasurementBandwidth()) + .set80211azNtbMeasurement(resultForRequest.is80211azNtbMeasurement()) + .setMinTimeBetweenNtbMeasurementsMicros( + resultForRequest.getMinTimeBetweenNtbMeasurementsMicros()) + .setMaxTimeBetweenNtbMeasurementsMicros( + resultForRequest.getMaxTimeBetweenNtbMeasurementsMicros()) + .set80211azInitiatorTxLtfRepetitionsCount( + resultForRequest.get80211azInitiatorTxLtfRepetitionsCount()) + .set80211azResponderTxLtfRepetitionsCount( + resultForRequest.get80211azResponderTxLtfRepetitionsCount()) + .set80211azNumberOfTxSpatialStreams( + resultForRequest.get80211azNumberOfTxSpatialStreams()) + .set80211azNumberOfRxSpatialStreams( + resultForRequest.get80211azNumberOfRxSpatialStreams()); if (peer.peerHandle == null) { - finalResults.add(new RangingResult( - status, - peer.macAddress, - resultForRequest.mDistanceMm, - resultForRequest.mDistanceStdDevMm, - resultForRequest.mRssi, - resultForRequest.mNumAttemptedMeasurements, - resultForRequest.mNumSuccessfulMeasurements, - lci, - lcr, - responderLocation, - resultForRequest.mTimestamp, - resultForRequest.mIs80211mcMeasurement, - resultForRequest.mFrequencyMHz, - resultForRequest.mPacketBw)); + builder.setMacAddress(peer.getMacAddress()); } else { - finalResults.add( - new RangingResult( - status, - peer.peerHandle, - resultForRequest.mDistanceMm, - resultForRequest.mDistanceStdDevMm, - resultForRequest.mRssi, - resultForRequest.mNumAttemptedMeasurements, - resultForRequest.mNumSuccessfulMeasurements, - lci, - lcr, - responderLocation, - resultForRequest.mTimestamp, - resultForRequest.mFrequencyMHz, - resultForRequest.mPacketBw)); + builder.setPeerHandle(peer.peerHandle); + } + if (SdkLevel.isAtLeastV() && resultForRequest.getVendorData() != null + && !resultForRequest.getVendorData().isEmpty()) { + builder.setVendorData(resultForRequest.getVendorData()); } + finalResults.add(builder.build()); } } return finalResults; diff --git a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java index 5a32c57bb8..77383f643b 100644 --- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java +++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java @@ -28,6 +28,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.wifi.IScanDataListener; import android.net.wifi.IWifiScanner; import android.net.wifi.IWifiScannerListener; import android.net.wifi.ScanResult; @@ -64,6 +65,7 @@ import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.ClientModeImpl; import com.android.server.wifi.Clock; import com.android.server.wifi.DeviceConfigFacade; +import com.android.server.wifi.WifiGlobals; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiLocalServices; import com.android.server.wifi.WifiLog; @@ -87,7 +89,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -106,17 +108,17 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { private void localLog(String message) { mLocalLog.log(message); if (isVerboseLoggingEnabled()) { - Log.i(TAG, message); + Log.i(TAG, message, null); } } private void logw(String message) { - Log.w(TAG, message); + Log.w(TAG, message, null); mLocalLog.log(message); } private void loge(String message) { - Log.e(TAG, message); + Log.e(TAG, message, null); mLocalLog.log(message); } @@ -456,6 +458,28 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { new ArrayList<ScanResult>()); } + + /** + * See {@link WifiScanner#getCachedScanData(Executor, Consumer)}. + */ + @Override + public void getCachedScanData(String packageName, String featureId, + IScanDataListener listener) { + localLog("get single scan result: package " + packageName + + " AttributionTag " + featureId); + final int uid = Binder.getCallingUid(); + Objects.requireNonNull(listener, "listener cannot be null"); + enforcePermission(uid, packageName, featureId, false, false, false); + + mWifiThreadRunner.post(() -> { + try { + listener.onResult(mWifiNative.getCachedScanResultsFromAllClientIfaces()); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } + }); + } + @Override public void startPnoScan(IWifiScannerListener listener, WifiScanner.ScanSettings scanSettings, WifiScanner.PnoSettings pnoSettings, String packageName, String featureId) { @@ -665,6 +689,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { private final WifiManager mWifiManager; private final LastCallerInfoManager mLastCallerInfoManager; private final DeviceConfigFacade mDeviceConfigFacade; + private final WifiGlobals mWifiGlobals; private AtomicBoolean mVerboseLoggingEnabled = new AtomicBoolean(false); @@ -685,6 +710,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { mWifiPermissionsUtil = wifiInjector.getWifiPermissionsUtil(); mWifiNative = wifiInjector.getWifiNative(); mDeviceConfigFacade = wifiInjector.getDeviceConfigFacade(); + mWifiGlobals = wifiInjector.getWifiGlobals(); // Wifi service is always started before other wifi services. So, there is no problem // obtaining WifiManager in the constructor here. mWifiManager = mContext.getSystemService(WifiManager.class); @@ -1561,7 +1587,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { "reason=" + reason + ", " + description); try { entry.clientInfo.mListener.onFailure(reason, description); - } catch (RemoteException e) { + } catch (Exception e) { loge("Failed to call onFailure: " + entry.clientInfo); } entry.clientInfo.unregister(); @@ -1822,6 +1848,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { case WifiScanner.CMD_GET_SCAN_RESULTS: ScanParams scanParams = (ScanParams) msg.obj; ClientInfo ci = mClients.get(scanParams.listener); + if (ci == null) { + loge("ClientInfo is null"); + break; + } ci.replyFailed(WifiScanner.REASON_UNSPECIFIED, "not available"); break; @@ -1873,6 +1903,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { ScanParams scanParams = (ScanParams) msg.obj; mWifiMetrics.incrementBackgroundScanCount(); ClientInfo ci = mClients.get(scanParams.listener); + if (ci == null) { + loge("ClientInfo is null"); + return HANDLED; + } if (scanParams.settings == null) { loge("params null"); return HANDLED; @@ -2422,8 +2456,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { scanParams.pnoSettings.isConnected)) { deferMessage(msg); transitionTo(mHwPnoScanState); - } else if (mContext.getResources().getBoolean( - R.bool.config_wifiSwPnoEnabled) + } else if (mWifiGlobals.isSwPnoEnabled() && mDeviceConfigFacade.isSoftwarePnoEnabled()) { deferMessage(msg); transitionTo(mSwPnoScanState); @@ -3082,7 +3115,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { } try { mListener.asBinder().unlinkToDeath(mDeathRecipient, 0); - } catch (NoSuchElementException e) { + } catch (Exception e) { Log.e(TAG, "Failed to unregister death recipient! " + mListener); } @@ -3154,7 +3187,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { try { mListener.onSuccess(); mLog.trace("onSuccess").flush(); - } catch (RemoteException e) { + } catch (Exception e) { // There's not much we can do if reply can't be sent! } } else { @@ -3170,7 +3203,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { .c(reason) .c(description) .flush(); - } catch (RemoteException e) { + } catch (Exception e) { // There's not much we can do if reply can't be sent! } } else { diff --git a/service/java/com/android/server/wifi/util/ApConfigUtil.java b/service/java/com/android/server/wifi/util/ApConfigUtil.java index 96c2984873..799e530986 100644 --- a/service/java/com/android/server/wifi/util/ApConfigUtil.java +++ b/service/java/com/android/server/wifi/util/ApConfigUtil.java @@ -440,12 +440,14 @@ public class ApConfigUtil { // If HAL doesn't support getUsableChannels then return null return null; } - List<Integer> regulatoryList = usableChannelList.stream() - .map(ch -> inFrequencyMHz - ? ch.getFrequencyMhz() - : ScanResult.convertFrequencyMhzToChannelIfSupported( - ch.getFrequencyMhz())) - .collect(Collectors.toList()); + List<Integer> regulatoryList = new ArrayList<>(); + if (inFrequencyMHz) { + usableChannelList.forEach(a -> regulatoryList.add(a.getFrequencyMhz())); + } else { + usableChannelList.forEach(a -> regulatoryList.add(ScanResult + .convertFrequencyMhzToChannelIfSupported(a.getFrequencyMhz()))); + + } return addDfsChannelsIfNeeded(regulatoryList, scannerBand, wifiNative, resources, inFrequencyMHz); } @@ -1086,6 +1088,19 @@ public class ApConfigUtil { }}); } + /** + * Helper function to get whether or not device claim support bridged AP. + * (i.e. In resource file) + * + * @param context the caller context used to get value from resource file. + * @return true if supported, false otherwise. + */ + public static boolean isBridgedModeSupportedInConfig(@NonNull Context context) { + return SdkLevel.isAtLeastS() && context.getResources().getBoolean( + R.bool.config_wifiBridgedSoftApSupported); + } + + /** * Helper function to get HAL support STA + bridged AP or not. * @@ -1521,20 +1536,31 @@ public class ApConfigUtil { return deepCopyMap; } - /** * Observer the available channel from native layer (vendor HAL if getUsableChannels is * supported, or wificond if not supported) and update the SoftApCapability * * @param softApCapability the current softap capability * @param context the caller context used to get value from resource file - * @param wifiNative reference used to collect regulatory restrictions. * + * @param wifiNative reference used to collect regulatory restrictions. + * @param channelMap the channel for each band * @return updated soft AP capability */ public static SoftApCapability updateSoftApCapabilityWithAvailableChannelList( @NonNull SoftApCapability softApCapability, @NonNull Context context, - @NonNull WifiNative wifiNative) { + @NonNull WifiNative wifiNative, @NonNull SparseArray<int[]> channelMap) { SoftApCapability newSoftApCapability = new SoftApCapability(softApCapability); + if (channelMap != null) { + for (int band : SoftApConfiguration.BAND_TYPES) { + if (isSoftApBandSupported(context, band)) { + int[] supportedChannelList = channelMap.get(band); + if (supportedChannelList != null) { + newSoftApCapability.setSupportedChannelList(band, supportedChannelList); + } + } + } + return newSoftApCapability; + } List<Integer> supportedChannelList = null; for (int band : SoftApConfiguration.BAND_TYPES) { diff --git a/service/java/com/android/server/wifi/util/HalAidlUtil.java b/service/java/com/android/server/wifi/util/HalAidlUtil.java index e845446858..500a3d862d 100644 --- a/service/java/com/android/server/wifi/util/HalAidlUtil.java +++ b/service/java/com/android/server/wifi/util/HalAidlUtil.java @@ -16,8 +16,12 @@ package com.android.server.wifi.util; +import android.annotation.NonNull; +import android.hardware.wifi.WifiChannelWidthInMhz; import android.hardware.wifi.common.OuiKeyedData; import android.hardware.wifi.supplicant.KeyMgmtMask; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiAnnotations; import android.net.wifi.WifiConfiguration; import android.util.Log; @@ -118,4 +122,47 @@ public class HalAidlUtil { } return halList.toArray(new OuiKeyedData[halList.size()]); } + + /** + * Convert a list of HAL OuiKeyedData its framework equivalent. + */ + public static List<android.net.wifi.OuiKeyedData> halToFrameworkOuiKeyedDataList( + @NonNull OuiKeyedData[] halList) { + if (halList == null) { + return new ArrayList<>(); + } + List<android.net.wifi.OuiKeyedData> frameworkList = new ArrayList<>(); + for (OuiKeyedData halData : halList) { + try { + android.net.wifi.OuiKeyedData frameworkData = + new android.net.wifi.OuiKeyedData.Builder( + halData.oui, halData.vendorData).build(); + frameworkList.add(frameworkData); + } catch (Exception e) { + Log.e(TAG, "Invalid HAL OuiKeyedData: " + e); + } + } + return frameworkList; + } + + /** + * Convert HAL channelBandwidth to framework enum + */ + @WifiAnnotations.ChannelWidth + public static int getChannelBandwidthFromHal(int channelBandwidth) { + switch (channelBandwidth) { + case WifiChannelWidthInMhz.WIDTH_40: + return ScanResult.CHANNEL_WIDTH_40MHZ; + case WifiChannelWidthInMhz.WIDTH_80: + return ScanResult.CHANNEL_WIDTH_80MHZ; + case WifiChannelWidthInMhz.WIDTH_160: + return ScanResult.CHANNEL_WIDTH_160MHZ; + case WifiChannelWidthInMhz.WIDTH_80P80: + return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ; + case WifiChannelWidthInMhz.WIDTH_320: + return ScanResult.CHANNEL_WIDTH_320MHZ; + default: + return ScanResult.CHANNEL_WIDTH_20MHZ; + } + } } diff --git a/service/java/com/android/server/wifi/util/InformationElementUtil.java b/service/java/com/android/server/wifi/util/InformationElementUtil.java index b6e991c146..57643b9c01 100644 --- a/service/java/com/android/server/wifi/util/InformationElementUtil.java +++ b/service/java/com/android/server/wifi/util/InformationElementUtil.java @@ -15,6 +15,7 @@ */ package com.android.server.wifi.util; +import android.hardware.wifi.WifiBand; import android.net.MacAddress; import android.net.wifi.MloLink; import android.net.wifi.ScanResult; @@ -27,6 +28,7 @@ import android.net.wifi.nl80211.NativeScanResult; import android.net.wifi.nl80211.WifiNl80211Manager; import android.net.wifi.util.HexEncoding; import android.util.Log; +import android.util.SparseIntArray; import com.android.server.wifi.ByteBufferReader; import com.android.server.wifi.MboOceConstants; @@ -833,10 +835,21 @@ public class InformationElementUtil { private static final int EHT_OPERATION_INFO_START_INDEX = EHT_OPERATION_BASIC_LENGTH; private static final int DISABLED_SUBCHANNEL_BITMAP_START_INDEX = EHT_OPERATION_INFO_START_INDEX + 3; + private static final int CHANNEL_WIDTH_INDEX = EHT_OPERATION_INFO_START_INDEX + 0; + private static final int CHANNEL_WIDTH_MASK = 0xF; + private static final int CHANNEL_CENTER_FREQ_SEG0_INDEX = + EHT_OPERATION_INFO_START_INDEX + 1; + private static final int CHANNEL_CENTER_FREQ_SEG_MASK = 0xFF; + private static final int CHANNEL_CENTER_FREQ_SEG1_INDEX = + EHT_OPERATION_INFO_START_INDEX + 2; + private boolean mPresent = false; private boolean mEhtOperationInfoPresent = false; private boolean mDisabledSubchannelBitmapPresent = false; private byte[] mDisabledSubchannelBitmap; + private int mChannelWidth; + private int mCenterFreqSeg0; + private int mCenterFreqSeg1; /** * Returns whether the EHT Information Element is present. @@ -868,6 +881,69 @@ public class InformationElementUtil { } /** + * @return Channel width if EHT Operation Information Present. + */ + public int getChannelWidth() { + /* + * Channel width in EHT operation Info is set, + * 0 for 20 MHz EHT BSS bandwidth. + * 1 for 40 MHz EHT BSS bandwidth. + * 2 for 80 MHz EHT BSS bandwidth. + * 3 for 160 MHz EHT BSS bandwidth. + * 4 for 320 MHz EHT BSS bandwidth. + * Values in the ranges 5 to 7 are reserved. + */ + switch(mChannelWidth) { + case 0: return ScanResult.CHANNEL_WIDTH_20MHZ; + case 1: return ScanResult.CHANNEL_WIDTH_40MHZ; + case 2: return ScanResult.CHANNEL_WIDTH_80MHZ; + case 3: return ScanResult.CHANNEL_WIDTH_160MHZ; + case 4: return ScanResult.CHANNEL_WIDTH_320MHZ; + default: + return ScanResult.UNSPECIFIED; + } + } + + /** + * Returns Channel Center Frequency Segment 0 (CCFS0). + * + * - For 20, 40 or 80 MHz BSS bandwidth, indicates the channel center frequency for the + * 20, 40 or 80 MHz channel on which the EHT BSS operates. + * - For 160 MHz BSS bandwidth, indicates the channel center frequency of the primary 80 + * MHz channel. + * - For 320 MHz BSS bandwidth, indicates the channel center frequency of the primary 160 + * MHz channel. + * + * @param band Operating band + * @return Center frequency. + */ + public int getCenterFreq0(@ScanResult.WifiBand int band) { + if (mCenterFreqSeg0 == 0 || band == WifiBand.BAND_UNSPECIFIED) { + return ScanResult.UNSPECIFIED; + } + return ScanResult.convertChannelToFrequencyMhzIfSupported(mCenterFreqSeg0, band); + } + + /** + * Returns Channel Center Frequency Segment 1 (CCFS1) + * + * - For a 20, 40 or 80 MHz BSS bandwidth, returns {@link ScanResult#UNSPECIFIED} . + * - For a 160 MHz BSS bandwidth, returns the channel center frequency of the 160 MHz + * channel on which the EHT BSS operates. + * - For a 320 MHz BSS bandwidth, returns the channel center frequency of the 320 MHz + * channel on which the EHT BSS operates + * + * @param band Operating band + * @return Center frequency. + */ + public int getCenterFreq1(@ScanResult.WifiBand int band) { + if (mCenterFreqSeg1 == 0 || band == WifiBand.BAND_UNSPECIFIED) { + return ScanResult.UNSPECIFIED; + } + return ScanResult.convertChannelToFrequencyMhzIfSupported(mCenterFreqSeg1, band); + } + + /** * Parse EHT Operation IE */ public void from(InformationElement ie) { @@ -899,6 +975,14 @@ public class InformationElementUtil { } mPresent = true; + if (mEhtOperationInfoPresent) { + mChannelWidth = ie.bytes[CHANNEL_WIDTH_INDEX] & CHANNEL_WIDTH_MASK; + mCenterFreqSeg0 = + ie.bytes[CHANNEL_CENTER_FREQ_SEG0_INDEX] & CHANNEL_CENTER_FREQ_SEG_MASK; + mCenterFreqSeg1 = + ie.bytes[CHANNEL_CENTER_FREQ_SEG1_INDEX] & CHANNEL_CENTER_FREQ_SEG_MASK; + } + if (mDisabledSubchannelBitmapPresent) { mDisabledSubchannelBitmap = new byte[2]; System.arraycopy(ie.bytes, DISABLED_SUBCHANNEL_BITMAP_START_INDEX, @@ -1689,7 +1773,7 @@ public class InformationElementUtil { private static final int FILS_CAPABILITY_BIT = 72; private static final int TWT_REQUESTER_CAPABILITY_BIT = 77; private static final int TWT_RESPONDER_CAPABILITY_BIT = 78; - private static final int NO_TB_RANGING_RESPONDER = 90; + private static final int NON_TB_RANGING_RESPONDER = 90; private static final int TB_RANGING_RESPONDER = 91; public BitSet capabilitiesBitSet; @@ -1698,7 +1782,7 @@ public class InformationElementUtil { * @return true if Trigger based ranging responder supported. Refer P802.11az/D7.0, * September 2022, section 9.4.2.26 Extended Capabilities element. */ - public boolean isTriggerBasedRangingRespSupported() { + public boolean is80211azTbResponder() { return capabilitiesBitSet.get(TB_RANGING_RESPONDER); } @@ -1706,8 +1790,8 @@ public class InformationElementUtil { * @return true if Non trigger based ranging responder supported. Refer P802.11az/D7.0, * September 2022, section 9.4.2.26 Extended Capabilities element. */ - public boolean isNonTriggerBasedRangingRespSupported() { - return capabilitiesBitSet.get(NO_TB_RANGING_RESPONDER); + public boolean is80211azNtbResponder() { + return capabilitiesBitSet.get(NON_TB_RANGING_RESPONDER); } /** @@ -1843,7 +1927,7 @@ public class InformationElementUtil { // // Note: InformationElement.bytes has 'Element ID' and 'Length' // stripped off already - private void parseRsnElement(InformationElement ie) { + private void parseRsnElement(InformationElement ie, SparseIntArray unknownAkmMap) { ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); try { @@ -1924,9 +2008,13 @@ public class InformationElementUtil { case RSN_AKM_DPP: rsnKeyManagement.add(ScanResult.KEY_MGMT_DPP); break; - default: - rsnKeyManagement.add(ScanResult.KEY_MGMT_UNKNOWN); + default: { + int akmScheme = + getScanResultAkmSchemeOfUnknownAkmIfConfigured( + akm, unknownAkmMap); + rsnKeyManagement.add(akmScheme); break; + } } } // Default AKM @@ -1961,6 +2049,27 @@ public class InformationElementUtil { } } + /** + * Get the ScanResult security key management scheme (ScanResult.KEY_MGMT_XX) corresponding + * to the unknown AKMs configured in overlay config item + * config_wifiUnknownAkmToKnownAkmMapping + * + * @param unknownAkm unknown AKM seen in the received beacon or probe response. + * @param unknownAkmMap unknownAkmMap Mapping of unknown AKMs configured in overlay config + * item config_wifiUnknownAkmToKnownAkmMapping to ScanResult security key management + * scheme (ScanResult.KEY_MGMT_XX). + * @return A valid ScanResult.KEY_MGMT_XX if unknownAkm is configured in the overlay, + * ScanResult.KEY_MGMT_UNKNOWN otherwise + */ + private int getScanResultAkmSchemeOfUnknownAkmIfConfigured( + int unknownAkm, SparseIntArray unknownAkmMap) { + if (unknownAkmMap != null) { + return unknownAkmMap.get(unknownAkm, ScanResult.KEY_MGMT_UNKNOWN); + } else { + return ScanResult.KEY_MGMT_UNKNOWN; + } + } + private static @Cipher int parseWpaCipher(int cipher) { switch (cipher) { case WPA_CIPHER_NONE: @@ -2040,7 +2149,7 @@ public class InformationElementUtil { // Note: InformationElement.bytes has 'Element ID' and 'Length' // stripped off already // - private void parseWpaOneElement(InformationElement ie) { + private void parseWpaOneElement(InformationElement ie, SparseIntArray unknownAkmMap) { ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); try { @@ -2085,7 +2194,10 @@ public class InformationElementUtil { wpaKeyManagement.add(ScanResult.KEY_MGMT_PSK); break; default: - wpaKeyManagement.add(ScanResult.KEY_MGMT_UNKNOWN); + int akmScheme = + getScanResultAkmSchemeOfUnknownAkmIfConfigured( + akm, unknownAkmMap); + wpaKeyManagement.add(akmScheme); break; } } @@ -2100,19 +2212,24 @@ public class InformationElementUtil { } /** - * Parse the Information Element and the 16-bit Capability Information field - * to build the InformationElemmentUtil.capabilities object. + * Parse the Information Element and the 16-bit Capability Information field to build the + * InformationElemmentUtil.capabilities object. * - * @param ies -- Information Element array - * @param beaconCap -- 16-bit Beacon Capability Information field + * @param ies -- Information Element array + * @param beaconCap -- 16-bit Beacon Capability Information field * @param isOweSupported -- Boolean flag to indicate if OWE is supported by the device - * @param freq -- Frequency on which frame/beacon was transmitted. - * Some parsing may be affected such as DMG parameters in - * DMG (60GHz) beacon. + * @param freq -- Frequency on which frame/beacon was transmitted. Some parsing may be + * affected such as DMG parameters in DMG (60GHz) beacon. + * @param unknownAkmMap -- unknown AKM to known AKM mapping (Internally converted to + * security key management scheme(ScanResult.KEY_MGMT_XX)) configured in overlay config + * item config_wifiUnknownAkmToKnownAkmMapping. */ - - public void from(InformationElement[] ies, int beaconCap, boolean isOweSupported, - int freq) { + public void from( + InformationElement[] ies, + int beaconCap, + boolean isOweSupported, + int freq, + SparseIntArray unknownAkmMap) { protocol = new ArrayList<>(); keyManagement = new ArrayList<>(); groupCipher = new ArrayList<>(); @@ -2148,12 +2265,12 @@ public class InformationElementUtil { } if (ie.id == InformationElement.EID_RSN) { - parseRsnElement(ie); + parseRsnElement(ie, unknownAkmMap); } if (ie.id == InformationElement.EID_VSA) { if (isWpaOneElement(ie)) { - parseWpaOneElement(ie); + parseWpaOneElement(ie, unknownAkmMap); } if (isWpsElement(ie)) { // TODO(b/62134557): parse WPS IE to provide finer granularity information. @@ -2187,6 +2304,48 @@ public class InformationElementUtil { } } + /** Convert the AKM suite selector to scan result Security key management scheme */ + public static int akmToScanResultKeyManagementScheme(int akm) { + switch (akm) { + case RSN_AKM_EAP: + case WPA_AKM_EAP: + return ScanResult.KEY_MGMT_EAP; + case RSN_AKM_PSK: + case WPA_AKM_PSK: + return ScanResult.KEY_MGMT_PSK; + case RSN_AKM_FT_EAP: + return ScanResult.KEY_MGMT_FT_EAP; + case RSN_AKM_FT_PSK: + return ScanResult.KEY_MGMT_FT_PSK; + case RSN_AKM_EAP_SHA256: + return ScanResult.KEY_MGMT_EAP_SHA256; + case RSN_AKM_PSK_SHA256: + return ScanResult.KEY_MGMT_PSK_SHA256; + case RSN_AKM_SAE: + return ScanResult.KEY_MGMT_SAE; + case RSN_AKM_FT_SAE: + return ScanResult.KEY_MGMT_FT_SAE; + case RSN_AKM_SAE_EXT_KEY: + return ScanResult.KEY_MGMT_SAE_EXT_KEY; + case RSN_AKM_FT_SAE_EXT_KEY: + return ScanResult.KEY_MGMT_FT_SAE_EXT_KEY; + case RSN_AKM_OWE: + return ScanResult.KEY_MGMT_OWE; + case RSN_AKM_EAP_SUITE_B_192: + return ScanResult.KEY_MGMT_EAP_SUITE_B_192; + case RSN_OSEN: + return ScanResult.KEY_MGMT_OSEN; + case RSN_AKM_EAP_FILS_SHA256: + return ScanResult.KEY_MGMT_FILS_SHA256; + case RSN_AKM_EAP_FILS_SHA384: + return ScanResult.KEY_MGMT_FILS_SHA384; + case RSN_AKM_DPP: + return ScanResult.KEY_MGMT_DPP; + default: + return ScanResult.KEY_MGMT_UNKNOWN; + } + } + private static boolean isOweElement(InformationElement ie) { ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); try { diff --git a/service/java/com/android/server/wifi/util/IpConfigStore.java b/service/java/com/android/server/wifi/util/IpConfigStore.java index 2a719c4e28..245bcd028b 100644 --- a/service/java/com/android/server/wifi/util/IpConfigStore.java +++ b/service/java/com/android/server/wifi/util/IpConfigStore.java @@ -255,10 +255,10 @@ public class IpConfigStore { } protected static void loge(String s) { - Log.e(TAG, s); + Log.e(TAG, s, null); } protected static void log(String s) { - Log.d(TAG, s); + Log.d(TAG, s, null); } } diff --git a/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java b/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java index a1501e63a4..f556a300f3 100644 --- a/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java +++ b/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java @@ -53,6 +53,8 @@ public class WifiConfigStoreEncryptionUtil { private static final int GCM_TAG_LENGTH = 128; private static final int KEY_LENGTH = 256; private static final String KEY_STORE = "AndroidKeyStore"; + private final SecretKey mSecretKeyReference; + private Cipher mEncryptCipher; private final String mDataFileName; @@ -69,6 +71,16 @@ public class WifiConfigStoreEncryptionUtil { + "string"); } mDataFileName = dataFileName; + mSecretKeyReference = getOrCreateSecretKey(getKeyAlias()); + try { + mEncryptCipher = Cipher.getInstance(CIPHER_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + reportException(e, "encrypt could not find the algorithm: " + CIPHER_ALGORITHM); + } catch (NoSuchPaddingException e) { + reportException(e, "encrypt had a padding exception"); + } catch (Exception e) { + reportException(e, "exception caught"); + } } private String getKeyAlias() { @@ -82,27 +94,25 @@ public class WifiConfigStoreEncryptionUtil { * @return Instance of {@link EncryptedData} containing the encrypted info. */ public @Nullable EncryptedData encrypt(byte[] data) { + if (data == null || data.length == 0) { + return null; + } EncryptedData encryptedData = null; try { - Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); - SecretKey secretKeyReference = getOrCreateSecretKey(getKeyAlias()); - if (secretKeyReference != null) { - cipher.init(Cipher.ENCRYPT_MODE, secretKeyReference); - encryptedData = new EncryptedData(cipher.doFinal(data), cipher.getIV()); + if (mSecretKeyReference != null) { + mEncryptCipher.init(Cipher.ENCRYPT_MODE, mSecretKeyReference); + encryptedData = new EncryptedData(mEncryptCipher.doFinal(data), + mEncryptCipher.getIV()); } else { reportException(new Exception("secretKeyReference is null."), "secretKeyReference is null."); } - } catch (NoSuchAlgorithmException e) { - reportException(e, "encrypt could not find the algorithm: " + CIPHER_ALGORITHM); - } catch (NoSuchPaddingException e) { - reportException(e, "encrypt had a padding exception"); - } catch (InvalidKeyException e) { - reportException(e, "encrypt received an invalid key"); } catch (BadPaddingException e) { reportException(e, "encrypt had a padding problem"); } catch (IllegalBlockSizeException e) { reportException(e, "encrypt had an illegal block size"); + } catch (InvalidKeyException e) { + reportException(e, "encrypt received an invalid key"); } catch (Exception e) { reportException(e, "exception caught"); } @@ -120,9 +130,8 @@ public class WifiConfigStoreEncryptionUtil { try { Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, encryptedData.getIv()); - SecretKey secretKeyReference = getOrCreateSecretKey(getKeyAlias()); - if (secretKeyReference != null) { - cipher.init(Cipher.DECRYPT_MODE, secretKeyReference, spec); + if (mSecretKeyReference != null) { + cipher.init(Cipher.DECRYPT_MODE, mSecretKeyReference, spec); decryptedData = cipher.doFinal(encryptedData.getEncryptedData()); } } catch (NoSuchAlgorithmException e) { diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java index 7c79fafa9d..c7d97cf6ed 100644 --- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java +++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java @@ -753,7 +753,8 @@ public class WifiPermissionsUtil { private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, int uid, @Nullable String message) { - return mAppOps.noteOp(op, uid, pkgName, featureId, message) == AppOpsManager.MODE_ALLOWED; + return mAppOps.noteOpNoThrow(op, uid, pkgName, featureId, message) + == AppOpsManager.MODE_ALLOWED; } private boolean checkAppOpAllowed(String op, String pkgName, int uid) { @@ -913,20 +914,6 @@ public class WifiPermissionsUtil { } /** - * Returns true if the |callingUid|/\callingPackage| holds SYSTEM_ALERT_WINDOW permission. - */ - public boolean checkSystemAlertWindowPermission(int callingUid, String callingPackage) { - final int mode = mAppOps.noteOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, callingUid, - callingPackage, null, null); - if (mode == AppOpsManager.MODE_DEFAULT) { - return mWifiPermissionsWrapper.getUidPermission( - Manifest.permission.SYSTEM_ALERT_WINDOW, callingUid) - == PackageManager.PERMISSION_GRANTED; - } - return mode == AppOpsManager.MODE_ALLOWED; - } - - /** * Returns the DevicePolicyManager from context */ public static DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) { diff --git a/service/java/com/android/server/wifi/util/XmlUtil.java b/service/java/com/android/server/wifi/util/XmlUtil.java index 47da81f907..e0bb9e5f28 100644 --- a/service/java/com/android/server/wifi/util/XmlUtil.java +++ b/service/java/com/android/server/wifi/util/XmlUtil.java @@ -29,6 +29,7 @@ import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StaticIpConfiguration; import android.net.Uri; +import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.SecurityParams; import android.net.wifi.SoftApConfiguration; @@ -39,6 +40,7 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiMigration; import android.net.wifi.WifiSsid; import android.os.ParcelUuid; +import android.os.PersistableBundle; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -50,6 +52,8 @@ 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.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; @@ -86,6 +90,11 @@ import java.util.Locale; public class XmlUtil { private static final String TAG = "WifiXmlUtil"; + public static final String XML_TAG_VENDOR_DATA_LIST = "VendorDataList"; + public static final String XML_TAG_OUI_KEYED_DATA = "OuiKeyedData"; + public static final String XML_TAG_VENDOR_DATA_OUI = "VendorDataOui"; + public static final String XML_TAG_PERSISTABLE_BUNDLE = "PersistableBundle"; + /** * Ensure that the XML stream is at a start tag or the end of document. * @@ -363,6 +372,7 @@ public class XmlUtil { public static final String XML_TAG_ROAMING_CONSORTIUM_OIS = "RoamingConsortiumOIs"; public static final String XML_TAG_RANDOMIZED_MAC_ADDRESS = "RandomizedMacAddress"; public static final String XML_TAG_MAC_RANDOMIZATION_SETTING = "MacRandomizationSetting"; + public static final String XML_TAG_SEND_DHCP_HOSTNAME = "SendDhcpHostname"; public static final String XML_TAG_CARRIER_ID = "CarrierId"; public static final String XML_TAG_SUBSCRIPTION_ID = "SubscriptionId"; public static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled"; @@ -385,11 +395,12 @@ public class XmlUtil { private static final String XML_TAG_IS_RESTRICTED = "IsRestricted"; private static final String XML_TAG_SUBSCRIPTION_GROUP = "SubscriptionGroup"; public static final String XML_TAG_BSSID_ALLOW_LIST = "bssidAllowList"; - private static final String XML_TAG_IS_REPEATER_ENABLED = "RepeaterEnabled"; + public static final String XML_TAG_IS_REPEATER_ENABLED = "RepeaterEnabled"; public static final String XML_TAG_DPP_PRIVATE_EC_KEY = "DppPrivateEcKey"; public static final String XML_TAG_DPP_CONNECTOR = "DppConnector"; public static final String XML_TAG_DPP_CSIGN_KEY = "DppCSignKey"; public static final String XML_TAG_DPP_NET_ACCESS_KEY = "DppNetAccessKey"; + public static final String XML_TAG_ENABLE_WIFI7 = "EnableWifi7"; /** * Write Wep Keys to the XML stream. @@ -424,7 +435,7 @@ public class XmlUtil { EncryptedData[] encryptedDataArray = new EncryptedData[len]; for (int i = 0; i < len; i++) { if (wepKeys[i] == null) { - encryptedDataArray[i] = new EncryptedData(null, null); + encryptedDataArray[i] = new EncryptedData(new byte[0], new byte[0]); } else { encryptedDataArray[i] = encryptionUtil.encrypt(wepKeys[i].getBytes()); if (encryptedDataArray[i] == null) { @@ -515,7 +526,7 @@ public class XmlUtil { EncryptedData encryptedData = null; if (encryptionUtil != null) { encryptedData = encryptionUtil.encrypt(data); - if (encryptedData == null) { + if (encryptedData == null && data != null && data.length != 0) { // We silently fail encryption failures! Log.wtf(TAG, "Encryption of " + tag + " failed"); } @@ -601,7 +612,10 @@ public class XmlUtil { configuration.numRebootsSinceLastUse); XmlUtil.writeNextValue(out, XML_TAG_IS_REPEATER_ENABLED, configuration.isRepeaterEnabled()); + XmlUtil.writeNextValue(out, XML_TAG_ENABLE_WIFI7, configuration.isWifi7Enabled()); writeSecurityParamsListToXml(out, configuration); + XmlUtil.writeNextValue(out, XML_TAG_SEND_DHCP_HOSTNAME, + configuration.isSendDhcpHostnameEnabled()); } /** @@ -683,6 +697,9 @@ public class XmlUtil { .getBssidAllowlistInternal())); } writeDppConfigurationToXml(out, configuration, encryptionUtil); + if (SdkLevel.isAtLeastV()) { + writeVendorDataListToXml(out, configuration.getVendorData()); + } } private static List<String> covertMacAddressListToStringList(List<MacAddress> macList) { @@ -735,7 +752,12 @@ public class XmlUtil { List<String> wepKeyList = new ArrayList<>(); final List<EncryptedData> encryptedDataList = XmlUtil.EncryptedDataXmlUtil.parseListFromXml(in, outerTagDepth); + EncryptedData emptyData = new EncryptedData(new byte[0], new byte[0]); for (int i = 0; i < encryptedDataList.size(); i++) { + if (encryptedDataList.get(i).equals(emptyData)) { + wepKeyList.add(null); + continue; + } byte[] passphraseBytes = encryptionUtil.decrypt(encryptedDataList.get(i)); if (passphraseBytes == null) { Log.wtf(TAG, "Decryption of passphraseBytes failed"); @@ -851,6 +873,7 @@ public class XmlUtil { WifiConfiguration configuration = new WifiConfiguration(); String configKeyInData = null; boolean macRandomizationSettingExists = false; + boolean sendDhcpHostnameExists = false; byte[] dppConnector = null; byte[] dppCSign = null; byte[] dppNetAccessKey = null; @@ -989,6 +1012,10 @@ public class XmlUtil { configuration.macRandomizationSetting = (int) value; macRandomizationSettingExists = true; break; + case XML_TAG_SEND_DHCP_HOSTNAME: + configuration.setSendDhcpHostnameEnabled((boolean) value); + sendDhcpHostnameExists = true; + break; case XML_TAG_CARRIER_ID: configuration.carrierId = (int) value; break; @@ -1048,6 +1075,9 @@ public class XmlUtil { case XML_TAG_DPP_NET_ACCESS_KEY: dppNetAccessKey = (byte[]) value; break; + case XML_TAG_ENABLE_WIFI7: + configuration.setWifi7Enabled((boolean) value); + break; default: Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]); break; @@ -1102,6 +1132,12 @@ public class XmlUtil { dppNetAccessKey = readEncrytepdBytesFromXml(encryptionUtil, in, outerTagDepth); break; + case XML_TAG_VENDOR_DATA_LIST: + if (SdkLevel.isAtLeastV()) { + configuration.setVendorData( + parseVendorDataListFromXml(in, outerTagDepth + 1)); + } + break; default: Log.w(TAG, "Ignoring unknown tag found: " + tagName); break; @@ -1115,6 +1151,12 @@ public class XmlUtil { == WifiConfiguration.RANDOMIZATION_PERSISTENT && !fromSuggestion) { configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO; } + if (!sendDhcpHostnameExists) { + // Update legacy configs to send the DHCP hostname for secure networks only. + configuration.setSendDhcpHostnameEnabled( + !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN) + && !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE)); + } configuration.convertLegacyFieldsToSecurityParamsIfNeeded(); configuration.setDppConnectionKeys(dppConnector, dppCSign, dppNetAccessKey); return Pair.create(configKeyInData, configuration); @@ -2154,6 +2196,9 @@ public class XmlUtil { softApConfig.getPersistentRandomizedMacAddress().toString()); } } + if (SdkLevel.isAtLeastV()) { + writeVendorDataListToXml(out, softApConfig.getVendorData()); + } } // End of writeSoftApConfigurationToXml /** @@ -2349,6 +2394,12 @@ public class XmlUtil { passphrase = readSoftApPassphraseFromXml(in, outerTagDepth, shouldExpectEncryptedCredentials, encryptionUtil); break; + case XML_TAG_VENDOR_DATA_LIST: + if (SdkLevel.isAtLeastV()) { + softApConfigBuilder.setVendorData( + parseVendorDataListFromXml(in, outerTagDepth + 1)); + } + break; default: Log.w(TAG, "Ignoring unknown tag found: " + tagName); break; @@ -2437,5 +2488,118 @@ public class XmlUtil { return new String(passphraseBytes); } } -} + /** + * Write the provided vendor data list to XML. + * + * @param out XmlSerializer instance pointing to the XML stream + * @param vendorDataList Vendor data list + */ + private static void writeVendorDataListToXml( + XmlSerializer out, List<OuiKeyedData> vendorDataList) + throws XmlPullParserException, IOException { + if (vendorDataList == null || vendorDataList.isEmpty()) { + return; + } + XmlUtil.writeNextSectionStart(out, XML_TAG_VENDOR_DATA_LIST); + for (OuiKeyedData data : vendorDataList) { + writeOuiKeyedDataToXml(out, data); + } + XmlUtil.writeNextSectionEnd(out, XML_TAG_VENDOR_DATA_LIST); + } + + private static void writeOuiKeyedDataToXml( + XmlSerializer out, OuiKeyedData ouiKeyedData) + throws XmlPullParserException, IOException { + // PersistableBundle cannot be written directly to XML + // Use byte[] as an intermediate data structure + if (ouiKeyedData == null) return; + byte[] bundleBytes; + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ouiKeyedData.getData().writeToStream(outputStream); + bundleBytes = outputStream.toByteArray(); + } catch (Exception e) { + Log.e(TAG, "Unable to write PersistableBundle to byte[]"); + return; + } + XmlUtil.writeNextSectionStart(out, XML_TAG_OUI_KEYED_DATA); + XmlUtil.writeNextValue(out, XML_TAG_VENDOR_DATA_OUI, ouiKeyedData.getOui()); + XmlUtil.writeNextValue(out, XML_TAG_PERSISTABLE_BUNDLE, bundleBytes); + XmlUtil.writeNextSectionEnd(out, XML_TAG_OUI_KEYED_DATA); + } + + /** + * Parses the vendor data list from the provided XML stream . + * + * @param in XmlPullParser instance pointing to the XML stream + * @param outerTagDepth depth of the outer tag in the XML document + * @return List of OuiKeyedData if successful, empty list otherwise + */ + private static List<OuiKeyedData> parseVendorDataListFromXml( + XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException, IllegalArgumentException { + List<OuiKeyedData> vendorDataList = new ArrayList<>(); + while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { + String tagName = in.getName(); + if (tagName == null) { + throw new XmlPullParserException("Unexpected null tag found"); + } + switch (tagName) { + case XML_TAG_OUI_KEYED_DATA: + OuiKeyedData data = parseOuiKeyedDataFromXml(in, outerTagDepth + 1); + if (data != null) { + vendorDataList.add(data); + } + break; + default: + Log.w(TAG, "Ignoring unknown tag found: " + tagName); + break; + } + } + return vendorDataList; + } + + private static PersistableBundle readPersistableBundleFromBytes(byte[] bundleBytes) { + try { + ByteArrayInputStream inputStream = new ByteArrayInputStream(bundleBytes); + return PersistableBundle.readFromStream(inputStream); + } catch (Exception e) { + Log.e(TAG, "Unable to read PersistableBundle from byte[]"); + return null; + } + } + + private static OuiKeyedData parseOuiKeyedDataFromXml( + XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException, IllegalArgumentException { + int oui = 0; + PersistableBundle bundle = null; + + while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { + String[] valueName = new String[1]; + Object value = XmlUtil.readCurrentValue(in, valueName); + if (valueName[0] == null) { + throw new XmlPullParserException("Missing value name"); + } + switch (valueName[0]) { + case XML_TAG_VENDOR_DATA_OUI: + oui = (int) value; + break; + case XML_TAG_PERSISTABLE_BUNDLE: + bundle = readPersistableBundleFromBytes((byte[]) value); + break; + default: + Log.e(TAG, "Unknown value name found: " + valueName[0]); + break; + } + } + + try { + return new OuiKeyedData.Builder(oui, bundle).build(); + } catch (Exception e) { + Log.e(TAG, "Unable to build OuiKeyedData"); + return null; + } + } +} diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto index 944ff6b774..9183dc7b4a 100644 --- a/service/proto/src/metrics.proto +++ b/service/proto/src/metrics.proto @@ -1463,6 +1463,9 @@ message StaEvent { // The network has been marked as untrusted. DISCONNECT_NETWORK_UNTRUSTED = 16; + + // Wi-Fi 7 support for this network has been enabled or disabled. + DISCONNECT_NETWORK_WIFI7_TOGGLED = 17; } // Authentication Failure reasons as reported through the API. @@ -2310,8 +2313,8 @@ message WifiRadioUsage { } message ExperimentValues { - // Indicates if we are logging WifiIsUnusableEvent in metrics - optional bool wifi_is_unusable_logging_enabled = 1; + reserved 1; + reserved "wifi_is_unusable_logging_enabled"; // Minimum number of txBad to trigger a data stall optional int32 wifi_data_stall_min_tx_bad = 2; diff --git a/service/tests/wifitests/Android.bp b/service/tests/wifitests/Android.bp index 260393243b..9319822b95 100644 --- a/service/tests/wifitests/Android.bp +++ b/service/tests/wifitests/Android.bp @@ -98,9 +98,33 @@ android_test { "com.android.server.wifi.AdaptiveConnectivityEnabledSettingObserver", "com.android.server.wifi.AdaptiveConnectivityEnabledSettingObserver$*", "com.android.server.wifi.AdaptiveConnectivityEnabledSettingObserver.**", + "com.android.server.wifi.AfcClient", + "com.android.server.wifi.AfcClient$*", + "com.android.server.wifi.AfcClient.**", + "com.android.server.wifi.AfcEllipseLocation", + "com.android.server.wifi.AfcEllipseLocation$*", + "com.android.server.wifi.AfcEllipseLocation.**", + "com.android.server.wifi.AfcLocation", + "com.android.server.wifi.AfcLocation$*", + "com.android.server.wifi.AfcLocation.**", + "com.android.server.wifi.AfcLocationUtil", + "com.android.server.wifi.AfcLocationUtil$*", + "com.android.server.wifi.AfcLocationUtil.**", + "com.android.server.wifi.AfcManager", + "com.android.server.wifi.AfcManager$*", + "com.android.server.wifi.AfcManager.**", + "com.android.server.wifi.AfcServerResponse", + "com.android.server.wifi.AfcServerResponse$*", + "com.android.server.wifi.AfcServerResponse.**", "com.android.server.wifi.AggressiveConnectedScore", "com.android.server.wifi.AggressiveConnectedScore$*", "com.android.server.wifi.AggressiveConnectedScore.**", + "com.android.server.wifi.ApplicationQosPolicyRequestHandler", + "com.android.server.wifi.ApplicationQosPolicyRequestHandler$*", + "com.android.server.wifi.ApplicationQosPolicyRequestHandler.**", + "com.android.server.wifi.ApplicationQosPolicyTrackingTable", + "com.android.server.wifi.ApplicationQosPolicyTrackingTable$*", + "com.android.server.wifi.ApplicationQosPolicyTrackingTable.**", "com.android.server.wifi.AssocRejectEventInfo", "com.android.server.wifi.AssocRejectEventInfo$*", "com.android.server.wifi.AssocRejectEventInfo.**", @@ -113,6 +137,9 @@ android_test { "com.android.server.wifi.BackupManagerProxy", "com.android.server.wifi.BackupManagerProxy$*", "com.android.server.wifi.BackupManagerProxy.**", + "com.android.server.wifi.BackupRestoreController", + "com.android.server.wifi.BackupRestoreController$*", + "com.android.server.wifi.BackupRestoreController.**", "com.android.server.wifi.BubbleFunScorer", "com.android.server.wifi.BubbleFunScorer$*", "com.android.server.wifi.BubbleFunScorer.**", @@ -123,7 +150,7 @@ android_test { "com.android.server.wifi.ByteBufferReader$*", "com.android.server.wifi.ByteBufferReader.**", "com.android.server.wifi.CertificateEventInfo", - "com.android.server.wifi.CertificateEventInfo*", + "com.android.server.wifi.CertificateEventInfo$*", "com.android.server.wifi.CertificateEventInfo.**", "com.android.server.wifi.ClientMode", "com.android.server.wifi.ClientMode$*", @@ -188,9 +215,6 @@ android_test { "com.android.server.wifi.DppMetrics", "com.android.server.wifi.DppMetrics$*", "com.android.server.wifi.DppMetrics.**", - "com.android.server.wifi.DtimMultiplierController", - "com.android.server.wifi.DtimMultiplierController$*", - "com.android.server.wifi.DtimMultiplierController.**", "com.android.server.wifi.EapFailureNotifier", "com.android.server.wifi.EapFailureNotifier$*", "com.android.server.wifi.EapFailureNotifier.**", @@ -455,6 +479,9 @@ android_test { "com.android.server.wifi.ThroughputScorer", "com.android.server.wifi.ThroughputScorer$*", "com.android.server.wifi.ThroughputScorer.**", + "com.android.server.wifi.TwtManager", + "com.android.server.wifi.TwtManager$*", + "com.android.server.wifi.TwtManager.**", "com.android.server.wifi.UntrustedWifiNetworkFactory", "com.android.server.wifi.UntrustedWifiNetworkFactory$*", "com.android.server.wifi.UntrustedWifiNetworkFactory.**", @@ -527,6 +554,9 @@ android_test { "com.android.server.wifi.WifiDataStall", "com.android.server.wifi.WifiDataStall$*", "com.android.server.wifi.WifiDataStall.**", + "com.android.server.wifi.WifiDeviceStateChangeManager", + "com.android.server.wifi.WifiDeviceStateChangeManager$*", + "com.android.server.wifi.WifiDeviceStateChangeManager.**", "com.android.server.wifi.WifiDiagnostics", "com.android.server.wifi.WifiDiagnostics$*", "com.android.server.wifi.WifiDiagnostics.**", @@ -599,6 +629,12 @@ android_test { "com.android.server.wifi.WifiPseudonymManager", "com.android.server.wifi.WifiPseudonymManager$*", "com.android.server.wifi.WifiPseudonymManager.**", + "com.android.server.wifi.WifiPulledAtomLogger", + "com.android.server.wifi.WifiPulledAtomLogger$*", + "com.android.server.wifi.WifiPulledAtomLogger.**", + "com.android.server.wifi.WifiRoamingConfigStore", + "com.android.server.wifi.WifiRoamingConfigStore$*", + "com.android.server.wifi.WifiRoamingConfigStore.**", "com.android.server.wifi.WifiScanAlwaysAvailableSettingsCompatibility", "com.android.server.wifi.WifiScanAlwaysAvailableSettingsCompatibility$*", "com.android.server.wifi.WifiScanAlwaysAvailableSettingsCompatibility.**", @@ -614,6 +650,9 @@ android_test { "com.android.server.wifi.WifiServiceImpl", "com.android.server.wifi.WifiServiceImpl$*", "com.android.server.wifi.WifiServiceImpl.**", + "com.android.server.wifi.WifiSettingsBackupRestore", + "com.android.server.wifi.WifiSettingsBackupRestore$*", + "com.android.server.wifi.WifiSettingsBackupRestore.**", "com.android.server.wifi.WifiSettingsConfigStore", "com.android.server.wifi.WifiSettingsConfigStore$*", "com.android.server.wifi.WifiSettingsConfigStore.**", @@ -686,6 +725,9 @@ android_test { "com.android.server.wifi.aware.WifiAwareStateManager", "com.android.server.wifi.aware.WifiAwareStateManager$*", "com.android.server.wifi.aware.WifiAwareStateManager.**", + "com.android.server.wifi.b2b.WifiRoamingModeManager", + "com.android.server.wifi.b2b.WifiRoamingModeManager$*", + "com.android.server.wifi.b2b.WifiRoamingModeManager.**", "com.android.server.wifi.coex.CoexManager", "com.android.server.wifi.coex.CoexManager$*", "com.android.server.wifi.coex.CoexManager.**", @@ -1043,6 +1085,9 @@ android_test { "com.android.server.wifi.hotspot2.soap.command.SppCommand", "com.android.server.wifi.hotspot2.soap.command.SppCommand$*", "com.android.server.wifi.hotspot2.soap.command.SppCommand.**", + "com.android.server.wifi.mockwifi.MockSupplicantManager", + "com.android.server.wifi.mockwifi.MockSupplicantManager$*", + "com.android.server.wifi.mockwifi.MockSupplicantManager.**", "com.android.server.wifi.mockwifi.MockWifiNl80211Manager", "com.android.server.wifi.mockwifi.MockWifiNl80211Manager$*", "com.android.server.wifi.mockwifi.MockWifiNl80211Manager.**", diff --git a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java index bbe67e1b89..fd98347e3b 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java @@ -16,6 +16,8 @@ package com.android.server.wifi; +import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; @@ -75,6 +77,7 @@ import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration.Builder; import android.net.wifi.SoftApInfo; +import android.net.wifi.SoftApState; import android.net.wifi.WifiClient; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; @@ -452,7 +455,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { private void enterSoftApActiveMode() throws Exception { enterSoftApActiveMode( new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mSoftApCapability, TEST_COUNTRYCODE)); + mSoftApCapability, TEST_COUNTRYCODE, null)); } private int mTimesCreatedSoftApManager = 1; @@ -1005,10 +1008,12 @@ public class ActiveModeWardenTest extends WifiBaseTest { enterSoftApActiveMode(); mSoftApListener.onStarted(mSoftApManager); - mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); + SoftApState softApState = new SoftApState( + WifiManager.WIFI_AP_STATE_ENABLED, 0, null, null); + mSoftApManagerCallback.onStateChanged(softApState); mLooper.dispatchAll(); - verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); + verify(mSoftApStateMachineCallback).onStateChanged(softApState); } /** @@ -1018,13 +1023,16 @@ public class ActiveModeWardenTest extends WifiBaseTest { @Test public void doesntCallWifiServiceCallbackOnLOHSStateChanged() throws Exception { enterSoftApActiveMode(new SoftApModeConfiguration( - WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null, mSoftApCapability, TEST_COUNTRYCODE)); + WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null, mSoftApCapability, TEST_COUNTRYCODE, + null)); mSoftApListener.onStarted(mSoftApManager); - mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); + SoftApState softApState = new SoftApState( + WifiManager.WIFI_AP_STATE_ENABLED, 0, null, null); + mSoftApManagerCallback.onStateChanged(softApState); mLooper.dispatchAll(); - verify(mSoftApStateMachineCallback, never()).onStateChanged(anyInt(), anyInt()); + verify(mSoftApStateMachineCallback, never()).onStateChanged(softApState); verify(mSoftApStateMachineCallback, never()).onConnectedClientsOrInfoChanged(any(), any(), anyBoolean()); } @@ -1069,7 +1077,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { configBuilder.setSsid("ThisIsAConfig"); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), mSoftApCapability, - TEST_COUNTRYCODE); + TEST_COUNTRYCODE, null); enterSoftApActiveMode(softApConfig); } @@ -1096,12 +1104,12 @@ public class ActiveModeWardenTest extends WifiBaseTest { configBuilder1.setSsid("ThisIsAConfig"); SoftApModeConfiguration softApConfig1 = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder1.build(), - mSoftApCapability, TEST_COUNTRYCODE); + mSoftApCapability, TEST_COUNTRYCODE, null); Builder configBuilder2 = new SoftApConfiguration.Builder(); configBuilder2.setSsid("ThisIsASecondConfig"); SoftApModeConfiguration softApConfig2 = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder2.build(), - mSoftApCapability, TEST_COUNTRYCODE); + mSoftApCapability, TEST_COUNTRYCODE, null); doAnswer(new Answer<SoftApManager>() { public SoftApManager answer(InvocationOnMock invocation) { @@ -1147,6 +1155,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { verify(mWifiNative).getSupportedFeatureSet(null); verify(mWifiNative).isStaApConcurrencySupported(); verify(mWifiNative).isStaStaConcurrencySupported(); + verify(mWifiNative).isP2pStaConcurrencySupported(); verifyZeroInteractions(mWifiNative); } @@ -1227,12 +1236,14 @@ public class ActiveModeWardenTest extends WifiBaseTest { mSoftApListener.onStopped(mSoftApManager); mLooper.dispatchAll(); - mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); + SoftApState softApState = new SoftApState( + WifiManager.WIFI_AP_STATE_DISABLED, 0, null, null); + mSoftApManagerCallback.onStateChanged(softApState); mLooper.dispatchAll(); shutdownWifi(); - verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); + verify(mSoftApStateMachineCallback).onStateChanged(softApState); } /** @@ -1245,10 +1256,12 @@ public class ActiveModeWardenTest extends WifiBaseTest { shutdownWifi(); mSoftApListener.onStopped(mSoftApManager); - mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); + SoftApState softApState = new SoftApState( + WifiManager.WIFI_AP_STATE_DISABLED, 0, null, null); + mSoftApManagerCallback.onStateChanged(softApState); mLooper.dispatchAll(); - verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); + verify(mSoftApStateMachineCallback).onStateChanged(softApState); verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager); } @@ -1287,12 +1300,12 @@ public class ActiveModeWardenTest extends WifiBaseTest { when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore); SoftApModeConfiguration tetherConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mSoftApCapability, TEST_COUNTRYCODE); + mSoftApCapability, TEST_COUNTRYCODE, null); SoftApConfiguration lohsConfigWC = mWifiApConfigStore.generateLocalOnlyHotspotConfig( mContext, null, mSoftApCapability); SoftApModeConfiguration lohsConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_LOCAL_ONLY, lohsConfigWC, - mSoftApCapability, TEST_COUNTRYCODE); + mSoftApCapability, TEST_COUNTRYCODE, null); // mock SoftAPManagers when(mSoftApManager.getRole()).thenReturn(ROLE_SOFTAP_TETHERED); @@ -1592,7 +1605,8 @@ public class ActiveModeWardenTest extends WifiBaseTest { WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null, mSoftApCapability, - TEST_COUNTRYCODE), + TEST_COUNTRYCODE, + null), TEST_WORKSOURCE); mLooper.dispatchAll(); @@ -2243,7 +2257,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { // try to start Soft AP mActiveModeWarden.startSoftAp( new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE); + mSoftApCapability, TEST_COUNTRYCODE, null), TEST_WORKSOURCE); mLooper.dispatchAll(); verify(mWifiInjector, never()) @@ -2251,13 +2265,19 @@ public class ActiveModeWardenTest extends WifiBaseTest { assertInDisabledState(); // verify triggered Soft AP failure callback - verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + ArgumentCaptor<SoftApState> softApStateCaptor = + ArgumentCaptor.forClass(SoftApState.class); + verify(mSoftApStateMachineCallback).onStateChanged(softApStateCaptor.capture()); + assertThat(softApStateCaptor.getValue().getState()).isEqualTo(WIFI_AP_STATE_FAILED); + assertThat(softApStateCaptor.getValue().getFailureReason()) + .isEqualTo(SAP_START_FAILURE_GENERAL); + assertThat(softApStateCaptor.getValue().getFailureReasonInternal()) + .isEqualTo(SAP_START_FAILURE_GENERAL); // try to start LOHS mActiveModeWarden.startSoftAp( new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null, - mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE); + mSoftApCapability, TEST_COUNTRYCODE, null), TEST_WORKSOURCE); mLooper.dispatchAll(); verify(mWifiInjector, never()) @@ -2265,8 +2285,12 @@ public class ActiveModeWardenTest extends WifiBaseTest { assertInDisabledState(); // verify triggered LOHS failure callback - verify(mLohsStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mLohsStateMachineCallback).onStateChanged(softApStateCaptor.capture()); + assertThat(softApStateCaptor.getValue().getState()).isEqualTo(WIFI_AP_STATE_FAILED); + assertThat(softApStateCaptor.getValue().getFailureReason()) + .isEqualTo(SAP_START_FAILURE_GENERAL); + assertThat(softApStateCaptor.getValue().getFailureReasonInternal()) + .isEqualTo(SAP_START_FAILURE_GENERAL); } /** @@ -2302,7 +2326,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { // Turn on SoftAp. mActiveModeWarden.startSoftAp( new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE); + mSoftApCapability, TEST_COUNTRYCODE, null), TEST_WORKSOURCE); mLooper.dispatchAll(); verify(mWifiInjector) .makeSoftApManager(any(), any(), any(), eq(TEST_WORKSOURCE), any(), anyBoolean()); @@ -2380,7 +2404,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { mActiveModeWarden.startSoftAp( new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE); + mSoftApCapability, TEST_COUNTRYCODE, null), TEST_WORKSOURCE); // add an "unexpected" sta mode stop to simulate a single interface device mClientListener.onStopped(mClientModeManager); mLooper.dispatchAll(); @@ -2416,7 +2440,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { mActiveModeWarden.startSoftAp( new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE); + mSoftApCapability, TEST_COUNTRYCODE, null), TEST_WORKSOURCE); mLooper.dispatchAll(); when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true); @@ -3074,8 +3098,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { assertEquals(additionalClientModeManager, requestedClientModeManager.getValue()); // the additional CMM never became primary verify(mPrimaryChangedCallback, never()).onChange(any(), eq(additionalClientModeManager)); - if (additionaClientModeManagerRole == ROLE_CLIENT_LOCAL_ONLY - || additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) { + if (additionaClientModeManagerRole == ROLE_CLIENT_LOCAL_ONLY) { assertEquals(Set.of(TEST_WORKSOURCE), mActiveModeWarden.getSecondaryRequestWs()); } return additionalClientListener.value; @@ -3122,8 +3145,9 @@ public class ActiveModeWardenTest extends WifiBaseTest { } private void requestRemoveAdditionalClientModeManagerWhenNotAllowed( - ClientConnectivityRole role, boolean clientIsExpected) throws Exception { - enterClientModeActiveState(); + ClientConnectivityRole role, boolean clientIsExpected, + long featureSet) throws Exception { + enterClientModeActiveState(false, featureSet); // Connected to ssid1/bssid1 WifiConfiguration config1 = new WifiConfiguration(); @@ -3338,7 +3362,8 @@ public class ActiveModeWardenTest extends WifiBaseTest { when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false); assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false)); - requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true); + requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true, + TEST_FEATURE_SET); } @Test @@ -3349,7 +3374,8 @@ public class ActiveModeWardenTest extends WifiBaseTest { .thenReturn(false); assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false)); - requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true); + requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true, + TEST_FEATURE_SET); } @Test @@ -3440,7 +3466,8 @@ public class ActiveModeWardenTest extends WifiBaseTest { WorkSource workSource = new WorkSource(TEST_WORKSOURCE); workSource.add(SETTINGS_WORKSOURCE); verify(mWifiNative).isItPossibleToCreateStaIface(eq(workSource)); - requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true); + requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, + true, TEST_FEATURE_SET); } @Test @@ -3464,6 +3491,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { throws Exception { // Ensure that we can't create more client ifaces - so will attempt to fallback (which we // should be able to do for <S apps) + when(mWifiNative.isStaStaConcurrencySupported()).thenReturn(true); when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false); when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled)) .thenReturn(true); @@ -3473,14 +3501,12 @@ public class ActiveModeWardenTest extends WifiBaseTest { .thenReturn(true); assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false)); - requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true); + requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, + true, TEST_FEATURE_SET | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY); } - @Test - public void requestRemoveLoClientModeManagerWhenNotSystemAppAndTargetSdkEqualToSAndCantCreate() - throws Exception { - // Ensure that we can't create more client ifaces - so will attempt to fallback (which we - // can't for >=S apps) + private void testLoFallbackAboveAndroidS(boolean isStaStaSupported) throws Exception { + when(mWifiNative.isStaStaConcurrencySupported()).thenReturn(isStaStaSupported); when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false); when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled)) .thenReturn(true); @@ -3490,7 +3516,30 @@ public class ActiveModeWardenTest extends WifiBaseTest { .thenReturn(false); assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false)); - requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, false); + long expectedFeatureSet = TEST_FEATURE_SET; + if (isStaStaSupported) { + expectedFeatureSet |= WifiManager.WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY; + } + + requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, + !isStaStaSupported, + expectedFeatureSet); + } + + @Test + public void requestRemoveLoClientModeManagerWhenNotSystemAppAndTargetSdkEqualToSAndCantCreate() + throws Exception { + // Ensure that we can't create more client ifaces - so will attempt to fallback (which we + // can't for >=S apps) + testLoFallbackAboveAndroidS(true); + } + + @Test + public void requestRemoveLoClientModeManagerWhenNotSystemAppAndTargetSdkEqualToSAndCantCreate2() + throws Exception { + // Ensure that we can't create more client ifaces and STA+STA is not supported, we + // fallback even for >=S apps + testLoFallbackAboveAndroidS(false); } @Test @@ -3513,7 +3562,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false)); requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_LONG_LIVED, - true); + true, TEST_FEATURE_SET); } @Test @@ -3526,7 +3575,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false)); requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_LONG_LIVED, - true); + true, TEST_FEATURE_SET); } @Test @@ -3602,7 +3651,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false)); requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_TRANSIENT, - true); + true, TEST_FEATURE_SET); } @Test @@ -3616,7 +3665,7 @@ public class ActiveModeWardenTest extends WifiBaseTest { assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole( TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false)); requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_TRANSIENT, - true); + true, TEST_FEATURE_SET); } @Test @@ -5239,6 +5288,42 @@ public class ActiveModeWardenTest extends WifiBaseTest { } @Test + public void testSatelliteModemDisableWifiWhenLocationModeChanged() throws Exception { + when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true); + when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false); + + // Wifi is enabled + enterClientModeActiveState(); + assertInEnabledState(); + + // Satellite mode is ON, disable Wifi + assertWifiShutDown(() -> { + when(mSettingsStore.isSatelliteModeOn()).thenReturn(true); + mActiveModeWarden.handleSatelliteModeChange(); + mLooper.dispatchAll(); + }); + mClientListener.onStopped(mClientModeManager); + mLooper.dispatchAll(); + assertInDisabledState(); + + // Location state changes + ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mContext).registerReceiver( + bcastRxCaptor.capture(), + argThat(filter -> filter.hasAction(LocationManager.MODE_CHANGED_ACTION))); + BroadcastReceiver broadcastReceiver = bcastRxCaptor.getValue(); + + when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); + Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION); + broadcastReceiver.onReceive(mContext, intent); + mLooper.dispatchAll(); + + // Ensure Wi-Fi is still disabled + assertInDisabledState(); + } + + @Test public void testOnIdleModeChanged() throws Exception { enterClientModeActiveState(); List<ClientModeManager> currentCMMs = mActiveModeWarden.getClientModeManagers(); @@ -5260,4 +5345,14 @@ public class ActiveModeWardenTest extends WifiBaseTest { when(mWifiGlobals.isWpaPersonalDeprecated()).thenReturn(false); enterClientModeActiveState(false, TEST_FEATURE_SET | WifiManager.WIFI_FEATURE_WPA_PERSONAL); } + + @Test + public void testD2dSupportedWhenInfraStaDisabled() throws Exception { + when(mWifiNative.isP2pStaConcurrencySupported()).thenReturn(true); + when(mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()).thenReturn(true); + mActiveModeWarden = createActiveModeWarden(); + mActiveModeWarden.start(); + verify(mWifiGlobals).setD2dStaConcurrencySupported(true); + verify(mWifiGlobals, atLeastOnce()).isD2dSupportedWhenInfraStaDisabled(); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyRequestHandlerTest.java b/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyRequestHandlerTest.java index c1809a95c4..5342efbafd 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyRequestHandlerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyRequestHandlerTest.java @@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -33,6 +34,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.wifi.IListListener; +import android.net.wifi.QosCharacteristics; import android.net.wifi.QosPolicyParams; import android.net.wifi.WifiManager; import android.os.HandlerThread; @@ -118,6 +120,14 @@ public class ApplicationQosPolicyRequestHandlerTest { .build(); } + private QosPolicyParams createUplinkPolicy(int policyId) { + QosCharacteristics mockQosCharacteristics = mock(QosCharacteristics.class); + when(mockQosCharacteristics.validate()).thenReturn(true); + return new QosPolicyParams.Builder(policyId, QosPolicyParams.DIRECTION_UPLINK) + .setQosCharacteristics(mockQosCharacteristics) + .build(); + } + private List<QosPolicyParams> createDownlinkPolicyList(int size, int basePolicyId) { List<QosPolicyParams> policies = new ArrayList<>(); for (int i = 0; i < size; i++) { @@ -126,6 +136,14 @@ public class ApplicationQosPolicyRequestHandlerTest { return policies; } + private List<QosPolicyParams> createUplinkPolicyList(int size, int basePolicyId) { + List<QosPolicyParams> policies = new ArrayList<>(); + for (int i = 0; i < size; i++) { + policies.add(createUplinkPolicy(basePolicyId + i)); + } + return policies; + } + private List<Integer> generateIntegerList(int size, int val) { List<Integer> integerList = new ArrayList<>(); for (int i = 0; i < size; i++) { @@ -618,7 +636,7 @@ public class ApplicationQosPolicyRequestHandlerTest { addPoliciesToTable(policyList); // Expect that the request is divided into two batches of size 16 and 2, respectively. - mDut.queueAllPoliciesOnIface(TEST_IFACE_NAME_1); + mDut.queueAllPoliciesOnIface(TEST_IFACE_NAME_1, false); verify(mWifiNative).addQosPolicyRequestForScs( eq(TEST_IFACE_NAME_1), mPolicyListCaptor.capture()); assertEquals(16, mPolicyListCaptor.getValue().size()); @@ -631,4 +649,46 @@ public class ApplicationQosPolicyRequestHandlerTest { eq(TEST_IFACE_NAME_1), mPolicyListCaptor.capture()); assertEquals(2, mPolicyListCaptor.getValue().size()); } + + /** + * Tests that uplink policies are only included in the queueAllPolicies request + * if the current AP supports QosCharacteristics. + */ + @Test + public void testQueueAllPoliciesRequest_mixedDirection() { + assumeTrue(SdkLevel.isAtLeastV()); + when(mActiveModeWarden.getInternetConnectivityClientModeManagers()) + .thenReturn(Arrays.asList(mClientModeManager0)); + int numDownlinkPolicies = 10; + int numUplinkPolicies = 5; + addPoliciesToTable(createDownlinkPolicyList(numDownlinkPolicies, TEST_POLICY_ID_START)); + addPoliciesToTable(createUplinkPolicyList(numUplinkPolicies, + TEST_POLICY_ID_START + numDownlinkPolicies)); + + // Expect that only the downlink policies are sent to the HAL + // if the current AP does not support QosCharacteristics. + mDut.queueAllPoliciesOnIface(TEST_IFACE_NAME_0, false); + verify(mWifiNative, atLeastOnce()).addQosPolicyRequestForScs( + eq(TEST_IFACE_NAME_0), mPolicyListCaptor.capture()); + assertEquals(numDownlinkPolicies, mPolicyListCaptor.getValue().size()); + + // Trigger AP callback to complete the current request. + triggerAndVerifyApCallback(TEST_IFACE_NAME_0, mPolicyListCaptor.getValue(), + SupplicantStaIfaceHal.QOS_POLICY_SCS_RESPONSE_STATUS_SUCCESS); + + // If the current AP supports QosCharacteristics, expect that both uplink + // and downlink policies are sent (albeit in separate transactions). + // Downlink policies will be sent first. + mDut.queueAllPoliciesOnIface(TEST_IFACE_NAME_0, true); + verify(mWifiNative, atLeastOnce()).addQosPolicyRequestForScs( + eq(TEST_IFACE_NAME_0), mPolicyListCaptor.capture()); + assertEquals(numDownlinkPolicies, mPolicyListCaptor.getValue().size()); + + // Trigger callback and check that the uplink policies are sent next. + triggerAndVerifyApCallback(TEST_IFACE_NAME_0, mPolicyListCaptor.getValue(), + SupplicantStaIfaceHal.QOS_POLICY_SCS_RESPONSE_STATUS_SUCCESS); + verify(mWifiNative, atLeastOnce()).addQosPolicyRequestForScs( + eq(TEST_IFACE_NAME_0), mPolicyListCaptor.capture()); + assertEquals(numUplinkPolicies, mPolicyListCaptor.getValue().size()); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyTrackingTableTest.java b/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyTrackingTableTest.java index 49f98d48cb..5a8b75a74a 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyTrackingTableTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ApplicationQosPolicyTrackingTableTest.java @@ -20,7 +20,10 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.junit.Assume.assumeTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import android.net.wifi.QosCharacteristics; import android.net.wifi.QosPolicyParams; import android.net.wifi.WifiManager; @@ -59,6 +62,20 @@ public class ApplicationQosPolicyTrackingTableTest { return policyList; } + private List<QosPolicyParams> generateUplinkPolicyList(int size, int policyIdStart) { + QosCharacteristics mockQosCharacteristics = mock(QosCharacteristics.class); + when(mockQosCharacteristics.validate()).thenReturn(true); + + List<QosPolicyParams> policyList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + policyList.add(new QosPolicyParams.Builder( + policyIdStart + i, QosPolicyParams.DIRECTION_UPLINK) + .setQosCharacteristics(mockQosCharacteristics) + .build()); + } + return policyList; + } + private List<Integer> getPolicyIdsFromPolicyList(List<QosPolicyParams> policyList) { List<Integer> policyIds = new ArrayList<>(); for (QosPolicyParams policy : policyList) { @@ -264,22 +281,53 @@ public class ApplicationQosPolicyTrackingTableTest { } /** - * Tests the {@link ApplicationQosPolicyTrackingTable#getAllPolicies()} method. + * Tests the {@link ApplicationQosPolicyTrackingTable#getAllPolicies(boolean)} method when + * no policies contain QosCharacteristics. */ @Test - public void testGetAllPolicies() { + public void testGetAllPolicies_noQosChars() { // Empty table should return an empty list. - List<QosPolicyParams> retrievedPolicies = mDut.getAllPolicies(); + List<QosPolicyParams> retrievedPolicies = mDut.getAllPolicies(false); assertTrue(retrievedPolicies.isEmpty()); - // Fill table with policies from multiple requesters. + // Fill table with downlink policies from multiple requesters. + // No policies contain QosCharacteristics. List<QosPolicyParams> policyList = generatePolicyList( NUM_VIRTUAL_POLICY_IDS / 2, TEST_PHYSICAL_POLICY_ID_START); mDut.addPolicies(policyList, TEST_UID); mDut.addPolicies(policyList, TEST_UID + 1); // getAllPolicies should return all policies across all requesters. - retrievedPolicies = mDut.getAllPolicies(); + retrievedPolicies = mDut.getAllPolicies(false); assertEquals(NUM_VIRTUAL_POLICY_IDS, retrievedPolicies.size()); } + + /** + * Tests the {@link ApplicationQosPolicyTrackingTable#getAllPolicies(boolean)} method when + * some policies in the table contain QosCharacteristics and others do not. + */ + @Test + public void testGetAllPolicies_filteredByQosChars() { + assumeTrue(SdkLevel.isAtLeastV()); + List<QosPolicyParams> policiesWithoutQosChars = generatePolicyList( + NUM_VIRTUAL_POLICY_IDS / 2, TEST_PHYSICAL_POLICY_ID_START); + mDut.addPolicies(policiesWithoutQosChars, TEST_UID); + + // Table should contain no policies with QosCharacteristics. + List<QosPolicyParams> retrievedPolicies = mDut.getAllPolicies(false); + assertEquals(policiesWithoutQosChars.size(), retrievedPolicies.size()); + retrievedPolicies = mDut.getAllPolicies(true); + assertEquals(0, retrievedPolicies.size()); + + // Uplink policies are guaranteed to contain QosCharacteristics. + List<QosPolicyParams> policiesWithQosChars = generateUplinkPolicyList( + NUM_VIRTUAL_POLICY_IDS / 2, TEST_PHYSICAL_POLICY_ID_START); + mDut.addPolicies(policiesWithQosChars, TEST_UID + 1); + + // Table should contain both policies with and without QosCharacteristics. + retrievedPolicies = mDut.getAllPolicies(false); + assertEquals(policiesWithoutQosChars.size(), retrievedPolicies.size()); + retrievedPolicies = mDut.getAllPolicies(true); + assertEquals(policiesWithQosChars.size(), retrievedPolicies.size()); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/AvailableNetworkNotifierTest.java b/service/tests/wifitests/src/com/android/server/wifi/AvailableNetworkNotifierTest.java index 3c9ac5b4d7..ceecf9bf9a 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/AvailableNetworkNotifierTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/AvailableNetworkNotifierTest.java @@ -106,9 +106,17 @@ public class AvailableNetworkNotifierTest extends WifiBaseTest { AvailableNetworkNotifier.STATE_SHOWING_RECOMMENDATION_NOTIFICATION; final String ssid = "UnknownAkm-Network"; final String caps = "[RSN-?-TKIP+CCMP][ESS][WPS]"; - ScanResult result = new ScanResult(WifiSsid.fromUtf8Text(ssid), ssid, - "ab:cd:01:ef:45:89", 1245, 0, caps, -78, 2450, 1025, 22, 33, 20, 0, - 0, true); + ScanResult result = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + "ab:cd:01:ef:45:89") + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); InformationElement ie = new InformationElement(); ie.id = InformationElement.EID_SSID; ie.bytes = ssid.getBytes(StandardCharsets.UTF_8); diff --git a/service/tests/wifitests/src/com/android/server/wifi/BackupRestoreControllerTest.java b/service/tests/wifitests/src/com/android/server/wifi/BackupRestoreControllerTest.java new file mode 100644 index 0000000000..47c61d620d --- /dev/null +++ b/service/tests/wifitests/src/com/android/server/wifi/BackupRestoreControllerTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2024 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 androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit tests for {@link com.android.server.wifi.BackupRestoreControllerTest}. + */ +@SmallTest +public class BackupRestoreControllerTest extends WifiBaseTest { + + public static final String XML_GENERAL_BEGINNING = + "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"; + + public static final String TEST_WIFI_UNION_BACKUP_DATA_WITH_SETTINGS_IN_V = + XML_GENERAL_BEGINNING + + "<WifiSettingsBackupData>\n" + + WifiSettingsBackupRestoreTest.generateTestWifiSettingsTestingXml("") + + "</WifiSettingsBackupData>\n"; + + @Mock WifiSettingsBackupRestore mWifiSettingsBackupRestore; + @Mock Clock mClock; + + + private BackupRestoreController mBackupRestoreController; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mBackupRestoreController = new BackupRestoreController( + mWifiSettingsBackupRestore, mClock); + } + + /** + * Verify that a data return when retrieve backup data is serialized correctly. + */ + @Test + public void testNormalBackupDataSerializedDeserialized() { + mBackupRestoreController.retrieveBackupData(); + verify(mWifiSettingsBackupRestore).retrieveBackupDataFromSettingsConfigStore(any(), any()); + mBackupRestoreController.parserBackupDataAndDispatch( + TEST_WIFI_UNION_BACKUP_DATA_WITH_SETTINGS_IN_V.getBytes()); + verify(mWifiSettingsBackupRestore).restoreSettingsFromBackupData(any(), eq(1)); + } +} diff --git a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java index d8606f0e3a..68c74f972c 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java @@ -30,6 +30,9 @@ import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_UNWANTED_LOW_RSSI; import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN; +import static android.net.wifi.WifiInfo.SECURITY_TYPE_OWE; +import static android.net.wifi.WifiInfo.SECURITY_TYPE_PSK; import static android.net.wifi.WifiManager.AddNetworkResult.STATUS_SUCCESS; import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY; @@ -135,8 +138,10 @@ import android.net.wifi.WifiNetworkAgentSpecifier; import android.net.wifi.WifiNetworkSpecifier; import android.net.wifi.WifiScanner; import android.net.wifi.WifiSsid; +import android.net.wifi.flags.Flags; import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; +import android.net.wifi.nl80211.DeviceWiphyCapabilities; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.util.ScanResultUtil; import android.os.BatteryStatsManager; @@ -172,6 +177,7 @@ import com.android.server.wifi.ClientModeManagerBroadcastQueue.QueuedBroadcast; import com.android.server.wifi.WifiNative.ConnectionCapabilities; import com.android.server.wifi.WifiScoreCard.PerBssid; import com.android.server.wifi.WifiScoreCard.PerNetwork; +import com.android.server.wifi.b2b.WifiRoamingModeManager; import com.android.server.wifi.hotspot2.NetworkDetail; import com.android.server.wifi.hotspot2.PasspointManager; import com.android.server.wifi.hotspot2.PasspointProvisioningTestUtil; @@ -267,6 +273,7 @@ public class ClientModeImplTest extends WifiBaseTest { private static final long TEST_BSSID = 0x112233445566L; private static final int TEST_DELAY_IN_SECONDS = 300; + private static final String TEST_ATTRIBUTION_TAG = "TEST_ATTRIBUTION_TAG"; private static final int DEFINED_ERROR_CODE = 32764; private static final String TEST_TERMS_AND_CONDITIONS_URL = @@ -300,6 +307,9 @@ public class ClientModeImplTest extends WifiBaseTest { private MockitoSession mSession; private TestNetworkParams mTestNetworkParams = new TestNetworkParams(); + // Attribution tag to be used in the mocked connect sequence + private String mAttributionTagForConnect = TEST_ATTRIBUTION_TAG; + /** * Helper class for setting the default parameters of the WifiConfiguration that gets used * in connect(). @@ -512,6 +522,7 @@ public class ClientModeImplTest extends WifiBaseTest { WifiConfiguration mConnectedNetwork; WifiConfiguration mTestConfig; ExtendedWifiInfo mWifiInfo; + WifiRoamingModeManager mWifiRoamingModeManager; ConnectionCapabilities mConnectionCapabilities = new ConnectionCapabilities(); @Mock ActivityManager mActivityManager; @@ -588,6 +599,9 @@ public class ClientModeImplTest extends WifiBaseTest { @Mock LocalLog mLocalLog; @Mock WifiDeviceStateChangeManager mWifiDeviceStateChangeManager; @Mock WifiCountryCode mWifiCountryCode; + @Mock WifiRoamingConfigStore mWifiRoamingConfigStore; + + @Mock DeviceWiphyCapabilities mDeviceWiphyCapabilities; @Captor ArgumentCaptor<WifiConfigManager.OnNetworkUpdateListener> mConfigUpdateListenerCaptor; @Captor ArgumentCaptor<WifiNetworkAgent.Callback> mWifiNetworkAgentCallbackCaptor; @@ -679,6 +693,8 @@ public class ClientModeImplTest extends WifiBaseTest { mFrameworkFacade = getFrameworkFacade(); mContext = getContext(); mWifiInfo = new ExtendedWifiInfo(mWifiGlobals, WIFI_IFACE_NAME); + mWifiRoamingModeManager = new WifiRoamingModeManager(mWifiNative, + mActiveModeWarden, mWifiRoamingConfigStore); when(mWifiGlobals.isConnectedMacRandomizationEnabled()).thenReturn(true); mResources = getMockResources(); @@ -691,6 +707,7 @@ public class ClientModeImplTest extends WifiBaseTest { when(mWifiGlobals.getPollRssiIntervalMillis()).thenReturn(3000); when(mWifiGlobals.getIpReachabilityDisconnectEnabled()).thenReturn(true); + when(mWifiGlobals.getRepeatedNudFailuresThreshold()).thenReturn(Integer.MAX_VALUE); when(mFrameworkFacade.getIntegerSetting(mContext, Settings.Global.WIFI_FREQUENCY_BAND, @@ -724,7 +741,10 @@ public class ClientModeImplTest extends WifiBaseTest { when(mWifiInjector.getWifiDeviceStateChangeManager()) .thenReturn(mWifiDeviceStateChangeManager); when(mWifiHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); - when(mWifiGlobals.isWpa3SaeUpgradeEnabled()).thenReturn(true); + when(mWifiNative.getDeviceWiphyCapabilities(any())).thenReturn(mDeviceWiphyCapabilities); + if (Flags.getDeviceCrossAkmRoamingSupport() && SdkLevel.isAtLeastV()) { + when(mDeviceWiphyCapabilities.getMaxNumberAkms()).thenReturn(2); + } when(mWifiGlobals.isOweUpgradeEnabled()).thenReturn(true); when(mWifiGlobals.getClientModeImplNumLogRecs()).thenReturn(100); when(mWifiGlobals.isSaveFactoryMacToConfigStoreEnabled()).thenReturn(true); @@ -754,6 +774,9 @@ public class ClientModeImplTest extends WifiBaseTest { initializeCmi(); // Retrieve factory MAC address on first bootup. verify(mWifiNative).getStaFactoryMacAddress(WIFI_IFACE_NAME); + if (Flags.getDeviceCrossAkmRoamingSupport() && SdkLevel.isAtLeastV()) { + verify(mWifiGlobals).setWpa3SaeUpgradeOffloadEnabled(); + } mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true); mConnectedNetwork = spy(WifiConfigurationTestUtil.createOpenNetwork()); @@ -773,6 +796,7 @@ public class ClientModeImplTest extends WifiBaseTest { when(mWifiScoreCard.lookupBssid(any(), any())).thenReturn(mPerBssid); when(mThroughputPredictor.predictMaxTxThroughput(any())).thenReturn(90); when(mThroughputPredictor.predictMaxRxThroughput(any())).thenReturn(80); + when(mWifiInjector.getWifiRoamingModeManager()).thenReturn(mWifiRoamingModeManager); doAnswer(new AnswerWithArguments() { public void answer(boolean shouldReduceNetworkScore) { @@ -998,7 +1022,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(config.networkId), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, mAttributionTagForConnect); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); } @@ -1061,8 +1085,17 @@ public class ClientModeImplTest extends WifiBaseTest { } }).when(mWifiNetworkSelector).selectNetwork(any()); String caps = "[RSN-OWE_TRANSITION]"; - ScanResult scanResult = new ScanResult(WifiSsid.fromUtf8Text(ssid), - ssid, TEST_BSSID_STR, 1245, 0, caps, -78, 2412, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(ssid), + TEST_BSSID_STR) + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)); scanResult.informationElements = new ScanResult.InformationElement[]{ie}; @@ -1184,8 +1217,16 @@ public class ClientModeImplTest extends WifiBaseTest { getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq)); when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn( getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult()); - ScanResult scanResult = new ScanResult(WifiSsid.fromUtf8Text(sFilsSsid), - sFilsSsid, TEST_BSSID_STR, 1245, 0, "", -78, 2412, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(sFilsSsid), + TEST_BSSID_STR) + .setHessid(1245) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID, sFilsSsid.getBytes(StandardCharsets.UTF_8)); scanResult.informationElements = new ScanResult.InformationElement[]{ie}; @@ -1323,8 +1364,16 @@ public class ClientModeImplTest extends WifiBaseTest { getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq)); when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn( getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult()); - ScanResult scanResult = new ScanResult(WifiSsid.fromUtf8Text(sFilsSsid), - sFilsSsid, TEST_BSSID_STR, 1245, 0, "", -78, 2412, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(sFilsSsid), + TEST_BSSID_STR) + .setHessid(1245) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID, sFilsSsid.getBytes(StandardCharsets.UTF_8)); scanResult.informationElements = new ScanResult.InformationElement[]{ie}; @@ -1692,7 +1741,7 @@ public class ClientModeImplTest extends WifiBaseTest { verify(mSimRequiredNotifier).showSimRequiredNotification(any(), any()); verify(mWifiNative, times(2)).removeAllNetworks(WIFI_IFACE_NAME); verify(mWifiMetrics).startConnectionEvent( - anyString(), any(), anyString(), anyInt(), eq(true), anyInt()); + anyString(), any(), anyString(), anyInt(), eq(true), anyInt(), anyInt()); } /** @@ -2255,9 +2304,11 @@ public class ClientModeImplTest extends WifiBaseTest { eq(WifiNative.DISABLE_FIRMWARE_ROAMING)); // Verify firmware roaming is enabled when idle mode exited + when(mWifiRoamingConfigStore.getRoamingMode(anyString())).thenReturn( + WifiManager.ROAMING_MODE_NORMAL); mCmi.onIdleModeChanged(false); - verify(mWifiNative).enableFirmwareRoaming(anyString(), - eq(WifiNative.ENABLE_FIRMWARE_ROAMING)); + verify(mWifiNative).setRoamingMode(anyString(), + eq(WifiManager.ROAMING_MODE_NORMAL)); } @Test @@ -2280,6 +2331,31 @@ public class ClientModeImplTest extends WifiBaseTest { } /** + * Verify that when the primary connects, roaming mode is set + * based on the connected network ssid. + */ + @Test + public void testPerSsidRoamingModePrimary() throws Exception { + when(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID)).thenReturn( + WifiManager.ROAMING_MODE_NORMAL); + connect(); + verify(mWifiRoamingConfigStore).getRoamingMode(TEST_SSID); + verify(mWifiNative).setRoamingMode(anyString(), + eq(WifiManager.ROAMING_MODE_NORMAL)); + } + + /** + * Verify that when the secondary connects, roaming mode is not set. + */ + @Test + public void testPerSsidRoamingModeSecondary() throws Exception { + when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT); + connect(); + verify(mWifiRoamingConfigStore, never()).getRoamingMode(anyString()); + verify(mWifiNative, never()).setRoamingMode(anyString(), anyInt()); + } + + /** * 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 @@ -2353,7 +2429,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(FRAMEWORK_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, TEST_ATTRIBUTION_TAG); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2378,7 +2454,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(FRAMEWORK_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - callingUid, OP_PACKAGE_NAME); + callingUid, OP_PACKAGE_NAME, TEST_ATTRIBUTION_TAG); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2403,7 +2479,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(FRAMEWORK_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2436,7 +2512,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( networkUpdateResult, new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2466,7 +2542,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(FRAMEWORK_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2496,7 +2572,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(FRAMEWORK_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2516,7 +2592,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(FRAMEWORK_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2639,7 +2715,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(TEST_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Process.SYSTEM_UID, OP_PACKAGE_NAME); + Process.SYSTEM_UID, OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); @@ -2656,7 +2732,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(networkId), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); } @@ -2892,7 +2968,7 @@ public class ClientModeImplTest extends WifiBaseTest { @Test public void testEapSimErrorVendorSpecific() throws Exception { when(mWifiMetrics.startConnectionEvent(any(), any(), anyString(), anyInt(), anyBoolean(), - anyInt())).thenReturn(80000); + anyInt(), anyInt())).thenReturn(80000); initializeAndAddNetworkAndVerifySuccess(); startConnectSuccess(); @@ -2923,7 +2999,7 @@ public class ClientModeImplTest extends WifiBaseTest { @Test public void testEapAkaRetrieveOobPseudonymTriggeredByAuthenticationFailure() throws Exception { when(mWifiMetrics.startConnectionEvent(any(), any(), anyString(), anyInt(), anyBoolean(), - anyInt())).thenReturn(80000); + anyInt(), anyInt())).thenReturn(80000); when(mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(anyInt())).thenReturn(true); initializeAndAddNetworkAndVerifySuccess(); @@ -5582,22 +5658,32 @@ public class ClientModeImplTest extends WifiBaseTest { anyInt()); } - /** - * Verify that on the second successful connection to a saved network we set the user connect - * choice. - */ - @Test - public void testConnectionSetUserConnectChoiceOnSecondConnection() throws Exception { + private void verifyUserConnectChoice(boolean shouldSetUcc) throws Exception { when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); mTestNetworkParams.hasEverConnected = true; connect(); verify(mWifiBlocklistMonitor).handleBssidConnectionSuccess(TEST_BSSID_STR, TEST_SSID); verify(mWifiConfigManager).updateNetworkAfterConnect(eq(FRAMEWORK_NETWORK_ID), - eq(true), eq(true), + eq(shouldSetUcc), eq(shouldSetUcc), anyInt()); } /** + * Verify that on the second successful connection to a saved network we set the user connect + * choice. + */ + @Test + public void testConnectionSetUserConnectChoiceOnSecondConnection() throws Exception { + verifyUserConnectChoice(true); + } + + @Test + public void testDisallowUserConnectChoice() throws Exception { + mAttributionTagForConnect = ClientModeImpl.ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE; + verifyUserConnectChoice(false); + } + + /** * Verify that on the first successful connection to an ephemeral network we set the user * connect choice. */ @@ -6838,8 +6924,17 @@ public class ClientModeImplTest extends WifiBaseTest { private void setupFilsEnabledApInScanResult() { String caps = "[WPA2-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA256-CCMP]" + "[RSN-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA256-CCMP][ESS]"; - ScanResult scanResult = new ScanResult(WifiSsid.fromUtf8Text(sFilsSsid), - sFilsSsid, TEST_BSSID_STR, 1245, 0, caps, -78, 2412, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(sFilsSsid), + TEST_BSSID_STR) + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID, sFilsSsid.getBytes(StandardCharsets.UTF_8)); scanResult.informationElements = new ScanResult.InformationElement[]{ie}; @@ -7461,10 +7556,7 @@ public class ClientModeImplTest extends WifiBaseTest { } @Test - public void testIpReachabilityFailureStaticIpOrganicTriggersDisconnection() throws Exception { - when(mDeviceConfigFacade.isHandleRssiOrganicKernelFailuresEnabled()).thenReturn(true); - assumeTrue(SdkLevel.isAtLeastT()); - + public void testIpReachabilityMonitorNotStartOnStaticIpConfiguration() throws Exception { final List<InetAddress> dnsServers = new ArrayList<>(); dnsServers.add(InetAddresses.parseNumericAddress("8.8.8.8")); dnsServers.add(InetAddresses.parseNumericAddress("4.4.4.4")); @@ -7498,19 +7590,9 @@ public class ClientModeImplTest extends WifiBaseTest { injectDhcpSuccess(dhcpResults); mLooper.dispatchAll(); expectRegisterNetworkAgent((agentConfig) -> {}, (cap) -> {}); - reset(mWifiNetworkAgent); - - // normal behavior outside specific CC - when(mWifiGlobals.disableNudDisconnectsForWapiInSpecificCc()).thenReturn(true); - when(mWifiCountryCode.getCountryCode()).thenReturn("US"); - // Trigger IP reachability failure and ensure we trigger a disconnection due to static IP. - ReachabilityLossInfoParcelable lossInfo = - new ReachabilityLossInfoParcelable("", ReachabilityLossReason.ORGANIC); - mIpClientCallback.onReachabilityFailure(lossInfo); - mLooper.dispatchAll(); - verify(mWifiNative).disconnect(WIFI_IFACE_NAME); - verify(mWifiNetworkAgent, never()).unregisterAfterReplacement(anyInt()); + verify(mIpClient).startProvisioning(mProvisioningConfigurationCaptor.capture()); + assertFalse(mProvisioningConfigurationCaptor.getValue().usingIpReachabilityMonitor); } private void doIpReachabilityFailureTest(int lossReason, boolean shouldWifiDisconnect) @@ -7573,6 +7655,57 @@ public class ClientModeImplTest extends WifiBaseTest { verify(mWifiNative).disconnect(WIFI_IFACE_NAME); } + /** + * Verify that when HandleRssiOrganicKernelFailuresEnabled, multiple IP reachability failures + * within a specified time window will lead to disconnect and network disabled. + */ + @Test + public void testRepeatedIpReachabilityFailureDisableNetwork() throws Exception { + assumeTrue(SdkLevel.isAtLeastU()); + when(mDeviceConfigFacade.isHandleRssiOrganicKernelFailuresEnabled()).thenReturn(true); + int failureThreshold = 5; + int failureWindowMs = 60000; + when(mWifiGlobals.getRepeatedNudFailuresThreshold()).thenReturn(failureThreshold); + when(mWifiGlobals.getRepeatedNudFailuresWindowMs()).thenReturn(failureWindowMs); + when(mClock.getElapsedSinceBootMillis()).thenReturn(0L); + + connect(); + expectRegisterNetworkAgent((agentConfig) -> { }, (cap) -> { }); + reset(mWifiNetworkAgent); + + for (int i = 0; i < failureThreshold; i++) { + // increment time outside the failure window. Failure counter should never add up and + // thus not trigger blocking. + when(mClock.getElapsedSinceBootMillis()).thenReturn( + (long) (i + 1) * (failureWindowMs + 1)); + verify(mWifiNative, never()).disconnect(WIFI_IFACE_NAME); + verify(mWifiConfigManager, never()).updateNetworkSelectionStatus(anyInt(), + eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_REPEATED_NUD_FAILURES)); + ReachabilityLossInfoParcelable lossInfo = + new ReachabilityLossInfoParcelable("", ReachabilityLossReason.ORGANIC); + mIpClientCallback.onReachabilityFailure(lossInfo); + mLooper.dispatchAll(); + } + + // Now trigger NUD failure within the failure window and verify the network is blocked. + for (int i = 0; i < failureThreshold - 1; i++) { + when(mClock.getElapsedSinceBootMillis()).thenReturn( + (long) (i + failureThreshold + 1) * (failureWindowMs)); + verify(mWifiNative, never()).disconnect(WIFI_IFACE_NAME); + verify(mWifiConfigManager, never()).updateNetworkSelectionStatus(anyInt(), + eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_REPEATED_NUD_FAILURES)); + ReachabilityLossInfoParcelable lossInfo = + new ReachabilityLossInfoParcelable("", ReachabilityLossReason.ORGANIC); + mIpClientCallback.onReachabilityFailure(lossInfo); + mLooper.dispatchAll(); + } + + // Should disconnect and block network after the last iteration. + verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(), + eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_REPEATED_NUD_FAILURES)); + verify(mWifiNative).disconnect(WIFI_IFACE_NAME); + } + @Test public void testIpReachabilityFailureOrganic_enableHandleRssiOrganicKernelFailuresFlag() throws Exception { @@ -8250,8 +8383,17 @@ public class ClientModeImplTest extends WifiBaseTest { private void verifyTransitionDisableEvent(String caps, int indication, boolean shouldUpdate) throws Exception { final int networkId = FRAMEWORK_NETWORK_ID; - ScanResult scanResult = new ScanResult(WifiSsid.fromUtf8Text(sFilsSsid), - sFilsSsid, TEST_BSSID_STR, 1245, 0, caps, -78, 2412, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder(WifiSsid.fromUtf8Text(sFilsSsid), + TEST_BSSID_STR) + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID, sFilsSsid.getBytes(StandardCharsets.UTF_8)); scanResult.informationElements = new ScanResult.InformationElement[]{ie}; @@ -8998,7 +9140,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(config.networkId), new ActionListenerWrapper(connectActionListener), - Binder.getCallingUid(), OP_PACKAGE_NAME); + Binder.getCallingUid(), OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR); verify(mWifiConfigManager, never()) @@ -9502,7 +9644,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(TEST_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Process.SYSTEM_UID, OP_PACKAGE_NAME); + Process.SYSTEM_UID, OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); if (shouldBeUpdated) { @@ -9719,7 +9861,7 @@ public class ClientModeImplTest extends WifiBaseTest { anyInt(), anyInt()); } - /** + /** * Verify Trust On First Use support. * - this network is automatically connected. * - Tap the notification. @@ -9878,22 +10020,24 @@ public class ClientModeImplTest extends WifiBaseTest { link1.setChannel(TEST_CHANNEL); link1.setApMacAddress(MacAddress.fromString(TEST_BSSID_STR)); link1.setLinkId(TEST_MLO_LINK_ID); + link1.setRssi(TEST_RSSI); MloLink link2 = new MloLink(); link2.setBand(WifiScanner.WIFI_BAND_5_GHZ); link2.setChannel(TEST_CHANNEL_1); link2.setApMacAddress(MacAddress.fromString(TEST_BSSID_STR1)); link2.setLinkId(TEST_MLO_LINK_ID_1); + link2.setRssi(TEST_RSSI); mloLinks.add(link1); mloLinks.add(link2); when(mScanResult.getApMldMacAddress()).thenReturn(TEST_AP_MLD_MAC_ADDRESS); when(mScanResult.getApMloLinkId()).thenReturn(TEST_MLO_LINK_ID); when(mScanResult.getAffiliatedMloLinks()).thenReturn(mloLinks); + mScanResult.level = TEST_RSSI; when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID)) .thenReturn(mScanDetailCache); when(mScanDetailCache.getScanResult(any())).thenReturn(mScanResult); - } private void setScanResultWithoutMloInfo() { @@ -9942,6 +10086,33 @@ public class ClientModeImplTest extends WifiBaseTest { assertFalse(mCmi.isAffiliatedLinkBssid(MacAddress.fromString(TEST_BSSID_STR2))); } + @Test + public void testAffiliatedLinkBssidMatchWithNullLinkMacAddress() throws Exception { + setConnection(); + List<MloLink> mloLinks = new ArrayList<>(); + // Build MLO link with null link mac address + MloLink link1 = new MloLink(); + link1.setBand(WifiScanner.WIFI_BAND_24_GHZ); + link1.setChannel(TEST_CHANNEL); + link1.setLinkId(TEST_MLO_LINK_ID); + link1.setRssi(TEST_RSSI); + mloLinks.add(link1); + when(mScanResult.getApMldMacAddress()).thenReturn(TEST_AP_MLD_MAC_ADDRESS); + when(mScanResult.getApMloLinkId()).thenReturn(TEST_MLO_LINK_ID); + when(mScanResult.getAffiliatedMloLinks()).thenReturn(mloLinks); + mScanResult.level = TEST_RSSI; + when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID)) + .thenReturn(mScanDetailCache); + when(mScanDetailCache.getScanResult(any())).thenReturn(mScanResult); + // Associate + mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, + new StateChangeResult(FRAMEWORK_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR, sFreq, + SupplicantState.ASSOCIATED)); + mLooper.dispatchAll(); + // Test isAffiliatedLinkBssid match fails with no NPE + assertFalse(mCmi.isAffiliatedLinkBssid(MacAddress.fromString(TEST_BSSID_STR))); + } + /** * Verify MLO parameters update from ScanResult at association */ @@ -10264,7 +10435,7 @@ public class ClientModeImplTest extends WifiBaseTest { mCmi.connectNetwork( new NetworkUpdateResult(TEST_NETWORK_ID), new ActionListenerWrapper(connectActionListener), - Process.SYSTEM_UID, OP_PACKAGE_NAME); + Process.SYSTEM_UID, OP_PACKAGE_NAME, null); mLooper.dispatchAll(); verify(connectActionListener).onSuccess(); if (shouldDropRequest) { @@ -10277,13 +10448,22 @@ public class ClientModeImplTest extends WifiBaseTest { } private ScanResult makeScanResult(String ssid, String caps) { - ScanResult scanResult = new ScanResult(WifiSsid.fromUtf8Text(ssid.replace("\"", "")), - ssid, TEST_BSSID_STR, 1245, 0, caps, -78, 2412, 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder( + WifiSsid.fromUtf8Text(ssid.replace("\"", "")), + TEST_BSSID_STR) + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID, ssid.getBytes(StandardCharsets.UTF_8)); scanResult.informationElements = new ScanResult.InformationElement[]{ie}; return scanResult; - } private void verifyConnectWithDisabledPskType( @@ -10734,6 +10914,28 @@ public class ClientModeImplTest extends WifiBaseTest { assertEquals(links.get(1).getBand(), WifiScanner.WIFI_BAND_5_GHZ); assertEquals(links.get(1).getChannel(), TEST_CHANNEL_1); assertEquals(links.get(1).getLinkId(), TEST_MLO_LINK_ID_1); + + // Make sure the dynamic attributes (Tx link speed, Rx link speed and RSSI) are matching + // with poll results for associated links. + assertEquals(65, links.get(0).getTxLinkSpeedMbps()); + assertEquals(54, links.get(0).getRxLinkSpeedMbps()); + assertEquals(-42, links.get(0).getRssi()); + + // Make sure the RSSI is matching with scan cache for un-associated links + assertEquals(TEST_RSSI, links.get(1).getRssi()); + + // Send signal poll for un-associated link + signalPollResults = new WifiSignalPollResults(); + signalPollResults.addEntry(TEST_MLO_LINK_ID_1, -42, 65, 54, sFreq); + when(mWifiNative.signalPoll(any())).thenReturn(signalPollResults); + mCmi.enableRssiPolling(true); + mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1); + mLooper.dispatchAll(); + links = mWifiInfo.getAffiliatedMloLinks(); + + // Make sure the RSSI is matching with scan result for associated link + assertEquals(TEST_RSSI, links.get(0).getRssi()); + } /** @@ -10831,4 +11033,71 @@ public class ClientModeImplTest extends WifiBaseTest { assertEquals(53, links.get(0).getChannel()); assertEquals(WifiScanner.WIFI_BAND_6_GHZ, links.get(0).getBand()); } + + /** + * Verify that we disconnect Wi-Fi 7 is toggled. + */ + @Test + public void verifyDisconnectOnTogglingWifi7() throws Exception { + connect(); + + WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork); + mConnectedNetwork.setWifi7Enabled(false); + + for (WifiConfigManager.OnNetworkUpdateListener listener : mConfigUpdateListenerCaptor + .getAllValues()) { + listener.onNetworkUpdated(mConnectedNetwork, oldConfig, false); + } + mLooper.dispatchAll(); + verify(mWifiNative).disconnect(WIFI_IFACE_NAME); + verify(mWifiMetrics).logStaEvent(anyString(), eq(StaEvent.TYPE_FRAMEWORK_DISCONNECT), + eq(StaEvent.DISCONNECT_NETWORK_WIFI7_TOGGLED)); + } + + private void testDhcpHostnameSetting( + boolean configEnabled, + @WifiManager.SendDhcpHostnameRestriction int restriction, + int security, + int expectedHostnameSetting) throws Exception { + if (!SdkLevel.isAtLeastV()) { + expectedHostnameSetting = IIpClient.HOSTNAME_SETTING_UNSET; + } + when(mWifiGlobals.getSendDhcpHostnameRestriction()).thenReturn(restriction); + mConnectedNetwork.setSecurityParams(security); + mConnectedNetwork.setSendDhcpHostnameEnabled(configEnabled); + connect(); + + verify(mIpClient).startProvisioning(mProvisioningConfigurationCaptor.capture()); + assertEquals(expectedHostnameSetting, + mProvisioningConfigurationCaptor.getValue().hostnameSetting); + } + + @Test + public void testSendDhcpHostnameEnabled() throws Exception { + testDhcpHostnameSetting(true, 0, SECURITY_TYPE_OPEN, IIpClient.HOSTNAME_SETTING_SEND); + } + + @Test + public void testSendDhcpHostnameDisabled() throws Exception { + testDhcpHostnameSetting(false, 0, + SECURITY_TYPE_OPEN, IIpClient.HOSTNAME_SETTING_DO_NOT_SEND); + } + + @Test + public void testSendDhcpHostnameEnabledWithOpenRestriction() throws Exception { + testDhcpHostnameSetting(true, WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN, + SECURITY_TYPE_OPEN, IIpClient.HOSTNAME_SETTING_DO_NOT_SEND); + } + + @Test + public void testSendDhcpHostnameEnabledWithOpenRestrictionOwe() throws Exception { + testDhcpHostnameSetting(true, WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN, + SECURITY_TYPE_OWE, IIpClient.HOSTNAME_SETTING_DO_NOT_SEND); + } + + @Test + public void testSendDhcpHostnameEnabledWithSecureRestriction() throws Exception { + testDhcpHostnameSetting(true, WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE, + SECURITY_TYPE_PSK, IIpClient.HOSTNAME_SETTING_DO_NOT_SEND); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/ConcreteClientModeManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/ConcreteClientModeManagerTest.java index a823f64c08..e30e8f8262 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ConcreteClientModeManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ConcreteClientModeManagerTest.java @@ -61,10 +61,11 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.RegistrationManager; -import android.test.suitebuilder.annotation.SmallTest; import android.util.LocalLog; import android.util.Log; +import androidx.test.filters.SmallTest; + import com.android.server.wifi.ClientModeManagerBroadcastQueue.QueuedBroadcast; import com.android.wifi.resources.R; @@ -779,6 +780,33 @@ public class ConcreteClientModeManagerTest extends WifiBaseTest { } /** + * Secondary CMM will stop without deferring. + */ + @Test + public void clientModeStopWithWifiOffDeferringTimeWithWifiCallingOnSecondaryTransient() + throws Exception { + setUpVoWifiTest(true, + TEST_WIFI_OFF_DEFERRING_TIME_MS); + startClientInConnectModeAndVerifyEnabled(); + reset(mContext, mListener); + setUpSystemServiceForContext(); + + // Make sure CMM is not primary + mClientModeManager.setRole(ROLE_CLIENT_SECONDARY_TRANSIENT, TEST_WORKSOURCE); + mLooper.dispatchAll(); + + // Stop CMM and verify the Defer stop code is skipped + mClientModeManager.stop(); + mLooper.dispatchAll(); + when(mClientModeImpl.hasQuit()).thenReturn(true); + mClientModeManager.onClientModeImplQuit(); + verify(mListener).onStopped(mClientModeManager); + verify(mImsMmTelManager, never()).registerImsRegistrationCallback(any(), any()); + verify(mImsMmTelManager, never()).unregisterImsRegistrationCallback(any()); + verify(mWifiMetrics).noteWifiOff(eq(false), eq(false), anyInt()); + } + + /** * ClientMode stop properly with IMS deferring time without WifiCalling. */ @Test diff --git a/service/tests/wifitests/src/com/android/server/wifi/ConnectHelperTest.java b/service/tests/wifitests/src/com/android/server/wifi/ConnectHelperTest.java index dc4e2b7091..bdf82a75b2 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ConnectHelperTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ConnectHelperTest.java @@ -17,6 +17,7 @@ package com.android.server.wifi; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -44,6 +45,7 @@ public class ConnectHelperTest extends WifiBaseTest { private static final int TEST_NETWORK_ID = 42; private static final String TEST_SSID = "TestSSID"; private static final String TEST_PACKAGE_NAME = "com.test.xxx"; + private static final String TEST_ATTRIBUTION_TAG = "TEST_ATTRIBUTION_TAG"; private ConnectHelper mConnectHelper; @@ -68,33 +70,42 @@ public class ConnectHelperTest extends WifiBaseTest { mWifiConfig.networkId = TEST_NETWORK_ID; } - @Test - public void connectToNetwork_success() throws Exception { + private void verifyConnectNetworkSuccess(String attributionTag, boolean expectDisableOthers) { when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(mWifiConfig); NetworkUpdateResult result = new NetworkUpdateResult(TEST_NETWORK_ID); mConnectHelper.connectToNetwork(result, mActionListener, TEST_CALLING_UID, - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, attributionTag); verify(mWifiConfigManager).updateBeforeConnect(TEST_NETWORK_ID, TEST_CALLING_UID, - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, expectDisableOthers); verify(mClientModeManager).connectNetwork(eq(result), any(), eq(TEST_CALLING_UID), - eq(TEST_PACKAGE_NAME)); + eq(TEST_PACKAGE_NAME), eq(attributionTag)); // success is sent by ClientModeManager, not sent by ConnectHelper verify(mActionListener, never()).sendSuccess(); verify(mActionListener, never()).sendFailure(anyInt()); } @Test + public void connectToNetwork_success() throws Exception { + verifyConnectNetworkSuccess(TEST_ATTRIBUTION_TAG, true); + } + + @Test + public void connectToNetwork_successDisallowUserConnectChoice() throws Exception { + verifyConnectNetworkSuccess(ClientModeImpl.ATTRIBUTION_TAG_DISALLOW_CONNECT_CHOICE, false); + } + + @Test public void connectToNetwork_invalidNetId_failure() throws Exception { when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(null); mConnectHelper.connectToNetwork(new NetworkUpdateResult(TEST_NETWORK_ID), mActionListener, - TEST_CALLING_UID, TEST_PACKAGE_NAME); + TEST_CALLING_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_TAG); - verify(mWifiConfigManager, never()).updateBeforeConnect(TEST_NETWORK_ID, TEST_CALLING_UID, - TEST_PACKAGE_NAME); - verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any()); + verify(mWifiConfigManager, never()).updateBeforeConnect(anyInt(), anyInt(), + any(), anyBoolean()); + verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any(), any()); verify(mActionListener).sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR); verify(mActionListener, never()).sendSuccess(); } diff --git a/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java index f060cddac4..1870690353 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java @@ -79,7 +79,8 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import com.android.internal.util.WakeupMessage; import com.android.modules.utils.build.SdkLevel; @@ -855,9 +856,18 @@ public class DppManagerTest extends WifiBaseTest { */ private void addTestNetworkInScanResult(int frequency) { String caps = "[WPA2-FT/SAE+SAE][ESS][WPS]"; - ScanResult scanResult = new ScanResult(WifiSsid.fromUtf8Text(TEST_SSID_NO_QUOTE), - TEST_SSID_NO_QUOTE, TEST_BSSID, 1245, 0, caps, -78, frequency, - 1025, 22, 33, 20, 0, 0, true); + ScanResult scanResult = new ScanResult.Builder( + WifiSsid.fromUtf8Text(TEST_SSID_NO_QUOTE), + TEST_BSSID) + .setHessid(1245) + .setCaps(caps) + .setRssi(-78) + .setFrequency(frequency) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); List<ScanResult> scanResults = new ArrayList<>(); scanResults.add(scanResult); when(mScanRequestProxy.getScanResults()).thenReturn(scanResults); diff --git a/service/tests/wifitests/src/com/android/server/wifi/DppMetricsTest.java b/service/tests/wifitests/src/com/android/server/wifi/DppMetricsTest.java index d0e4cbc793..40d4694fdd 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/DppMetricsTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/DppMetricsTest.java @@ -39,7 +39,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; -import android.test.suitebuilder.annotation.SmallTest; +import androidx.test.filters.SmallTest; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.proto.nano.WifiMetricsProto; diff --git a/service/tests/wifitests/src/com/android/server/wifi/HostapdHalAidlImpTest.java b/service/tests/wifitests/src/com/android/server/wifi/HostapdHalAidlImpTest.java index 8fd5c3e7e9..8328dd3618 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/HostapdHalAidlImpTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/HostapdHalAidlImpTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -165,7 +166,7 @@ public class HostapdHalAidlImpTest extends WifiBaseTest { verify(mockSoftApHalCallback).onInfoChanged(eq(TEST_AP_INSTANCE), eq(TEST_FREQ_24G), eq(mHostapdHal.mapHalChannelBandwidthToSoftApInfo(TEST_BANDWIDTH)), eq(mHostapdHal.mapHalGenerationToWifiStandard(TEST_GENERATION)), - eq(MacAddress.fromString(TEST_CLIENT_MAC))); + eq(MacAddress.fromString(TEST_CLIENT_MAC)), anyList()); } else if (numOfApInfo == 2) { apInfo.apIfaceInstance = TEST_AP_INSTANCE_2; apInfo.freqMhz = TEST_FREQ_5G; @@ -173,7 +174,7 @@ public class HostapdHalAidlImpTest extends WifiBaseTest { verify(mockSoftApHalCallback).onInfoChanged(eq(TEST_AP_INSTANCE_2), eq(TEST_FREQ_5G), eq(mHostapdHal.mapHalChannelBandwidthToSoftApInfo(TEST_BANDWIDTH)), eq(mHostapdHal.mapHalGenerationToWifiStandard(TEST_GENERATION)), - eq(MacAddress.fromString(TEST_CLIENT_MAC))); + eq(MacAddress.fromString(TEST_CLIENT_MAC)), anyList()); } } @@ -893,7 +894,7 @@ public class HostapdHalAidlImpTest extends WifiBaseTest { // Trigger on info changed and verify. mockApInfoChangedAndVerify(IFACE_NAME, 1, mIHostapdCallback, mSoftApHalCallback); verify(mSoftApHalCallback1, never()).onInfoChanged(anyString(), anyInt(), anyInt(), - anyInt(), any()); + anyInt(), any(), anyList()); // Trigger on client connected. ClientInfo clientInfo = new ClientInfo(); diff --git a/service/tests/wifitests/src/com/android/server/wifi/HostapdHalHidlImpTest.java b/service/tests/wifitests/src/com/android/server/wifi/HostapdHalHidlImpTest.java index 44dc1512f9..f1a3c312d7 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/HostapdHalHidlImpTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/HostapdHalHidlImpTest.java @@ -1321,9 +1321,9 @@ public class HostapdHalHidlImpTest extends WifiBaseTest { verify(mSoftApHalCallback).onInfoChanged(eq(TEST_AP_INSTANCE), eq(testFreq), eq(mHostapdHal.mapHalBandwidthToSoftApInfo(testBandwidth)), eq(mHostapdHal.mapHalGenerationToWifiStandard(testGeneration)), - eq(MacAddress.fromString(TEST_CLIENT_MAC))); + eq(MacAddress.fromString(TEST_CLIENT_MAC)), anyList()); verify(mSoftApHalCallback1, never()).onInfoChanged(anyString(), anyInt(), anyInt(), - anyInt(), any()); + anyInt(), any(), anyList()); // Trigger on client connected. mIHostapdCallback13.onConnectedClientsChanged(IFACE_NAME, TEST_AP_INSTANCE, diff --git a/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java b/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java index af60b424e6..3addabb430 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/InsecureEapNetworkHandlerTest.java @@ -99,6 +99,7 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { private static final int TEST_GEN_SERVER_CERT = 2; private static final int TEST_GEN_SELF_SIGNED_CERT = 3; private static final int TEST_GEN_FAKE_CA_CERT = 4; + private static final int TEST_GEN_SERVER_CERTIFICATE_WITHOUT_COMMON_NAME = 5; private static final String TEST_SERVER_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n" + "MIIGPjCCBCagAwIBAgIUN2Ss1JmvjveRe97iWoNh4V+Y5LYwDQYJKoZIhvcNAQEM\n" @@ -279,6 +280,42 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { + "jUR49A==\n" + "-----END CERTIFICATE-----"; + private static final String TEST_SERVER_CERTIFICATE_WITHOUT_COMMON_NAME = + "-----BEGIN CERTIFICATE-----\n" + + "MIIF+zCCA+OgAwIBAgIUCvmbTyLRy+5/Tt8iSpBB+xmZTfUwDQYJKoZIhvcNAQEM\n" + + "BQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRswGQYDVQQK\n" + + "DBJBbmRyb2lkIFdpLUZpIFRlc3QxGDAWBgNVBAsMD2FuZHJvaWR3aWZpLm9lbTE8\n" + + "MDoGA1UEAwwzQW5kcm9pZCBQYXJ0bmVyIFJvb3QgQ0EgZm9yIHRlc3RpbmcgYW5k\n" + + "IGRldmVsb3BtZW50MB4XDTI0MDMxMzE3NTIwMFoXDTI2MDMxMzE3NTIwMFowQTEL\n" + + "MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExHTAbBgNVBAoMFEFuZHJv\n" + + "aWQgV2ktRmkgVGVzdGVyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA\n" + + "uVNdRG1M/DVcfqi1Cl1FRXxZ2eeKe/IM6OA4KhkR0aymZtjmsoTO52JFVoTykCrj\n" + + "bnDp6wOTDaglwbClip/Be5Oj//6LS+A5J3PqUfQsOI+s8ZeAu6s4Kur4g0oPhfNz\n" + + "msRyQvhIUkwYCXEum+uQ3INLpy38JggEbTRR4nnn2UUh4+Shv9xYA/SiYrV/sd/f\n" + + "Vj++lAmOUQu/CLCWtpfBFTeiyg/DhypbHQVPnr+k1QBy7DKZlBXQb7POjE4M6Ed/\n" + + "/st11tB8qHZnM8Xe4CdM3xSJj9qs2BQyT228z7SCmA3r3P1CMvSRYqWu1mn4iMO1\n" + + "t0sShF/OfUkihE1ADA0q6GRHDLQ3T/TSnuYWyH4/iMMygHl+yfDeECaLOn/KEQM9\n" + + "hOBlXo5iKB/GMkFKeoGQQePwWllHK7HjNEAOOPyXS4nzRA1VUq0gVvhFpQX7ZK9X\n" + + "OWdNdcnof4wzOEJse96I7v3A1C0FYg57f1HKOnx195hb1wQfi0MOyE/mgqvtVWbP\n" + + "90Vd2nFMlNSVc38DUT7jyYTygUAl5eQDRZo/npNs32nf8YW4cWmN1r+LCHUkK22v\n" + + "y8bmSVTts7WHzx9K1kg5+XvaTxpgmmFneuh0XIFvTcGFwMPrHzwaa5pOCYjUvlSy\n" + + "GXOmRuSqFipufxxlRKM0cJhMUqI/vmYJ5byx5Wb1N+MCAwEAAaOBkzCBkDAdBgNV\n" + + "HQ4EFgQUz4BlPUEPOANhQ74NbClj0CrdiHswHwYDVR0jBBgwFoAUyWVsWmPxPCB6\n" + + "D7hRF7K2vyVzKOMwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYI\n" + + "KwYBBQUHAwEwIQYDVR0RBBowGIIWc2VydmVyLmFuZHJvaWR3aWZpLm9lbTANBgkq\n" + + "hkiG9w0BAQwFAAOCAgEAkf5CHaqzDsQKn8udsA9/fIKSOEqr0LUfwP20JzFe0HBA\n" + + "F3cWoMrEVoAJFfi5NFQJOjlEib7kvu2MI92lL6ch3D3iW5mnY5Ncnm2eyqi1kvii\n" + + "uueKnH4a9jsolWgcsGiw5vUhsodgxWzFr/yDURYZEWkzP4uiW3+0K6eoc11DPiDr\n" + + "16LS4xAINHVeEDhhkuZG2Bqo1ctbcQWR7Leb5JGpfkC7xNGyVNUwJYjI5vow5GzR\n" + + "Af2SvJuG3mMxBfM+8TMx4wf4Sgq80FmaJLNAOlfKlYIN0u/NV/pq6nWb0B4u3K0u\n" + + "ytH3BRJsuKg35fZEy4qRpBZL1Us9FzwPkRaUK+Sgtz9BLRPL5my3xUwnZaqw+ZRp\n" + + "Gw+vwErnSc3md9DhYMeGc0JdA141/pxc/P20hoLG7cDK/tO4PwBzNrF57XLEFC7v\n" + + "bww0rQoADGCIk48n2gZX/wh1XeHWJhk7C+lGGbA/qrs5zZbzDaMi/N3C74eiQJOH\n" + + "KdQk10pt2nU8xwC/RsfL7W+2K4c4/mZvaroxQvIxs8tRB3glbpwQe4HntpE0LdvH\n" + + "7hotzbIt0YtGtzIdOwpR277a73qT09pmYL97+rwPGWMviCkb9QNvFHBKc0MsgxXz\n" + + "15THXfttbGruZySMyj9kMox0NbhsVKiSEEiqMMHvJMbn4FDI1O9U5IDZdUplI0A=\n" + + "-----END CERTIFICATE-----"; + @Mock WifiContext mContext; @Mock WifiConfigManager mWifiConfigManager; @Mock WifiNative mWifiNative; @@ -660,6 +697,8 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { certString = TEST_SELF_SIGNED_CERTIFICATE; } else if (type == TEST_GEN_FAKE_CA_CERT) { certString = TEST_FAKE_CA_CERTIFICATE; + } else if (type == TEST_GEN_SERVER_CERTIFICATE_WITHOUT_COMMON_NAME) { + certString = TEST_SERVER_CERTIFICATE_WITHOUT_COMMON_NAME; } else { throw (new Exception()); } @@ -921,6 +960,31 @@ public class InsecureEapNetworkHandlerTest extends WifiBaseTest { } /** + * Verify that is reports errors if the server certificate doesn't contain the common name + */ + @Test + public void verifyOnErrorWithServerCertificateWithoutCommonName() throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + boolean isAtLeastT = true, isTrustOnFirstUseSupported = true, isUserSelected = true; + + WifiConfiguration config = prepareWifiConfiguration(isAtLeastT); + setupTest(config, isAtLeastT, isTrustOnFirstUseSupported); + + CertificateEventInfo mockCaCert = generateMockCertEventInfo(TEST_GEN_CA2_CERT); + // Server certificate without common name + CertificateEventInfo mockServerCert = + generateMockCertEventInfo(TEST_GEN_SERVER_CERTIFICATE_WITHOUT_COMMON_NAME); + mInsecureEapNetworkHandler.addPendingCertificate(config.networkId, 1, mockCaCert); + mInsecureEapNetworkHandler.addPendingCertificate(config.networkId, 0, mockServerCert); + + mInsecureEapNetworkHandler.startUserApprovalIfNecessary(isUserSelected); + verify(mCallbacks).onError(eq(config.SSID)); + verify(mWifiConfigManager, atLeastOnce()).updateNetworkSelectionStatus(eq(config.networkId), + eq(WifiConfiguration.NetworkSelectionStatus + .DISABLED_BY_WIFI_MANAGER)); + } + + /** * Verify that setting pending certificate won't crash with no current configuration. */ @Test diff --git a/service/tests/wifitests/src/com/android/server/wifi/MultiInternetWifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/MultiInternetWifiNetworkFactoryTest.java index 70412573f0..fa1dc98e00 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/MultiInternetWifiNetworkFactoryTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/MultiInternetWifiNetworkFactoryTest.java @@ -39,9 +39,10 @@ import android.net.wifi.WifiNetworkSpecifier; import android.os.PatternMatcher; import android.os.WorkSource; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; import android.util.LocalLog; +import androidx.test.filters.SmallTest; + import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.util.WifiPermissionsUtil; @@ -50,6 +51,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; + /** * Unit tests for {@link com.android.server.wifi.MultiInternetWifiNetworkFactory}. */ diff --git a/service/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java b/service/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java index 3598cf128e..06384c3138 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java @@ -103,6 +103,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<int name=\"DeletionPriority\" value=\"0\" />\n" + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + "<boolean name=\"RepeaterEnabled\" value=\"false\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"true\" />\n" + "<SecurityParamsList>\n" + "<SecurityParams>\n" + "<int name=\"SecurityType\" value=\"0\" />\n" @@ -121,6 +122,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + "</SecurityParams>\n" + "</SecurityParamsList>\n" + + "<boolean name=\"SendDhcpHostname\" value=\"true\" />\n" + "<boolean name=\"Trusted\" value=\"true\" />\n" + "<boolean name=\"IsRestricted\" value=\"false\" />\n" + "<boolean name=\"OemPaid\" value=\"false\" />\n" @@ -192,6 +194,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<int name=\"DeletionPriority\" value=\"0\" />\n" + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + "<boolean name=\"RepeaterEnabled\" value=\"false\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"true\" />\n" + "<SecurityParamsList>\n" + "<SecurityParams>\n" + "<int name=\"SecurityType\" value=\"3\" />\n" @@ -210,6 +213,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + "</SecurityParams>\n" + "</SecurityParamsList>\n" + + "<boolean name=\"SendDhcpHostname\" value=\"true\" />\n" + "<boolean name=\"Trusted\" value=\"true\" />\n" + "<boolean name=\"IsRestricted\" value=\"false\" />\n" + "<boolean name=\"OemPaid\" value=\"false\" />\n" @@ -315,6 +319,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<int name=\"DeletionPriority\" value=\"0\" />\n" + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + "<boolean name=\"RepeaterEnabled\" value=\"false\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"true\" />\n" + "<SecurityParamsList>\n" + "<SecurityParams>\n" + "<int name=\"SecurityType\" value=\"4\" />\n" @@ -325,6 +330,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + "</SecurityParams>\n" + "</SecurityParamsList>\n" + + "<boolean name=\"SendDhcpHostname\" value=\"true\" />\n" + "<boolean name=\"Trusted\" value=\"true\" />\n" + "<boolean name=\"IsRestricted\" value=\"false\" />\n" + "<boolean name=\"OemPaid\" value=\"false\" />\n" @@ -396,6 +402,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<int name=\"DeletionPriority\" value=\"0\" />\n" + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + "<boolean name=\"RepeaterEnabled\" value=\"false\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"true\" />\n" + "<SecurityParamsList>\n" + "<SecurityParams>\n" + "<int name=\"SecurityType\" value=\"3\" />\n" @@ -414,6 +421,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + "</SecurityParams>\n" + "</SecurityParamsList>\n" + + "<boolean name=\"SendDhcpHostname\" value=\"true\" />\n" + "<boolean name=\"Trusted\" value=\"true\" />\n" + "<boolean name=\"OemPaid\" value=\"false\" />\n" + "<boolean name=\"OemPrivate\" value=\"false\" />\n" @@ -521,6 +529,7 @@ public class NetworkListStoreDataTest extends WifiBaseTest { + "<int name=\"DeletionPriority\" value=\"0\" />\n" + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + "<boolean name=\"RepeaterEnabled\" value=\"false\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"true\" />\n" + "<boolean name=\"Trusted\" value=\"true\" />\n" + "<null name=\"BSSID\" />\n" + "<int name=\"Status\" value=\"2\" />\n" diff --git a/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java b/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java index b89a150738..7d65e3f78f 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java @@ -42,6 +42,7 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiNetworkSuggestion; import android.net.wifi.WifiSsid; +import android.os.Process; import android.telephony.SubscriptionManager; import android.util.LocalLog; import android.util.Pair; @@ -1820,6 +1821,53 @@ public class NetworkSuggestionNominatorTest extends WifiBaseTest { .incrementNetworkSuggestionMoreThanOneSuggestionForSingleScanResult(); } + /** + * Ensure that we nominate the one matching network suggestion. + * Because the only matched suggestion is restricted and suggested by the SYSTEM_SERVER + * Expected connectable Networks: {suggestionSsids[0]} + */ + @Test + public void testSelectNetworkSuggestionForOneMatchRestrictedAllowBySystemServer() { + String[] scanSsids = {"test1", "test2"}; + String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"}; + int[] freqs = {2470, 2437}; + String[] caps = {"[WPA2-EAP/SHA1-CCMP][ESS]", "[WPA2-EAP/SHA1-CCMP][ESS]"}; + int[] levels = {-67, -76}; + String[] suggestionSsids = {"\"" + scanSsids[0] + "\""}; + int[] securities = {SECURITY_PSK}; + boolean[] appInteractions = {true}; + boolean[] meteredness = {true}; + int[] priorities = {-1}; + int[] uids = {Process.SYSTEM_UID}; + String[] packageNames = {TEST_PACKAGE}; + boolean[] autojoin = {true}; + boolean[] shareWithUser = {true}; + int[] priorityGroup = {0}; + + ScanDetail[] scanDetails = + buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock); + ExtendedWifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, + securities, appInteractions, meteredness, priorities, uids, + packageNames, autojoin, shareWithUser, priorityGroup); + suggestions[0].wns.wifiConfiguration.restricted = true; + // Link the scan result with suggestions. + linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions); + + setupAddToWifiConfigManager(suggestions[0]); + + List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>(); + mNetworkSuggestionNominator.nominateNetworks( + Arrays.asList(scanDetails), mPasspointCandidates, true, false, false, + Collections.emptySet(), // restrictedNetworkAllowedUids is empty + (ScanDetail scanDetail, WifiConfiguration configuration) -> { + connectableNetworks.add(Pair.create(scanDetail, configuration)); + }); + + validateConnectableNetworks(connectableNetworks, scanSsids[0]); + verify(mWifiMetrics, never()) + .incrementNetworkSuggestionMoreThanOneSuggestionForSingleScanResult(); + } + private void setupAddToWifiConfigManager(ExtendedWifiNetworkSuggestion...candidates) { for (int i = 0; i < candidates.length; i++) { WifiConfiguration candidate = candidates[i].createInternalWifiConfiguration( diff --git a/service/tests/wifitests/src/com/android/server/wifi/OemWifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/OemWifiNetworkFactoryTest.java index 63e811dbc7..45439e0ed6 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/OemWifiNetworkFactoryTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/OemWifiNetworkFactoryTest.java @@ -25,7 +25,8 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.WorkSource; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import com.android.modules.utils.build.SdkLevel; diff --git a/service/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java b/service/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java index 533c5b95a3..e061ea5e3f 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java @@ -554,7 +554,7 @@ public class OpenNetworkNotifierTest extends WifiBaseTest { @Test public void actionConnectToNetwork_notificationNotShowing_doesNothing() { mBroadcastReceiver.onReceive(mContext, createIntent(ACTION_CONNECT_TO_NETWORK)); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); } /** @@ -575,7 +575,7 @@ public class OpenNetworkNotifierTest extends WifiBaseTest { mBroadcastReceiver.onReceive(mContext, createIntent(ACTION_CONNECT_TO_NETWORK)); verify(mConnectHelper).connectToNetwork(eq(new NetworkUpdateResult(TEST_NETWORK_ID)), - any(ActionListenerWrapper.class), eq(Process.SYSTEM_UID), any()); + any(ActionListenerWrapper.class), eq(Process.SYSTEM_UID), any(), any()); // Connecting Notification verify(mNotificationBuilder).createNetworkConnectingNotification(OPEN_NET_NOTIFIER_TAG, mTestNetwork); @@ -759,7 +759,7 @@ public class OpenNetworkNotifierTest extends WifiBaseTest { ArgumentCaptor<ActionListenerWrapper> connectListenerCaptor = ArgumentCaptor.forClass(ActionListenerWrapper.class); verify(mConnectHelper).connectToNetwork(eq(new NetworkUpdateResult(TEST_NETWORK_ID)), - connectListenerCaptor.capture(), eq(Process.SYSTEM_UID), any()); + connectListenerCaptor.capture(), eq(Process.SYSTEM_UID), any(), any()); ActionListenerWrapper connectListener = connectListenerCaptor.getValue(); // Connecting Notification diff --git a/service/tests/wifitests/src/com/android/server/wifi/OuiKeyedDataUtil.java b/service/tests/wifitests/src/com/android/server/wifi/OuiKeyedDataUtil.java new file mode 100644 index 0000000000..3be43596a2 --- /dev/null +++ b/service/tests/wifitests/src/com/android/server/wifi/OuiKeyedDataUtil.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 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.wifi.OuiKeyedData; +import android.os.PersistableBundle; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test utils for {@link OuiKeyedData}. Implementation is the same as + * {@link android.net.wifi.OuiKeyedDataUtil} + */ +public class OuiKeyedDataUtil { + private static final String STRING_FIELD_KEY = "stringField"; + private static final String ARRAY_FIELD_KEY = "arrayField"; + + private static final String STRING_FIELD_VALUE = "someString"; + private static final int[] ARRAY_FIELD_VALUE = new int[] {1, 2, 3}; + + /** + * Generate a single OuiKeyedData object containing several test fields. + */ + public static OuiKeyedData createTestOuiKeyedData(int oui) { + PersistableBundle bundle = new PersistableBundle(); + bundle.putString(STRING_FIELD_KEY, STRING_FIELD_VALUE); + bundle.putIntArray(ARRAY_FIELD_KEY, ARRAY_FIELD_VALUE); + return new OuiKeyedData.Builder(oui, bundle).build(); + } + + /** + * Generate a list of OuiKeyedData objects, each containing several test fields. + */ + public static List<OuiKeyedData> createTestOuiKeyedDataList(int size) { + List<OuiKeyedData> ouiKeyedDataList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + ouiKeyedDataList.add(createTestOuiKeyedData(i + 1)); + } + return ouiKeyedDataList; + } +} diff --git a/service/tests/wifitests/src/com/android/server/wifi/RestrictedWifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/RestrictedWifiNetworkFactoryTest.java index eca0a01e0a..12cac6ece4 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/RestrictedWifiNetworkFactoryTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/RestrictedWifiNetworkFactoryTest.java @@ -27,7 +27,8 @@ import android.content.Context; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import org.junit.After; import org.junit.Before; diff --git a/service/tests/wifitests/src/com/android/server/wifi/SavedNetworkNominatorTest.java b/service/tests/wifitests/src/com/android/server/wifi/SavedNetworkNominatorTest.java index 025973cabc..850f8a7a82 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/SavedNetworkNominatorTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/SavedNetworkNominatorTest.java @@ -26,10 +26,11 @@ import static org.mockito.Mockito.*; import android.net.MacAddress; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; -import android.test.suitebuilder.annotation.SmallTest; import android.util.LocalLog; import android.util.Pair; +import androidx.test.filters.SmallTest; + import com.android.server.wifi.WifiNetworkSelector.NetworkNominator.OnConnectableListener; import com.android.server.wifi.WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs; import com.android.server.wifi.entitlement.PseudonymInfo; diff --git a/service/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java b/service/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java index ccbc456203..7c690e7856 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java +++ b/service/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java @@ -311,9 +311,11 @@ public class ScanTestUtil { } public static ScanResult createScanResult(int freq) { - return new ScanResult(WifiSsid.fromUtf8Text("AN SSID"), - MacAddressUtils.createRandomUnicastAddress().toString(), 0L, - -1, null, "", 0, freq, 0); + return new ScanResult.Builder(WifiSsid.fromUtf8Text("AN SSID"), + MacAddressUtils.createRandomUnicastAddress().toString()) + .setCaps("") + .setFrequency(freq) + .build(); } private static ScanData createScanData(int[] freqs, int bucketsScanned, int bandScanned) { diff --git a/service/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java b/service/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java index cc9080fdb6..b8759d84df 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java @@ -18,6 +18,8 @@ package com.android.server.wifi; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -276,6 +278,10 @@ public class SelfRecoveryTest extends WifiBaseTest { @Test public void testUnsolicitedSystemRestart() { mRestartListenerCaptor.getValue().onSubsystemRestart(); + ExtendedMockito.verify(() -> WifiStatsLog.write(eq(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED), + eq(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__REASON__REASON_SUBSYSTEM_RESTART), + eq(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__RESULT__RES_RESTART_STARTED_INTERNAL_RECOVERY_BY_NATIVE_CALLBACK), + anyLong())); verify(mActiveModeWarden).recoveryRestartWifi(SelfRecovery.REASON_SUBSYSTEM_RESTART, true); assertTrue(mSelfRecovery.isRecoveryInProgress()); @@ -369,15 +375,20 @@ public class SelfRecoveryTest extends WifiBaseTest { 10000L)); when(mClock.getWallClockMillis()).thenReturn(100000L); - when(mWifiNative.startSubsystemRestart()).thenReturn(false); + doAnswer((invocation) -> { + return false; + }).when(mWifiNative).startSubsystemRestart(); mSelfRecovery.trigger(SelfRecovery.REASON_API_CALL); ExtendedMockito.verify(() -> WifiStatsLog.write(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED, WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__REASON__REASON_API_CALL, - WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__RESULT__RES_RESTART_FAILURE, + WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__RESULT__RES_RESTART_STARTED_INTERNAL_RECOVERY, 20000L)); when(mClock.getWallClockMillis()).thenReturn(160000L); - when(mWifiNative.startSubsystemRestart()).thenReturn(true); + doAnswer((invocation) -> { + mRestartListenerCaptor.getValue().onSubsystemRestart(); + return true; + }).when(mWifiNative).startSubsystemRestart(); mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG); ExtendedMockito.verify(() -> WifiStatsLog.write(WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED, WifiStatsLog.WIFI_SELF_RECOVERY_TRIGGERED__REASON__REASON_LAST_RESORT_WDOG, diff --git a/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java index 8cfd632061..03ca47d3fb 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java @@ -63,17 +63,21 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.net.MacAddress; +import android.net.TetheringManager; import android.net.wifi.CoexUnsafeChannel; +import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration.Builder; import android.net.wifi.SoftApInfo; +import android.net.wifi.SoftApState; import android.net.wifi.WifiClient; import android.net.wifi.WifiContext; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; +import android.net.wifi.nl80211.DeviceWiphyCapabilities; import android.net.wifi.nl80211.NativeWifiClient; import android.os.BatteryManager; import android.os.Message; @@ -105,6 +109,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -125,6 +130,7 @@ public class SoftApManagerTest extends WifiBaseTest { private static final String TEST_FIRST_INSTANCE_NAME = "testif1"; private static final String TEST_SECOND_INSTANCE_NAME = "testif2"; private static final String OTHER_INTERFACE_NAME = "otherif"; + private static final String TEST_STA_INTERFACE_NAME = "testif0sta"; private static final long TEST_DEFAULT_SHUTDOWN_TIMEOUT_MILLIS = 600_000; private static final long TEST_DEFAULT_SHUTDOWN_IDLE_INSTANCE_IN_BRIDGED_MODE_TIMEOUT_MILLIS = 300_000; @@ -160,6 +166,10 @@ public class SoftApManagerTest extends WifiBaseTest { private static final int[] ALLOWED_60G_FREQS = {58320, 60480}; // ch# 1, 2 private static final WorkSource TEST_WORKSOURCE = new WorkSource(); private SoftApConfiguration mDefaultApConfig = createDefaultApConfig(); + + private static final TetheringManager.TetheringRequest TEST_TETHERING_REQUEST = + new TetheringManager.TetheringRequest.Builder(TetheringManager.TETHERING_WIFI).build(); + private final int mBand256G = SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ | SoftApConfiguration.BAND_6GHZ; private static final int[] TEST_SUPPORTED_24G_CHANNELS = new int[] {1, 2}; @@ -207,6 +217,7 @@ public class SoftApManagerTest extends WifiBaseTest { @Mock WifiInjector mWifiInjector; @Mock WifiCountryCode mWifiCountryCode; @Mock LocalLog mLocalLog; + @Mock DeviceWiphyCapabilities mDeviceWiphyCapabilities; final ArgumentCaptor<WifiNative.InterfaceCallback> mWifiNativeInterfaceCallbackCaptor = ArgumentCaptor.forClass(WifiNative.InterfaceCallback.class); @@ -229,14 +240,16 @@ public class SoftApManagerTest extends WifiBaseTest { /** Old callback event from wificond */ private void mockChannelSwitchEvent(int frequency, int bandwidth) { mSoftApHalCallbackCaptor.getValue().onInfoChanged( - TEST_INTERFACE_NAME, frequency, bandwidth, 0, null); + TEST_INTERFACE_NAME, frequency, bandwidth, 0, null, Collections.emptyList()); } /** New callback event from hostapd */ private void mockApInfoChangedEvent(SoftApInfo apInfo) { + List<OuiKeyedData> vendorData = SdkLevel.isAtLeastV() + ? apInfo.getVendorData() : Collections.emptyList(); mSoftApHalCallbackCaptor.getValue().onInfoChanged( apInfo.getApInstanceIdentifier(), apInfo.getFrequency(), apInfo.getBandwidth(), - apInfo.getWifiStandardInternal(), apInfo.getBssidInternal()); + apInfo.getWifiStandardInternal(), apInfo.getBssidInternal(), vendorData); mTestSoftApInfoMap.put(apInfo.getApInstanceIdentifier(), apInfo); mTestWifiClientsMap.put(apInfo.getApInstanceIdentifier(), new ArrayList<WifiClient>()); } @@ -387,9 +400,15 @@ public class SoftApManagerTest extends WifiBaseTest { .thenReturn(mPrimaryWifiInfo); when(mConcreteClientModeManager.getConnectionInfo()) .thenReturn(mPrimaryWifiInfo); + when(mConcreteClientModeManager.getInterfaceName()) + .thenReturn(TEST_STA_INTERFACE_NAME); when(mWifiNative.forceClientDisconnect(any(), any(), anyInt())).thenReturn(true); when(mWifiInjector.getWifiHandlerLocalLog()).thenReturn(mLocalLog); when(mWifiInjector.getWifiCountryCode()).thenReturn(mWifiCountryCode); + when(mWifiNative.getDeviceWiphyCapabilities(any(), anyBoolean())).thenReturn( + mDeviceWiphyCapabilities); + when(mDeviceWiphyCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE)) + .thenReturn(true); // Init Test SoftAp infos mTestSoftApInfo = new SoftApInfo(); @@ -467,7 +486,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void startSoftApWithoutConfig() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); } @@ -479,7 +498,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); } @@ -491,7 +510,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( IFACE_IP_MODE_LOCAL_ONLY, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabledWithUserApproval(apConfig); } @@ -503,15 +522,15 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( IFACE_IP_MODE_LOCAL_ONLY, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); when(mInterfaceConflictManager.manageInterfaceConflictForStateMachine(any(), any(), any(), any(), any(), anyInt(), any(), anyBoolean())) .thenReturn(InterfaceConflictManager.ICM_ABORT_COMMAND); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_USER_REJECTED); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_USER_REJECTED, TEST_TETHERING_REQUEST, null))); verify(mListener).onStartFailure(mSoftApManager); verify(mWifiMetrics).writeSoftApStartedEvent( eq(SoftApManager.START_RESULT_FAILURE_INTERFACE_CONFLICT_USER_REJECTED), @@ -527,7 +546,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mInterfaceConflictManager).manageInterfaceConflictForStateMachine(any(), any(), any(), any(), any(), anyInt(), any(), eq(true)); @@ -545,7 +564,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setHiddenSsid(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); } @@ -562,7 +581,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); } @@ -572,10 +591,10 @@ public class SoftApManagerTest extends WifiBaseTest { when(mWifiApConfigStore.getApConfiguration()).thenReturn(null); SoftApModeConfiguration nullApConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(nullApConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_GENERAL, TEST_TETHERING_REQUEST, null))); verify(mListener).onStartFailure(mSoftApManager); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); if (SdkLevel.isAtLeastSv2()) { @@ -608,10 +627,10 @@ public class SoftApManagerTest extends WifiBaseTest { when(mWifiApConfigStore.getApConfiguration()).thenReturn(null); SoftApModeConfiguration nullApConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(nullApConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_GENERAL, TEST_TETHERING_REQUEST, null))); verify(mListener).onStartFailure(mSoftApManager); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); if (SdkLevel.isAtLeastSv2()) { @@ -641,16 +660,19 @@ public class SoftApManagerTest extends WifiBaseTest { @Test public void testStartSoftApNotPossibleToCreateApInterfaceIncrementsMetrics() throws Exception { + when(mWifiNative.setupInterfaceForSoftApMode( + any(), any(), anyInt(), anyBoolean(), any(), anyList())).thenReturn(null); when(mWifiNative.isItPossibleToCreateApIface(any())).thenReturn(false); Builder configBuilder = new SoftApConfiguration.Builder(); configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( IFACE_IP_MODE_LOCAL_ONLY, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mWifiNative).isItPossibleToCreateApIface(any()); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_GENERAL, TEST_TETHERING_REQUEST, null))); verify(mListener).onStartFailure(mSoftApManager); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); if (SdkLevel.isAtLeastSv2()) { @@ -684,10 +706,12 @@ public class SoftApManagerTest extends WifiBaseTest { any(), any(), anyInt(), anyBoolean(), any(), anyList())).thenReturn(""); SoftApModeConfiguration nullApConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(nullApConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, ""))); + verify(mWifiNative).isItPossibleToCreateApIface(any()); verify(mListener).onStartFailure(mSoftApManager); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); if (SdkLevel.isAtLeastSv2()) { @@ -721,7 +745,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, null); + mTestSoftApCapability, null, null); mSoftApManager = createSoftApManager(softApConfig, ROLE_SOFTAP_TETHERED); @@ -760,7 +784,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setPassphrase("somepassword", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, null); + mTestSoftApCapability, null, null); mSoftApManager = createSoftApManager(softApConfig, ROLE_SOFTAP_TETHERED); @@ -795,7 +819,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); when(mWifiNative.setApCountryCode( TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT))) @@ -836,7 +860,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setPassphrase("somepassword", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); when(mWifiNative.setApCountryCode( TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT))) @@ -876,7 +900,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, null); + mTestSoftApCapability, null, null); startSoftApAndVerifyEnabled(softApConfig); verify(mWifiNative, never()).setApCountryCode(eq(TEST_INTERFACE_NAME), any()); @@ -894,7 +918,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setPassphrase("somepassword", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, null); + mTestSoftApCapability, null, null); startSoftApAndVerifyEnabled(softApConfig); verify(mWifiNative, never()).setApCountryCode(eq(TEST_INTERFACE_NAME), any()); @@ -911,7 +935,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); when(mWifiNative.setApCountryCode(eq(TEST_INTERFACE_NAME), any())).thenReturn(false); @@ -932,7 +956,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setPassphrase("somepassword", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); when(mWifiNative.setApCountryCode(eq(TEST_INTERFACE_NAME), any())).thenReturn(false); @@ -954,7 +978,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setSsid(TEST_SSID); SoftApModeConfiguration softApConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - noAcsCapability, TEST_COUNTRY_CODE); + noAcsCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ)) .thenReturn(EMPTY_CHANNEL_ARRAY); @@ -977,7 +1001,8 @@ public class SoftApManagerTest extends WifiBaseTest { softApConfig.getTargetMode()); checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED, WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_NO_CHANNEL, - TEST_INTERFACE_NAME, softApConfig.getTargetMode()); + TEST_INTERFACE_NAME, softApConfig.getTargetMode() + ); } /** @@ -991,13 +1016,14 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration softApModeConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, mDefaultApConfig, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager( softApModeConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); verify(mListener).onStartFailure(mSoftApManager); verify(mWifiNative).teardownInterface(TEST_INTERFACE_NAME); verify(mWifiMetrics).writeSoftApStartedEvent( @@ -1013,7 +1039,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void stopWhenStarted() throws Exception { SoftApModeConfiguration softApModeConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(softApModeConfig); // reset to clear verified Intents for ap state change updates @@ -1025,7 +1051,9 @@ public class SoftApManagerTest extends WifiBaseTest { mLooper.dispatchAll(); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); + order.verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_DISABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); if (SdkLevel.isAtLeastSv2()) { order.verify(mContext).sendBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL), eq(android.Manifest.permission.ACCESS_WIFI_STATE)); @@ -1037,7 +1065,9 @@ public class SoftApManagerTest extends WifiBaseTest { WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, softApModeConfig.getTargetMode()); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); + order.verify(mCallback).onStateChanged(eq(new SoftApState( + WIFI_AP_STATE_DISABLED, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); verify(mSarManager).setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED); verify(mWifiDiagnostics).stopLogging(TEST_INTERFACE_NAME); if (SdkLevel.isAtLeastSv2()) { @@ -1061,7 +1091,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void cleanStopOnInterfaceDestroyed() throws Exception { SoftApModeConfiguration softApModeConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(softApModeConfig); // reset to clear verified Intents for ap state change updates @@ -1074,7 +1104,9 @@ public class SoftApManagerTest extends WifiBaseTest { mLooper.dispatchAll(); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); + order.verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_DISABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); if (SdkLevel.isAtLeastSv2()) { order.verify(mContext).sendBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL), eq(android.Manifest.permission.ACCESS_WIFI_STATE)); @@ -1086,7 +1118,9 @@ public class SoftApManagerTest extends WifiBaseTest { WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, softApModeConfig.getTargetMode()); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); + order.verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_DISABLED, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); if (SdkLevel.isAtLeastSv2()) { order.verify(mContext).sendBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL), eq(android.Manifest.permission.ACCESS_WIFI_STATE)); @@ -1107,15 +1141,17 @@ public class SoftApManagerTest extends WifiBaseTest { public void noCallbackOnInterfaceDestroyedWhenAlreadyStopped() throws Exception { SoftApModeConfiguration softApModeConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(softApModeConfig); verify(mListener, never()).onStopped(mSoftApManager); mSoftApManager.stop(); mLooper.dispatchAll(); verify(mListener).onStopped(mSoftApManager); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_DISABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_DISABLED, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); reset(mCallback); @@ -1133,7 +1169,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testInterfaceOnDownHandled() throws Exception { SoftApModeConfiguration softApModeConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(softApModeConfig); // reset to clear verified Intents for ap state change updates @@ -1146,8 +1182,9 @@ public class SoftApManagerTest extends WifiBaseTest { mLooper.dispatchAll(); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + order.verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); order.verify(mListener).onStopped(mSoftApManager); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); if (SdkLevel.isAtLeastSv2()) { @@ -1180,7 +1217,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testInterfaceOnDownForDifferentInterfaceDoesNotTriggerStop() throws Exception { SoftApModeConfiguration softApModeConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(softApModeConfig); // reset to clear verified Intents for ap state change updates @@ -1200,7 +1237,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testHostapdOnFailureHandled() throws Exception { SoftApModeConfiguration softApModeConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(softApModeConfig); // reset to clear verified Intents for ap state change updates @@ -1211,8 +1248,9 @@ public class SoftApManagerTest extends WifiBaseTest { mSoftApHalCallbackCaptor.getValue().onFailure(); mLooper.dispatchAll(); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + order.verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); order.verify(mListener).onStopped(mSoftApManager); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); if (SdkLevel.isAtLeastSv2()) { @@ -1246,7 +1284,7 @@ public class SoftApManagerTest extends WifiBaseTest { assumeTrue(SdkLevel.isAtLeastS()); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); // SoftApInfo updated @@ -1283,7 +1321,7 @@ public class SoftApManagerTest extends WifiBaseTest { assumeTrue(SdkLevel.isAtLeastS()); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); // SoftApInfo updated mockSoftApInfoUpdateAndVerifyAfterSapStarted(true /* bridged mode*/, true); @@ -1327,7 +1365,7 @@ public class SoftApManagerTest extends WifiBaseTest { assumeTrue(SdkLevel.isAtLeastS()); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); // SoftApInfo updated mockSoftApInfoUpdateAndVerifyAfterSapStarted(true /* bridged mode*/, true); @@ -1365,7 +1403,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void updatesMetricsOnChannelSwitchedEvent() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1383,7 +1421,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); SoftApInfo testSoftApInfo = new SoftApInfo(mTestSoftApInfo); testSoftApInfo.setFrequency(5220); @@ -1407,7 +1445,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1428,7 +1466,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1447,7 +1485,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testOnSoftApChannelSwitchedEventTriggerSoftApInfoUpdate() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1465,7 +1503,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testDoesNotTriggerCallbackForSameChannelInfoUpdate() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1489,7 +1527,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testHandlesInvalidChannelFrequency() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); mockChannelSwitchEvent(-1, TEST_AP_BANDWIDTH_FROM_IFACE_CALLBACK); @@ -1508,7 +1546,7 @@ public class SoftApManagerTest extends WifiBaseTest { InOrder order = inOrder(mCallback, mWifiMetrics); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); order.verify(mWifiMetrics).addSoftApChannelSwitchedEvent( @@ -1530,7 +1568,7 @@ public class SoftApManagerTest extends WifiBaseTest { InOrder order = inOrder(mCallback, mWifiMetrics); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); reset(mCallback); @@ -1552,7 +1590,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testDoesNotTriggerCallbackForSameClients() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1589,7 +1627,7 @@ public class SoftApManagerTest extends WifiBaseTest { InOrder order = inOrder(mCallback, mWifiMetrics); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -1610,7 +1648,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void handlesInvalidConnectedClients() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); reset(mCallback); @@ -1628,7 +1666,7 @@ public class SoftApManagerTest extends WifiBaseTest { InOrder order = inOrder(mCallback, mWifiMetrics); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1671,7 +1709,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setBlockedClientList(blockedClientList); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); reset(mCallback); @@ -1700,7 +1739,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setClientControlByUserEnabled(false); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -1742,7 +1782,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setClientControlByUserEnabled(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); reset(mCallback); @@ -1771,7 +1812,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setClientControlByUserEnabled(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); reset(mWifiMetrics); @@ -1821,7 +1863,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setClientControlByUserEnabled(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); reset(mWifiMetrics); @@ -1877,7 +1920,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setAllowedClientList(allowedClientList); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -1924,7 +1968,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void schedulesTimeoutTimerOnStart() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mResources) .getInteger(R.integer.config_wifiFrameworkSoftApShutDownTimeoutMilliseconds); @@ -1951,7 +1995,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setShutdownTimeoutMillis(50000); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); @@ -1972,7 +2017,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void cancelsTimeoutTimerOnStop() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -1990,7 +2035,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void cancelsTimeoutTimerOnNewClientsConnect() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -2008,7 +2053,7 @@ public class SoftApManagerTest extends WifiBaseTest { InOrder order = inOrder(mCallback, mWifiMetrics); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -2031,7 +2076,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void stopsSoftApOnTimeoutMessage() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -2053,7 +2098,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void cancelsTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -2077,7 +2122,7 @@ public class SoftApManagerTest extends WifiBaseTest { .build(); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); @@ -2114,7 +2159,7 @@ public class SoftApManagerTest extends WifiBaseTest { .build(); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); SoftApInfo expectedInfo = new SoftApInfo(mTestSoftApInfo); @@ -2137,7 +2182,7 @@ public class SoftApManagerTest extends WifiBaseTest { .build(); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); @@ -2169,7 +2214,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); ArgumentCaptor<MacAddress> mac = ArgumentCaptor.forClass(MacAddress.class); startSoftApAndVerifyEnabled(apConfig); @@ -2182,6 +2227,8 @@ public class SoftApManagerTest extends WifiBaseTest { | SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD | SoftApCapability.SOFTAP_FEATURE_WPA3_SAE; + when(mDeviceWiphyCapabilities.isWifiStandardSupported( + ScanResult.WIFI_STANDARD_11BE)).thenReturn(false); SoftApCapability testSoftApCapability = new SoftApCapability(testSoftApFeature); testSoftApCapability.setCountryCode(TEST_COUNTRY_CODE); Builder configBuilder = new SoftApConfiguration.Builder(); @@ -2194,7 +2241,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), testSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); ArgumentCaptor<MacAddress> mac = ArgumentCaptor.forClass(MacAddress.class); startSoftApAndVerifyEnabled(apConfig); @@ -2213,7 +2260,7 @@ public class SoftApManagerTest extends WifiBaseTest { } SoftApModeConfiguration apConfig = new SoftApModeConfiguration( IFACE_IP_MODE_LOCAL_ONLY, configBuilder.build(), mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); ArgumentCaptor<MacAddress> mac = ArgumentCaptor.forClass(MacAddress.class); when(mWifiNative.setApMacAddress(eq(TEST_INTERFACE_NAME), mac.capture())).thenReturn(true); @@ -2234,14 +2281,16 @@ public class SoftApManagerTest extends WifiBaseTest { } SoftApModeConfiguration apConfig = new SoftApModeConfiguration( IFACE_IP_MODE_LOCAL_ONLY, configBuilder.build(), mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); ArgumentCaptor<MacAddress> mac = ArgumentCaptor.forClass(MacAddress.class); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_LOCAL_ONLY); mLooper.dispatchAll(); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_ENABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); verify(mWifiNative, never()).setApMacAddress(any(), any()); } @@ -2256,15 +2305,17 @@ public class SoftApManagerTest extends WifiBaseTest { } SoftApModeConfiguration apConfig = new SoftApModeConfiguration( IFACE_IP_MODE_LOCAL_ONLY, configBuilder.build(), mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); ArgumentCaptor<MacAddress> mac = ArgumentCaptor.forClass(MacAddress.class); when(mWifiNative.setApMacAddress(eq(TEST_INTERFACE_NAME), mac.capture())).thenReturn(false); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_LOCAL_ONLY); mLooper.dispatchAll(); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_ENABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); assertThat(mac.getValue()).isEqualTo(TEST_CLIENT_MAC_ADDRESS); } @@ -2281,21 +2332,25 @@ public class SoftApManagerTest extends WifiBaseTest { when(mWifiApConfigStore.randomizeBssidIfUnset(any(), any())).thenReturn( randomizedBssidConfig); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( - IFACE_IP_MODE_LOCAL_ONLY, null, mTestSoftApCapability, TEST_COUNTRY_CODE); + IFACE_IP_MODE_LOCAL_ONLY, null, mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); ArgumentCaptor<MacAddress> mac = ArgumentCaptor.forClass(MacAddress.class); when(mWifiNative.setApMacAddress(eq(TEST_INTERFACE_NAME), mac.capture())).thenReturn(false); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_LOCAL_ONLY); mLooper.dispatchAll(); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_ENABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); } @Test public void setRandomMacWhenSetMacNotsupport() throws Exception { when(mWifiNative.isApSetMacAddressSupported(any())).thenReturn(false); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( - IFACE_IP_MODE_LOCAL_ONLY, null, mTestSoftApCapability, TEST_COUNTRY_CODE); + IFACE_IP_MODE_LOCAL_ONLY, null, mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mWifiNative, never()).setApMacAddress(any(), any()); } @@ -2305,7 +2360,7 @@ public class SoftApManagerTest extends WifiBaseTest { mTestSoftApCapability.setMaxSupportedClients(1); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -2340,7 +2395,7 @@ public class SoftApManagerTest extends WifiBaseTest { mTestSoftApCapability.setMaxSupportedClients(2); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); verify(mCallback).onConnectedClientsOrInfoChanged(mTestSoftApInfoMap, @@ -2463,7 +2518,6 @@ public class SoftApManagerTest extends WifiBaseTest { mWifiNativeInterfaceCallbackCaptor.capture(), eq(TEST_WORKSOURCE), eq(expectedConfig.getBand()), eq(expectedConfig.getBands().length > 1), eq(mSoftApManager), anyList()); - // Simulate user approval ArgumentCaptor<StateMachine> stateMachineCaptor = ArgumentCaptor.forClass(StateMachine.class); @@ -2477,6 +2531,9 @@ public class SoftApManagerTest extends WifiBaseTest { stateMachineCaptor.getValue().sendMessage(Message.obtain(messageCaptor.getValue())); mLooper.dispatchAll(); } + // isItPossibleToCreateApIface should never happen in normal case since it may fail in + // normal use case + verify(mWifiNative, never()).isItPossibleToCreateApIface(any()); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mFakeSoftApNotifier).dismissSoftApShutdownTimeoutExpiredNotification(); order.verify(mWifiNative).setupInterfaceForSoftApMode( @@ -2485,7 +2542,9 @@ public class SoftApManagerTest extends WifiBaseTest { eq(mSoftApManager), anyList()); ArgumentCaptor<SoftApConfiguration> configCaptor = ArgumentCaptor.forClass(SoftApConfiguration.class); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); + order.verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_ENABLING, 0, + softApConfig.getTetheringRequest(), TEST_INTERFACE_NAME))); if (!TextUtils.isEmpty(softApConfig.getCountryCode()) && !TextUtils.equals( softApConfig.getCountryCode(), @@ -2519,7 +2578,9 @@ public class SoftApManagerTest extends WifiBaseTest { ? expectedConfigWithFrameworkACS : expectedConfig); mWifiNativeInterfaceCallbackCaptor.getValue().onUp(TEST_INTERFACE_NAME); mLooper.dispatchAll(); - order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); + order.verify(mCallback).onStateChanged(eq(new SoftApState( + WifiManager.WIFI_AP_STATE_ENABLED, 0, + softApConfig.getTetheringRequest(), TEST_INTERFACE_NAME))); order.verify(mCallback).onConnectedClientsOrInfoChanged(eq(mTestSoftApInfoMap), eq(mTestWifiClientsMap), eq(expectedConfig.getBands().length > 1)); verify(mSarManager).setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED); @@ -2590,12 +2651,14 @@ public class SoftApManagerTest extends WifiBaseTest { | SoftApCapability.SOFTAP_FEATURE_WPA3_SAE | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD | SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION; + when(mDeviceWiphyCapabilities.isWifiStandardSupported( + ScanResult.WIFI_STANDARD_11BE)).thenReturn(false); SoftApCapability noClientControlCapability = new SoftApCapability(testSoftApFeature); noClientControlCapability.setMaxSupportedClients(1); noClientControlCapability.setCountryCode(TEST_COUNTRY_CODE); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - noClientControlCapability, TEST_COUNTRY_CODE); + noClientControlCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -2633,12 +2696,14 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, - noClientControlCapability, TEST_COUNTRY_CODE); + noClientControlCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_ENABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); verify(mWifiMetrics).incrementSoftApStartResult(false, WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION); verify(mListener).onStartFailure(mSoftApManager); @@ -2661,12 +2726,14 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, - noSaeCapability, TEST_COUNTRY_CODE); + noSaeCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_ENABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); verify(mListener).onStartFailure(mSoftApManager); verify(mWifiMetrics).writeSoftApStartedEvent( eq(SoftApManager.START_RESULT_FAILURE_UNSUPPORTED_CONFIG), @@ -2683,6 +2750,8 @@ public class SoftApManagerTest extends WifiBaseTest { | SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT | SoftApCapability.SOFTAP_FEATURE_WPA3_SAE | SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION; + when(mDeviceWiphyCapabilities.isWifiStandardSupported( + ScanResult.WIFI_STANDARD_11BE)).thenReturn(false); SoftApCapability testCapability = new SoftApCapability(testSoftApFeature); testCapability.setSupportedChannelList( SoftApConfiguration.BAND_2GHZ, TEST_SUPPORTED_24G_CHANNELS); @@ -2692,13 +2761,15 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration softApConfig = generateBridgedModeSoftApConfig(null); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, - testCapability, TEST_COUNTRY_CODE); + testCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_TETHERED); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); - verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_ENABLING, 0, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); + verify(mCallback).onStateChanged(eq(new SoftApState(WifiManager.WIFI_AP_STATE_FAILED, + WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION, + TEST_TETHERING_REQUEST, TEST_INTERFACE_NAME))); verify(mWifiMetrics).incrementSoftApStartResult(false, WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION); verify(mListener).onStartFailure(mSoftApManager); @@ -2717,6 +2788,8 @@ public class SoftApManagerTest extends WifiBaseTest { | SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT | SoftApCapability.SOFTAP_FEATURE_WPA3_SAE | SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION; + when(mDeviceWiphyCapabilities.isWifiStandardSupported( + ScanResult.WIFI_STANDARD_11BE)).thenReturn(false); SparseIntArray dual_channels = new SparseIntArray(2); dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149); dual_channels.put(SoftApConfiguration.BAND_2GHZ, 2); @@ -2730,7 +2803,7 @@ public class SoftApManagerTest extends WifiBaseTest { .build(); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, - testCapability, TEST_COUNTRY_CODE); + testCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, null, false); } @@ -2743,7 +2816,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mCallback).onConnectedClientsOrInfoChanged(mTestSoftApInfoMap, @@ -2783,7 +2856,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); @@ -2806,7 +2879,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setMaxNumberOfClients(2); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -2847,7 +2921,8 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setMaxNumberOfClients(1); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE); + configBuilder.build(), mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -2917,7 +2992,8 @@ public class SoftApManagerTest extends WifiBaseTest { InOrder order = inOrder(mCallback, mWifiMetrics); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, - customizedBssidConfig, mTestSoftApCapability, TEST_COUNTRY_CODE); + customizedBssidConfig, mTestSoftApCapability, TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); order.verify(mWifiMetrics).addSoftApChannelSwitchedEvent( @@ -2943,7 +3019,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testHandleCallbackFromWificond() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); mockChannelSwitchEvent(mTestSoftApInfo.getFrequency(), mTestSoftApInfo.getBandwidth()); @@ -2970,7 +3046,7 @@ public class SoftApManagerTest extends WifiBaseTest { mTestSoftApCapability.setMaxSupportedClients(1); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); mockClientConnectedEvent(TEST_CLIENT_MAC_ADDRESS, true, TEST_INTERFACE_NAME, true); @@ -3017,7 +3093,7 @@ public class SoftApManagerTest extends WifiBaseTest { mTestSoftApCapability.setMaxSupportedClients(1); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); mockSoftApInfoUpdateAndVerifyAfterSapStarted(false, true); reset(mCallback); @@ -3060,7 +3136,7 @@ public class SoftApManagerTest extends WifiBaseTest { assumeTrue(SdkLevel.isAtLeastS()); SoftApModeConfiguration dualBandConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(dualBandConfig, ROLE_SOFTAP_TETHERED); verify(mWifiNative).setupInterfaceForSoftApMode( any(), any(), eq(SoftApConfiguration.BAND_2GHZ), eq(true), eq(mSoftApManager), @@ -3071,7 +3147,7 @@ public class SoftApManagerTest extends WifiBaseTest { public void testOnInfoChangedFromDifferentInstancesTriggerSoftApInfoUpdate() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mCallback); mockApInfoChangedEvent(mTestSoftApInfoOnFirstInstance); @@ -3090,7 +3166,7 @@ public class SoftApManagerTest extends WifiBaseTest { assumeTrue(SdkLevel.isAtLeastS()); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mResources) @@ -3126,7 +3202,7 @@ public class SoftApManagerTest extends WifiBaseTest { assumeTrue(SdkLevel.isAtLeastS()); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mResources) @@ -3237,7 +3313,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mResources) @@ -3271,7 +3347,7 @@ public class SoftApManagerTest extends WifiBaseTest { configBuilder.setBridgedModeOpportunisticShutdownEnabled(false); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mResources) @@ -3324,7 +3400,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - testCapability, TEST_COUNTRY_CODE); + testCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 6G to generate expected configuration configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_6GHZ); startSoftApAndVerifyEnabled(apConfig, configBuilder.build(), false); @@ -3344,7 +3420,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - testCapability, TEST_COUNTRY_CODE); + testCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band array to {2.4G, 5G} to generate expected configuration int[] expected_dual_bands = {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ}; @@ -3363,7 +3439,7 @@ public class SoftApManagerTest extends WifiBaseTest { generateBridgedModeSoftApConfig(null)); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - testCapability, TEST_COUNTRY_CODE); + testCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 5G to generate expected configuration configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); startSoftApAndVerifyEnabled(apConfig, configBuilder.build(), false); @@ -3387,7 +3463,7 @@ public class SoftApManagerTest extends WifiBaseTest { generateBridgedModeSoftApConfig(null)); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - testCapability, TEST_COUNTRY_CODE); + testCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 5G to generate expected configuration configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); startSoftApAndVerifyEnabled(apConfig, configBuilder.build(), false); @@ -3402,7 +3478,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration bridgedConfig = generateBridgedModeSoftApConfig(null); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); } @@ -3421,7 +3497,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); } @@ -3440,7 +3516,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G to generate expected configuration configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); startSoftApAndVerifyEnabled(apConfig, configBuilder.build(), false); @@ -3459,7 +3535,7 @@ public class SoftApManagerTest extends WifiBaseTest { generateBridgedModeSoftApConfig(null)); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - testCapability, worldModeCC); + testCapability, worldModeCC, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 5G to generate expected configuration configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); startSoftApAndVerifyEnabled(apConfig, configBuilder.build(), false); @@ -3474,7 +3550,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration bridgedConfig = generateBridgedModeSoftApConfig(null); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); reset(mCallback); @@ -3506,7 +3582,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration bridgedConfig = generateBridgedModeSoftApConfig(null); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); reset(mCallback); @@ -3550,7 +3626,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration bridgedConfig = generateBridgedModeSoftApConfig(null); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); reset(mCallback); @@ -3576,7 +3652,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration bridgedConfig = generateBridgedModeSoftApConfig(null); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); reset(mCallback); @@ -3600,7 +3676,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApConfiguration bridgedConfig = generateBridgedModeSoftApConfig(null); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, mTestSoftApCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); reset(mCallback); @@ -3609,6 +3685,9 @@ public class SoftApManagerTest extends WifiBaseTest { // TEST_SUPPORTED_5G_CHANNELS = 36, 149, mark to unsafe. Let Wifi connect to 5945 (6G) when(mPrimaryWifiInfo.getFrequency()).thenReturn(5945); + // Device doesn't support three band combination. + when(mWifiNative.isBandCombinationSupported(eq(TEST_STA_INTERFACE_NAME), any())) + .thenReturn(false); reset(mCallback); // Trigger wifi connected @@ -3631,11 +3710,40 @@ public class SoftApManagerTest extends WifiBaseTest { } @Test + public void testBridgedModeNotShutDownForWifiUnavailableChannelWhenBandCombinationSupported() + throws Exception { + assumeTrue(SdkLevel.isAtLeastS()); + SoftApConfiguration bridgedConfig = generateBridgedModeSoftApConfig(null); + SoftApModeConfiguration apConfig = new SoftApModeConfiguration( + WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, mTestSoftApCapability, + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); + startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); + + reset(mCallback); + // SoftApInfo updated + mockSoftApInfoUpdateAndVerifyAfterSapStarted(true /* bridged mode*/, true); + + // TEST_SUPPORTED_5G_CHANNELS = 36, 149, mark to unsafe. Let Wifi connect to 5945 (6G) + when(mPrimaryWifiInfo.getFrequency()).thenReturn(5945); + // Device supports three band combination + when(mWifiNative.isBandCombinationSupported(eq(TEST_STA_INTERFACE_NAME), any())) + .thenReturn(true); + + reset(mCallback); + // Trigger wifi connected + mCmiListenerCaptor.getValue().onL2Connected(mConcreteClientModeManager); + mLooper.dispatchAll(); + // Verify instance not removed + verify(mWifiNative, never()).removeIfaceInstanceFromBridgedApIface(eq(TEST_INTERFACE_NAME), + eq(TEST_SECOND_INSTANCE_NAME)); + } + + @Test public void testBridgedModeDowngradeIfaceInstanceForRemoval() throws Exception { assumeTrue(SdkLevel.isAtLeastS()); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); // SoftApInfo updated @@ -3673,7 +3781,8 @@ public class SoftApManagerTest extends WifiBaseTest { WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), staleCapability, - TEST_COUNTRY_CODE); + TEST_COUNTRY_CODE, + TEST_TETHERING_REQUEST); // Started bands should include both 2.4GHz and 5GHz since we get the updated capabilities // after waiting for the driver CC event. startSoftApAndVerifyEnabled(apConfig, configBuilder.build(), false); @@ -3685,7 +3794,7 @@ public class SoftApManagerTest extends WifiBaseTest { R.bool.config_wifiDriverSupportedNl80211RegChangedEvent)).thenReturn(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, "Not " + TEST_COUNTRY_CODE); + mTestSoftApCapability, "Not " + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); } @@ -3695,7 +3804,7 @@ public class SoftApManagerTest extends WifiBaseTest { R.bool.config_wifiDriverSupportedNl80211RegChangedEvent)).thenReturn(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, "Not" + TEST_COUNTRY_CODE); + mTestSoftApCapability, "Not" + TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); mSoftApManager = createSoftApManager(apConfig, ROLE_SOFTAP_TETHERED); ArgumentCaptor<WifiCountryCode.ChangeListener> changeListenerCaptor = ArgumentCaptor.forClass(WifiCountryCode.ChangeListener.class); @@ -3716,7 +3825,7 @@ public class SoftApManagerTest extends WifiBaseTest { .thenReturn(false); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mWifiNative); mSoftApManager.updateCountryCode(TEST_COUNTRY_CODE + "TW"); @@ -3730,7 +3839,7 @@ public class SoftApManagerTest extends WifiBaseTest { .thenReturn(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mWifiNative); mSoftApManager.updateCountryCode(TEST_COUNTRY_CODE + "TW"); @@ -3744,7 +3853,7 @@ public class SoftApManagerTest extends WifiBaseTest { .thenReturn(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); reset(mWifiNative); mSoftApManager.updateCountryCode(TEST_COUNTRY_CODE); @@ -3763,7 +3872,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 5G to generate expected configuration since it should fallback to // single AP mode configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); @@ -3782,7 +3891,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 5G to generate expected configuration since it should fallback to // single AP mode configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); @@ -3798,7 +3907,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 5G to generate expected configuration since it should fallback to // single AP mode configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); @@ -3816,7 +3925,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); // Reset band to 2.4G | 5G to generate expected configuration since it should fallback to // single AP mode configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); @@ -3836,7 +3945,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig, - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, bridgedConfig, false); } @@ -3849,7 +3958,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, generateBridgedModeSoftApConfig(null), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig); verify(mResources) @@ -3912,7 +4021,7 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - testCapability, TEST_COUNTRY_CODE); + testCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); startSoftApAndVerifyEnabled(apConfig, configBuilder.build(), false); } @@ -3923,17 +4032,16 @@ public class SoftApManagerTest extends WifiBaseTest { @Test public void testStartSoftApRemoves11BEIfNotSupported() throws Exception { assumeTrue(SdkLevel.isAtLeastT()); - mTestSoftApCapability.setSupportedFeatures(false, - SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE); + when(mDeviceWiphyCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE)) + .thenReturn(false); Builder configBuilder = new SoftApConfiguration.Builder(); configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); configBuilder.setSsid(TEST_SSID); configBuilder.setIeee80211beEnabled(true); SoftApModeConfiguration apConfig = new SoftApModeConfiguration( WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), - mTestSoftApCapability, TEST_COUNTRY_CODE); + mTestSoftApCapability, TEST_COUNTRY_CODE, TEST_TETHERING_REQUEST); SoftApConfiguration expectedConfig = configBuilder.setIeee80211beEnabled(false).build(); startSoftApAndVerifyEnabled(apConfig, expectedConfig, false); } } - diff --git a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java index e3f0695609..65bee6e0be 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java @@ -35,6 +35,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; @@ -77,10 +78,13 @@ import android.hardware.wifi.supplicant.KeyMgmtMask; import android.hardware.wifi.supplicant.LegacyMode; import android.hardware.wifi.supplicant.MloLink; import android.hardware.wifi.supplicant.MloLinksInfo; +import android.hardware.wifi.supplicant.MscsParams.FrameClassifierFields; +import android.hardware.wifi.supplicant.MsduDeliveryInfo; import android.hardware.wifi.supplicant.OceRssiBasedAssocRejectAttr; import android.hardware.wifi.supplicant.OsuMethod; import android.hardware.wifi.supplicant.PmkSaCacheData; import android.hardware.wifi.supplicant.PortRange; +import android.hardware.wifi.supplicant.QosCharacteristics.QosCharacteristicsMask; import android.hardware.wifi.supplicant.QosPolicyClassifierParams; import android.hardware.wifi.supplicant.QosPolicyClassifierParamsMask; import android.hardware.wifi.supplicant.QosPolicyData; @@ -101,6 +105,8 @@ import android.hardware.wifi.supplicant.WpsErrorIndication; import android.net.DscpPolicy; import android.net.MacAddress; import android.net.NetworkAgent; +import android.net.wifi.MscsParams; +import android.net.wifi.QosCharacteristics; import android.net.wifi.QosPolicyParams; import android.net.wifi.ScanResult; import android.net.wifi.SecurityParams; @@ -120,6 +126,7 @@ import androidx.test.filters.SmallTest; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.MboOceController.BtmFrameData; +import com.android.server.wifi.hal.HalTestUtils; import com.android.server.wifi.hotspot2.AnqpEvent; import com.android.server.wifi.hotspot2.IconEvent; import com.android.server.wifi.hotspot2.WnmData; @@ -1262,6 +1269,74 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { } /** + * Tests that association rejection due to timeout doesn't broadcast authentication failure + * with reason code ERROR_AUTH_FAILURE_WRONG_PSWD. + * Driver/Supplicant sets the timedOut field when there is no ACK or response frame for + * Authentication request or Association request frame. + */ + @Test + public void testAssociationRejectionDueToTimedOutDoesntNotifyWrongPassword() throws Exception { + executeAndValidateInitializationSequence(); + assertNotNull(mISupplicantStaIfaceCallback); + + executeAndValidateConnectSequenceWithKeyMgmt( + SUPPLICANT_NETWORK_ID, false, TRANSLATED_SUPPLICANT_SSID.toString(), + WifiConfiguration.SECURITY_TYPE_SAE, null, true); + mISupplicantStaIfaceCallback.onStateChanged( + StaIfaceCallbackState.ASSOCIATING, + NativeUtil.macAddressToByteArray(BSSID), + SUPPLICANT_NETWORK_ID, + NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(SUPPLICANT_SSID)), false); + AssociationRejectionData rejectionData = createAssocRejectData(SUPPLICANT_SSID, BSSID, + StaIfaceStatusCode.UNSPECIFIED_FAILURE, true); + mISupplicantStaIfaceCallback.onAssociationRejected(rejectionData); + verify(mWifiMonitor, never()).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME), + anyInt(), anyInt(), any(), any()); + ArgumentCaptor<AssocRejectEventInfo> assocRejectEventInfoCaptor = + ArgumentCaptor.forClass(AssocRejectEventInfo.class); + verify(mWifiMonitor).broadcastAssociationRejectionEvent( + eq(WLAN0_IFACE_NAME), assocRejectEventInfoCaptor.capture()); + AssocRejectEventInfo assocRejectEventInfo = assocRejectEventInfoCaptor.getValue(); + assertNotNull(assocRejectEventInfo); + assertTrue(assocRejectEventInfo.timedOut); + } + + /** + * Tests the handling of authentication failure for WPA3-Personal networks with + * status code = 15 (CHALLENGE_FAIL) + */ + @Test + public void testWpa3AuthRejectionDueToChallengeFail() throws Exception { + executeAndValidateInitializationSequence(); + assertNotNull(mISupplicantStaIfaceCallback); + + executeAndValidateConnectSequenceWithKeyMgmt( + SUPPLICANT_NETWORK_ID, false, TRANSLATED_SUPPLICANT_SSID.toString(), + WifiConfiguration.SECURITY_TYPE_SAE, null, true); + mISupplicantStaIfaceCallback.onStateChanged( + StaIfaceCallbackState.ASSOCIATING, + NativeUtil.macAddressToByteArray(BSSID), + SUPPLICANT_NETWORK_ID, + NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(SUPPLICANT_SSID)), false); + int statusCode = StaIfaceStatusCode.CHALLENGE_FAIL; + AssociationRejectionData rejectionData = createAssocRejectData(SUPPLICANT_SSID, BSSID, + statusCode, false); + mISupplicantStaIfaceCallback.onAssociationRejected(rejectionData); + verify(mWifiMonitor).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME), + eq(WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD), eq(-1), + eq(TRANSLATED_SUPPLICANT_SSID.toString()), + eq(MacAddress.fromString(BSSID))); + ArgumentCaptor<AssocRejectEventInfo> assocRejectEventInfoCaptor = + ArgumentCaptor.forClass(AssocRejectEventInfo.class); + verify(mWifiMonitor).broadcastAssociationRejectionEvent( + eq(WLAN0_IFACE_NAME), assocRejectEventInfoCaptor.capture()); + AssocRejectEventInfo assocRejectEventInfo = assocRejectEventInfoCaptor.getValue(); + assertNotNull(assocRejectEventInfo); + assertEquals(SupplicantStaIfaceCallbackAidlImpl.halToFrameworkStatusCode( + statusCode), assocRejectEventInfo.statusCode); + } + + /** * Tests the handling of incorrect network passwords for WEP networks. */ @Test @@ -1349,6 +1424,30 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { } /** + * Tests the handling of incorrect network password for AP_BUSY error code + * + * If the disconnect reason is "NO_MORE_STAS - Disassociated because AP is unable + * to handle all currently associated STAs", do not call it a password mismatch. + */ + @Test + public void testApBusy() throws Exception { + executeAndValidateInitializationSequence(); + assertNotNull(mISupplicantStaIfaceCallback); + + int reasonCode = StaIfaceReasonCode.DISASSOC_AP_BUSY; + + mISupplicantStaIfaceCallback.onStateChanged( + StaIfaceCallbackState.FOURWAY_HANDSHAKE, + NativeUtil.macAddressToByteArray(BSSID), + SUPPLICANT_NETWORK_ID, + NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(SUPPLICANT_SSID)), false); + mISupplicantStaIfaceCallback.onDisconnected( + NativeUtil.macAddressToByteArray(BSSID), true, reasonCode); + verify(mWifiMonitor, never()).broadcastAuthenticationFailureEvent(any(), anyInt(), + anyInt(), any(), any()); + } + + /** * Tests the handling of eap failure during disconnect. */ @Test @@ -2006,6 +2105,9 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { halCap.channelBandwidth = WifiChannelWidthInMhz.WIDTH_20; halCap.maxNumberTxSpatialStreams = 1; halCap.maxNumberRxSpatialStreams = 1; + if (SdkLevel.isAtLeastV()) { + halCap.vendorData = HalTestUtils.createHalOuiKeyedDataList(5); + } doReturn(halCap).when(mISupplicantStaIfaceMock).getConnectionCapabilities(); WifiNative.ConnectionCapabilities expectedCap = @@ -2015,6 +2117,12 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { assertEquals(testChannelBandwidth, expectedCap.channelBandwidth); assertEquals(maxNumberTxSpatialStreams, expectedCap.maxNumberTxSpatialStreams); assertEquals(maxNumberRxSpatialStreams, expectedCap.maxNumberRxSpatialStreams); + if (SdkLevel.isAtLeastV()) { + assertTrue(HalTestUtils.ouiKeyedDataListEquals( + halCap.vendorData, expectedCap.vendorData)); + } else { + assertTrue(expectedCap.vendorData.isEmpty()); + } } /** @@ -2428,8 +2536,35 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { .setDestinationPort(10) .build(); frameworkPolicy.setTranslatedPolicyId(translatedPolicyId); - QosPolicyScsData halPolicy = SupplicantStaIfaceHalAidlImpl - .frameworkToHalQosPolicyScsData(frameworkPolicy); + QosPolicyScsData halPolicy = mDut.frameworkToHalQosPolicyScsData(frameworkPolicy); + compareQosPolicyParamsToHal(frameworkPolicy, halPolicy); + } + + /** + * Tests the conversion method + * {@link SupplicantStaIfaceHalAidlImpl#frameworkToHalQosPolicyScsData(QosPolicyParams)} + * when the instance contains QosCharacteristics. + */ + @Test + public void testFrameworkToHalQosPolicyScsDataWithCharacteristics() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + when(mISupplicantMock.getInterfaceVersion()).thenReturn(3); + assertTrue(mDut.startDaemon()); // retrieves and caches the interface version + + QosCharacteristics frameworkChars = new QosCharacteristics.Builder( + 2000, 5000, 500, 2) + .setMaxMsduSizeOctets(4) + .setServiceStartTimeInfo(250, 0x5) + .setMeanDataRateKbps(1500) + .setMsduLifetimeMillis(400) + .setMsduDeliveryInfo(QosCharacteristics.DELIVERY_RATIO_99, 5) + .build(); + QosPolicyParams frameworkPolicy = new QosPolicyParams.Builder( + 5 /* policyId */, QosPolicyParams.DIRECTION_UPLINK) + .setQosCharacteristics(frameworkChars) + .build(); + frameworkPolicy.setTranslatedPolicyId(15); + QosPolicyScsData halPolicy = mDut.frameworkToHalQosPolicyScsData(frameworkPolicy); compareQosPolicyParamsToHal(frameworkPolicy, halPolicy); } @@ -2540,6 +2675,55 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { return qosPolicyData; } + private static void compareFrameworkQosCharacteristicsToHal( + android.net.wifi.QosCharacteristics frameworkChars, + android.hardware.wifi.supplicant.QosCharacteristics halChars) { + assertEquals(frameworkChars.getMinServiceIntervalMicros(), halChars.minServiceIntervalUs); + assertEquals(frameworkChars.getMaxServiceIntervalMicros(), halChars.maxServiceIntervalUs); + assertEquals(frameworkChars.getMinDataRateKbps(), halChars.minDataRateKbps); + assertEquals(frameworkChars.getDelayBoundMicros(), halChars.delayBoundUs); + + int paramsMask = halChars.optionalFieldMask; + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MAX_MSDU_SIZE)) { + assertNotEquals(0, paramsMask & QosCharacteristicsMask.MAX_MSDU_SIZE); + assertEquals((char) frameworkChars.getMaxMsduSizeOctets(), halChars.maxMsduSizeOctets); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.SERVICE_START_TIME)) { + assertNotEquals(0, paramsMask & QosCharacteristicsMask.SERVICE_START_TIME); + assertNotEquals(0, paramsMask & QosCharacteristicsMask.SERVICE_START_TIME_LINK_ID); + assertEquals(frameworkChars.getServiceStartTimeMicros(), halChars.serviceStartTimeUs); + assertEquals((byte) frameworkChars.getServiceStartTimeLinkId(), + halChars.serviceStartTimeLinkId); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MEAN_DATA_RATE)) { + assertNotEquals(0, paramsMask & QosCharacteristicsMask.MEAN_DATA_RATE); + assertEquals(frameworkChars.getMeanDataRateKbps(), halChars.meanDataRateKbps); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.BURST_SIZE)) { + assertNotEquals(0, paramsMask & QosCharacteristicsMask.BURST_SIZE); + assertEquals(frameworkChars.getBurstSizeOctets(), halChars.burstSizeOctets); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MSDU_LIFETIME)) { + assertNotEquals(0, paramsMask & QosCharacteristicsMask.MSDU_LIFETIME); + assertEquals((char) frameworkChars.getMsduLifetimeMillis(), halChars.msduLifetimeMs); + } + if (frameworkChars.containsOptionalField( + android.net.wifi.QosCharacteristics.MSDU_DELIVERY_INFO)) { + assertNotEquals(0, paramsMask & QosCharacteristicsMask.MSDU_DELIVERY_INFO); + MsduDeliveryInfo halDeliveryInfo = halChars.msduDeliveryInfo; + int convertedFrameworkRatio = + SupplicantStaIfaceHalAidlImpl.frameworkToHalDeliveryRatio( + frameworkChars.getDeliveryRatio()); + assertEquals(convertedFrameworkRatio, halDeliveryInfo.deliveryRatio); + assertEquals((byte) frameworkChars.getCountExponent(), halDeliveryInfo.countExponent); + } + } + private void compareQosPolicyParamsToHal(QosPolicyParams frameworkPolicy, QosPolicyScsData halPolicy) { assertEquals((byte) frameworkPolicy.getTranslatedPolicyId(), halPolicy.policyId); @@ -2576,6 +2760,17 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { assertNotEquals(0, paramsMask & QosPolicyClassifierParamsMask.DSCP); assertEquals((byte) frameworkPolicy.getDscp(), classifierParams.dscp); } + + if (mDut.isServiceVersionAtLeast(3)) { + int convertedFrameworkDirection = + SupplicantStaIfaceHalAidlImpl.frameworkToHalPolicyDirection( + frameworkPolicy.getDirection()); + assertEquals(convertedFrameworkDirection, halPolicy.direction); + if (frameworkPolicy.getQosCharacteristics() != null) { + compareFrameworkQosCharacteristicsToHal( + frameworkPolicy.getQosCharacteristics(), halPolicy.QosCharacteristics); + } + } } /** @@ -3122,4 +3317,74 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest { assertTrue(mDut.startDaemon()); verify(mISupplicantMock, never()).getInterfaceVersion(); } + + /** + * Test {@link SupplicantStaIfaceHalAidlImpl#enableMscs(MscsParams, String)} and verify the + * conversion from {@link MscsParams} to its HAL equivalent. + */ + @Test + public void testEnableMscs() throws Exception { + int userPriorityBitmap = (1 << 6) | (1 << 7); + int userPriorityLimit = 5; + int streamTimeoutUs = 1500; + int frameworkFrameClassifierMask = + MscsParams.FRAME_CLASSIFIER_IP_VERSION | MscsParams.FRAME_CLASSIFIER_DSCP; + byte halFrameClassifierMask = + FrameClassifierFields.IP_VERSION | FrameClassifierFields.DSCP; + + ArgumentCaptor<android.hardware.wifi.supplicant.MscsParams> halParamsCaptor = + ArgumentCaptor.forClass(android.hardware.wifi.supplicant.MscsParams.class); + doNothing().when(mISupplicantStaIfaceMock).configureMscs(any()); + executeAndValidateInitializationSequence(); + + MscsParams frameworkParams = new MscsParams.Builder() + .setUserPriorityBitmap(userPriorityBitmap) + .setUserPriorityLimit(userPriorityLimit) + .setStreamTimeoutUs(streamTimeoutUs) + .setFrameClassifierFields(frameworkFrameClassifierMask) + .build(); + mDut.setupIface(WLAN0_IFACE_NAME); + mDut.enableMscs(frameworkParams, WLAN0_IFACE_NAME); + + verify(mISupplicantStaIfaceMock).configureMscs(halParamsCaptor.capture()); + android.hardware.wifi.supplicant.MscsParams halParams = halParamsCaptor.getValue(); + assertEquals((byte) userPriorityBitmap, halParams.upBitmap); + assertEquals((byte) userPriorityLimit, halParams.upLimit); + assertEquals(streamTimeoutUs, halParams.streamTimeoutUs); + assertEquals(halFrameClassifierMask, halParams.frameClassifierMask); + } + + /** + * Test that MSCS params set through {@link SupplicantStaIfaceHalAidlImpl#enableMscs( + * MscsParams, String)} are cached for later resends. + */ + @Test + public void testEnableAndResendMscs() throws Exception { + executeAndValidateInitializationSequence(); + mDut.setupIface(WLAN0_IFACE_NAME); + + doNothing().when(mISupplicantStaIfaceMock).configureMscs(any()); + MscsParams defaultParams = new MscsParams.Builder().build(); + + ArgumentCaptor<android.hardware.wifi.supplicant.MscsParams> halParamsCaptor = + ArgumentCaptor.forClass(android.hardware.wifi.supplicant.MscsParams.class); + mDut.enableMscs(defaultParams, WLAN0_IFACE_NAME); + verify(mISupplicantStaIfaceMock).configureMscs(halParamsCaptor.capture()); + android.hardware.wifi.supplicant.MscsParams initialParams = halParamsCaptor.getValue(); + + // Resend should use the params cached during the initial send. + mDut.resendMscs(WLAN0_IFACE_NAME); + verify(mISupplicantStaIfaceMock, times(2)).configureMscs(halParamsCaptor.capture()); + android.hardware.wifi.supplicant.MscsParams resendParams = halParamsCaptor.getValue(); + + assertEquals(initialParams.upBitmap, resendParams.upBitmap); + assertEquals(initialParams.upLimit, resendParams.upLimit); + assertEquals(initialParams.streamTimeoutUs, resendParams.streamTimeoutUs); + assertEquals(initialParams.frameClassifierMask, resendParams.frameClassifierMask); + + // Disabling MSCS should clear the cached params and prevent future resends. + mDut.disableMscs(WLAN0_IFACE_NAME); + mDut.resendMscs(WLAN0_IFACE_NAME); + verify(mISupplicantStaIfaceMock, times(2)).configureMscs(halParamsCaptor.capture()); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalHidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalHidlImplTest.java index 7f01d7b563..be19bc53d1 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalHidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalHidlImplTest.java @@ -1501,6 +1501,73 @@ public class SupplicantStaIfaceHalHidlImplTest extends WifiBaseTest { } /** + * Tests that association rejection due to timeout doesn't broadcast authentication failure + * with reason code ERROR_AUTH_FAILURE_WRONG_PSWD. + * Driver/Supplicant sets the timedOut field when there is no ACK or response frame for + * Authentication request or Association request frame. + */ + @Test + public void testAssociationRejectionDueToTimedOutDoesntNotifyWrongPassword() throws Exception { + executeAndValidateInitializationSequence(); + assertNotNull(mISupplicantStaIfaceCallback); + + executeAndValidateConnectSequenceWithKeyMgmt( + SUPPLICANT_NETWORK_ID, false, TRANSLATED_SUPPLICANT_SSID.toString(), + WifiConfiguration.SECURITY_TYPE_SAE, null, true); + mISupplicantStaIfaceCallback.onStateChanged( + ISupplicantStaIfaceCallback.State.ASSOCIATING, + NativeUtil.macAddressToByteArray(BSSID), + SUPPLICANT_NETWORK_ID, + NativeUtil.decodeSsid(SUPPLICANT_SSID)); + mISupplicantStaIfaceCallback.onAssociationRejected( + NativeUtil.macAddressToByteArray(BSSID), + ISupplicantStaIfaceCallback.StatusCode.UNSPECIFIED_FAILURE, true); + verify(mWifiMonitor, never()).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME), + anyInt(), anyInt(), any(), any()); + ArgumentCaptor<AssocRejectEventInfo> assocRejectEventInfoCaptor = + ArgumentCaptor.forClass(AssocRejectEventInfo.class); + verify(mWifiMonitor).broadcastAssociationRejectionEvent( + eq(WLAN0_IFACE_NAME), assocRejectEventInfoCaptor.capture()); + AssocRejectEventInfo assocRejectEventInfo = + (AssocRejectEventInfo) assocRejectEventInfoCaptor.getValue(); + assertNotNull(assocRejectEventInfo); + assertTrue(assocRejectEventInfo.timedOut); + } + + /** + * Tests the handling of authentication failure for WPA3-Personal networks with + * status code = 15 (CHALLENGE_FAIL) + */ + @Test + public void testWpa3AuthRejectionDueToChallengeFail() throws Exception { + executeAndValidateInitializationSequence(); + assertNotNull(mISupplicantStaIfaceCallback); + + executeAndValidateConnectSequenceWithKeyMgmt( + SUPPLICANT_NETWORK_ID, false, TRANSLATED_SUPPLICANT_SSID.toString(), + WifiConfiguration.SECURITY_TYPE_SAE, null, true); + mISupplicantStaIfaceCallback.onStateChanged( + ISupplicantStaIfaceCallback.State.ASSOCIATING, + NativeUtil.macAddressToByteArray(BSSID), + SUPPLICANT_NETWORK_ID, + NativeUtil.decodeSsid(SUPPLICANT_SSID)); + int statusCode = ISupplicantStaIfaceCallback.StatusCode.CHALLENGE_FAIL; + mISupplicantStaIfaceCallback.onAssociationRejected( + NativeUtil.macAddressToByteArray(BSSID), statusCode, false); + verify(mWifiMonitor).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME), + eq(WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD), eq(-1), + eq(TRANSLATED_SUPPLICANT_SSID.toString()), eq(MacAddress.fromString(BSSID))); + ArgumentCaptor<AssocRejectEventInfo> assocRejectEventInfoCaptor = + ArgumentCaptor.forClass(AssocRejectEventInfo.class); + verify(mWifiMonitor).broadcastAssociationRejectionEvent( + eq(WLAN0_IFACE_NAME), assocRejectEventInfoCaptor.capture()); + AssocRejectEventInfo assocRejectEventInfo = + (AssocRejectEventInfo) assocRejectEventInfoCaptor.getValue(); + assertNotNull(assocRejectEventInfo); + assertEquals(statusCode, assocRejectEventInfo.statusCode); + } + + /** * Tests the handling of incorrect network passwords for WEP networks. */ @Test @@ -1586,6 +1653,30 @@ public class SupplicantStaIfaceHalHidlImplTest extends WifiBaseTest { } /** + * Tests the handling of incorrect network password for AP_BUSY error code + * + * If the disconnect reason is "NO_MORE_STAS - Disassociated because AP is unable + * to handle all currently associated STAs", do not call it a password mismatch. + */ + @Test + public void testApBusy() throws Exception { + executeAndValidateInitializationSequence(); + assertNotNull(mISupplicantStaIfaceCallback); + + int reasonCode = ISupplicantStaIfaceCallback.ReasonCode.DISASSOC_AP_BUSY; + + mISupplicantStaIfaceCallback.onStateChanged( + ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE, + NativeUtil.macAddressToByteArray(BSSID), + SUPPLICANT_NETWORK_ID, + NativeUtil.decodeSsid(SUPPLICANT_SSID)); + mISupplicantStaIfaceCallback.onDisconnected( + NativeUtil.macAddressToByteArray(BSSID), true, reasonCode); + verify(mWifiMonitor, never()).broadcastAuthenticationFailureEvent(any(), anyInt(), + anyInt(), any(), any()); + } + + /** * Tests the handling of eap failure during disconnect. */ @Test diff --git a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalAidlImplTest.java index 8d77125a0b..fbd03da9c8 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalAidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalAidlImplTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.when; import android.app.test.MockAnswerUtil.AnswerWithArguments; import android.content.Context; +import android.hardware.wifi.common.OuiKeyedData; import android.hardware.wifi.supplicant.GroupCipherMask; import android.hardware.wifi.supplicant.GsmRand; import android.hardware.wifi.supplicant.ISupplicantStaNetwork; @@ -53,6 +54,7 @@ import android.net.wifi.SecurityParams; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiManager; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.text.TextUtils; @@ -74,6 +76,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; @@ -1359,6 +1362,34 @@ public class SupplicantStaNetworkHalAidlImplTest extends WifiBaseTest { } /** + * Tests that vendor data is sent to the HAL if included in the WifiConfiguration. + */ + @Test + public void testSetVendorData() throws Exception { + // Re-initialize DUT to HAL service version 3 + assumeTrue(SdkLevel.isAtLeastV()); + mSupplicantNetwork = new SupplicantStaNetworkHalAidlImpl(3, + mISupplicantStaNetworkMock, IFACE_NAME, mContext, mWifiMonitor, + mWifiGlobals, mAdvanceKeyMgmtFeatures, mWpaDriverFeatures); + + PersistableBundle bundle = new PersistableBundle(); + bundle.putInt("intFieldKey", 1337); + android.net.wifi.OuiKeyedData ouiKeyedData = + new android.net.wifi.OuiKeyedData.Builder(0x00aabbcc, bundle).build(); + List<android.net.wifi.OuiKeyedData> frameworkVendorData = Arrays.asList(ouiKeyedData); + + WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork(); + config.setVendorData(frameworkVendorData); + testWifiConfigurationSaveLoad(config); + + verify(mISupplicantStaNetworkMock).setVendorData(any(OuiKeyedData[].class)); + OuiKeyedData[] halVendorData = mSupplicantVariables.vendorData; + assertEquals(frameworkVendorData.size(), halVendorData.length); + assertEquals(frameworkVendorData.get(0).getOui(), halVendorData[0].oui); + assertTrue(frameworkVendorData.get(0).getData().equals(halVendorData[0].vendorData)); + } + + /** * Sets up the AIDL interface mock with all the setters/getter values. * Note: This only sets up the mock to return success on all methods. */ @@ -1818,6 +1849,13 @@ public class SupplicantStaNetworkHalAidlImplTest extends WifiBaseTest { mSupplicantVariables.selectedRcoi = selectedRcoi; } }).when(mISupplicantStaNetworkMock).setRoamingConsortiumSelection(any(byte[].class)); + + /** Vendor data */ + doAnswer(new AnswerWithArguments() { + public void answer(OuiKeyedData[] vendorData) throws RemoteException { + mSupplicantVariables.vendorData = vendorData; + } + }).when(mISupplicantStaNetworkMock).setVendorData(any(OuiKeyedData[].class)); } // Private class to to store/inspect values set via the AIDL mock. @@ -1860,5 +1898,6 @@ public class SupplicantStaNetworkHalAidlImplTest extends WifiBaseTest { public boolean eapErp; public byte saeH2eMode; public byte[] selectedRcoi; + public OuiKeyedData[] vendorData; } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/TwtManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/TwtManagerTest.java new file mode 100644 index 0000000000..6bcc9c59cf --- /dev/null +++ b/service/tests/wifitests/src/com/android/server/wifi/TwtManagerTest.java @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2024 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.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import android.app.AlarmManager; +import android.app.test.TestAlarmManager; +import android.content.res.Resources; +import android.net.wifi.ITwtCallback; +import android.net.wifi.ITwtCapabilitiesListener; +import android.net.wifi.ITwtStatsListener; +import android.net.wifi.WifiContext; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiTwtSession; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSession; +import android.net.wifi.twt.TwtSessionCallback; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.test.TestLooper; + +import androidx.test.filters.SmallTest; + +import com.android.wifi.resources.R; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InOrder; +import org.mockito.Mock; + +/** + * Unit test for {@link TwtManager} + */ +@SmallTest +public class TwtManagerTest extends WifiBaseTest { + private static final int TWT_CALLBACKS_ID_START_OFFSET = 1; + private static final String WIFI_IFACE_NAME = "wlan0"; + private static final String WIFI_IFACE_NAME_1 = "wlan1"; + + private static final int TEST_TWT_SESSION_ID = 10; + private static final int TEST_TWT_CMD_ID = 1; + private static final String TEST_BSSID = "00:11:22:33:44:55"; + private static final String TEST_BLOCKED_BSSID_1 = "AA:BB:CC:DD:EE:FF"; + private static final int TEST_BLOCKED_OUI_1 = 0xAABBCC; + private static final int TEST_BLOCKED_OUI_2 = 0xAABBCD; + private static final int TEST_BLOCKED_OUI_3 = 0xAABBCE; + private static final int TEST_BLOCKED_OUI_4 = 0xAABBCF; + + @Mock + Clock mClock; + private TestAlarmManager mTestAlarmManager; + private final TestLooper mLooper = new TestLooper(); + @Mock + private WifiInjector mWifiInjector; + private TwtManager mTwtManager; + @Mock + WifiNative mWifiNative; + @Mock + private ClientModeImplMonitor mCmiMonitor; + @Captor + private ArgumentCaptor<ClientModeImplListener> mCmiListenerCaptor; + @Mock + private IBinder mAppBinder; + private Handler mHandler; + private AlarmManager mAlarmManager; + @Mock + ConcreteClientModeManager mClientModeManager; + @Captor + private ArgumentCaptor<TwtManager.WifiNativeTwtEvents> mWifiNativeTwtEventsArgumentCaptor; + @Mock + Resources mResources; + @Mock + WifiContext mContext; + + /** + * Test setup. + */ + @Before + public void setUp() throws Exception { + initMocks(this); + mHandler = new Handler(mLooper.getLooper()); + mTestAlarmManager = new TestAlarmManager(); + mAlarmManager = mTestAlarmManager.getAlarmManager(); + when(mWifiInjector.getAlarmManager()).thenReturn(mAlarmManager); + when(mWifiInjector.getContext()).thenReturn(mContext); + when(mContext.getResources()).thenReturn(mResources); + int[] blockedOuiList = + {TEST_BLOCKED_OUI_4, TEST_BLOCKED_OUI_3, TEST_BLOCKED_OUI_2, TEST_BLOCKED_OUI_1}; + when(mResources.getIntArray(R.array.config_wifiTwtBlockedOuiList)).thenReturn( + blockedOuiList); + mTwtManager = new TwtManager(mWifiInjector, mCmiMonitor, mWifiNative, mHandler, mClock, + WifiTwtSession.MAX_TWT_SESSIONS, TWT_CALLBACKS_ID_START_OFFSET); + verify(mCmiMonitor).registerListener(mCmiListenerCaptor.capture()); + mTwtManager.registerWifiNativeTwtEvents(); + verify(mWifiNative).registerTwtCallbacks(mWifiNativeTwtEventsArgumentCaptor.capture()); + } + + private Bundle getDefaultTwtCapabilities() { + Bundle twtCapabilities = new Bundle(); + twtCapabilities.putBoolean(WifiManager.TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER, false); + twtCapabilities.putInt(WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS, -1); + twtCapabilities.putInt(WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS, -1); + twtCapabilities.putLong(WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS, -1); + twtCapabilities.putLong(WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS, -1); + return twtCapabilities; + } + + private Bundle getMockTwtCapabilities() { + Bundle twtCapabilities = new Bundle(); + twtCapabilities.putBoolean(WifiManager.TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER, true); + twtCapabilities.putInt(WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS, 100); + twtCapabilities.putInt(WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS, 1000); + twtCapabilities.putLong(WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS, + 1000); + twtCapabilities.putLong(WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS, + 10000); + return twtCapabilities; + } + + private static Bundle getMockTwtStats() { + Bundle twtStats = new Bundle(); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT, 200); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT, 300); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE, 400); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE, 200); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS, 1000); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_EOSP_COUNT, 10); + return twtStats; + } + + private static Bundle getDefaultTwtStats() { + Bundle twtStats = new Bundle(); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS, -1); + twtStats.putInt(TwtSession.TWT_STATS_KEY_INT_EOSP_COUNT, -1); + return twtStats; + } + + private boolean isBundleContentEqual(Bundle expected, Bundle actual) { + if (expected == actual) return true; + for (String key : expected.keySet()) { + if (!actual.containsKey(key) || !actual.get(key).equals(expected.get(key))) { + return false; + } + } + return true; + } + + @Test + public void testGetTwtCapabilities() throws RemoteException { + ITwtCapabilitiesListener iTwtCapabilitiesListener = mock(ITwtCapabilitiesListener.class); + InOrder inorder = inOrder(iTwtCapabilitiesListener); + // Test with null interface name + final Bundle defaultTwtCapabilities = getDefaultTwtCapabilities(); + mTwtManager.getTwtCapabilities(null, iTwtCapabilitiesListener); + inorder.verify(iTwtCapabilitiesListener).onResult( + argThat(argument -> isBundleContentEqual(defaultTwtCapabilities, argument))); + // Test getTwtCapabilities when WifiNative return null + when(mWifiNative.getTwtCapabilities(eq(WIFI_IFACE_NAME))).thenReturn(null); + mTwtManager.getTwtCapabilities(null, iTwtCapabilitiesListener); + inorder.verify(iTwtCapabilitiesListener).onResult( + argThat(argument -> isBundleContentEqual(defaultTwtCapabilities, argument))); + // Test getTwtCapabilities + final Bundle mockTwtCapabilities = getMockTwtCapabilities(); + when(mWifiNative.getTwtCapabilities(eq(WIFI_IFACE_NAME))).thenReturn(mockTwtCapabilities); + mTwtManager.getTwtCapabilities(WIFI_IFACE_NAME, iTwtCapabilitiesListener); + inorder.verify(iTwtCapabilitiesListener).onResult( + argThat(argument -> isBundleContentEqual(mockTwtCapabilities, argument))); + } + + @Test + public void testOuiBlockListing() throws RemoteException { + ITwtCallback iTwtCallback = mock(ITwtCallback.class); + TwtRequest twtRequest = mock(TwtRequest.class); + InOrder inOrderCallback = inOrder(iTwtCallback); + when(iTwtCallback.asBinder()).thenReturn(mAppBinder); + when(mWifiNative.setupTwtSession(eq(1), eq(WIFI_IFACE_NAME), eq(twtRequest))).thenReturn( + true); + mTwtManager.setupTwtSession(WIFI_IFACE_NAME, twtRequest, iTwtCallback, + Binder.getCallingUid(), TEST_BLOCKED_BSSID_1); + inOrderCallback.verify(iTwtCallback).onFailure( + TwtSessionCallback.TWT_ERROR_CODE_AP_OUI_BLOCKLISTED); + } + + @Test + public void testSetupTwtSession() throws RemoteException { + ITwtCallback iTwtCallback = mock(ITwtCallback.class); + TwtRequest twtRequest = mock(TwtRequest.class); + when(iTwtCallback.asBinder()).thenReturn(mAppBinder); + InOrder inOrderCallback = inOrder(iTwtCallback); + InOrder inOrderBinder = inOrder(mAppBinder); + InOrder inOrderAlarm = inOrder(mAlarmManager); + // Test with null interface + mTwtManager.setupTwtSession(null, twtRequest, iTwtCallback, Binder.getCallingUid(), + TEST_BSSID); + inOrderCallback.verify(iTwtCallback).onFailure( + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + // Test when wifiNative.setupTwtSession return false + when(mWifiNative.setupTwtSession(eq(1), eq(WIFI_IFACE_NAME), eq(twtRequest))).thenReturn( + false); + mTwtManager.setupTwtSession(WIFI_IFACE_NAME, twtRequest, iTwtCallback, + Binder.getCallingUid(), TEST_BSSID); + inOrderBinder.verify(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderAlarm.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), + anyString(), any(AlarmManager.OnAlarmListener.class), eq(mHandler)); + inOrderBinder.verify(mAppBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderCallback.verify(iTwtCallback).onFailure( + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + inOrderAlarm.verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class)); + // Test when wifiNative.setupTwtSession return true + when(mWifiNative.setupTwtSession(eq(1), eq(WIFI_IFACE_NAME), eq(twtRequest))).thenReturn( + true); + mTwtManager.setupTwtSession(WIFI_IFACE_NAME, twtRequest, iTwtCallback, + Binder.getCallingUid(), TEST_BSSID); + inOrderBinder.verify(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderAlarm.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), + anyString(), any(AlarmManager.OnAlarmListener.class), eq(mHandler)); + } + + @Test + public void testTeardownTwtSession() throws RemoteException { + ITwtCallback iTwtCallback = mock(ITwtCallback.class); + TwtRequest twtRequest = mock(TwtRequest.class); + when(iTwtCallback.asBinder()).thenReturn(mAppBinder); + InOrder inOrderCallback = inOrder(iTwtCallback); + InOrder inOrderBinder = inOrder(mAppBinder); + InOrder inOrderAlarm = inOrder(mAlarmManager); + when(mWifiNative.tearDownTwtSession(eq(TEST_TWT_CMD_ID), eq(WIFI_IFACE_NAME), + eq(TEST_TWT_SESSION_ID))).thenReturn(true); + when(mWifiNative.setupTwtSession(eq(TEST_TWT_CMD_ID), eq(WIFI_IFACE_NAME), + eq(twtRequest))).thenReturn(true); + // Test when session is not setup + mTwtManager.tearDownTwtSession(WIFI_IFACE_NAME, TEST_TWT_SESSION_ID); + inOrderCallback.verifyNoMoreInteractions(); + inOrderBinder.verifyNoMoreInteractions(); + inOrderAlarm.verifyNoMoreInteractions(); + // Make a session + mTwtManager.setupTwtSession(WIFI_IFACE_NAME, twtRequest, iTwtCallback, + Binder.getCallingUid(), TEST_BSSID); + inOrderBinder.verify(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderAlarm.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), + anyString(), any(AlarmManager.OnAlarmListener.class), eq(mHandler)); + mWifiNativeTwtEventsArgumentCaptor.getValue().onTwtSessionCreate(TEST_TWT_CMD_ID, 100, 1000, + 1, TEST_TWT_SESSION_ID); + inOrderCallback.verify(iTwtCallback).onCreate(eq(100), eq(1000L), eq(1), + eq(Binder.getCallingUid()), eq(TEST_TWT_SESSION_ID)); + // Test teardown with null interface + mTwtManager.tearDownTwtSession(null, TEST_TWT_SESSION_ID); + inOrderCallback.verify(iTwtCallback).onFailure( + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + // Test teardown with wrong interface + mTwtManager.tearDownTwtSession(WIFI_IFACE_NAME_1, TEST_TWT_SESSION_ID); + inOrderCallback.verify(iTwtCallback).onFailure( + TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE); + // Test teardown the session + mTwtManager.tearDownTwtSession(WIFI_IFACE_NAME, TEST_TWT_SESSION_ID); + inOrderBinder.verify(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderAlarm.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), + anyString(), any(AlarmManager.OnAlarmListener.class), eq(mHandler)); + } + + @Test + public void testGetStatsSession() throws RemoteException { + final Bundle defaultTwtStats = getDefaultTwtStats(); + ITwtCallback iTwtCallback = mock(ITwtCallback.class); + ITwtStatsListener iTwtStatsListener = mock(ITwtStatsListener.class); + TwtRequest twtRequest = mock(TwtRequest.class); + when(iTwtStatsListener.asBinder()).thenReturn(mAppBinder); + when(iTwtCallback.asBinder()).thenReturn(mAppBinder); + InOrder inOrderListener = inOrder(iTwtStatsListener); + InOrder inOrderBinder = inOrder(mAppBinder); + InOrder inOrderAlarm = inOrder(mAlarmManager); + when(mWifiNative.getStatsTwtSession(eq(TEST_TWT_CMD_ID), eq(WIFI_IFACE_NAME), + eq(TEST_TWT_SESSION_ID))).thenReturn(true); + when(mWifiNative.setupTwtSession(eq(TEST_TWT_CMD_ID), eq(WIFI_IFACE_NAME), + eq(twtRequest))).thenReturn(true); + // Test when interface is not registered + mTwtManager.getStatsTwtSession(WIFI_IFACE_NAME_1, iTwtStatsListener, TEST_TWT_SESSION_ID); + inOrderListener.verify(iTwtStatsListener).onResult( + argThat(argument -> isBundleContentEqual(defaultTwtStats, argument))); + // Test when session is not setup + mTwtManager.getStatsTwtSession(WIFI_IFACE_NAME, iTwtStatsListener, TEST_TWT_SESSION_ID); + inOrderListener.verify(iTwtStatsListener).onResult( + argThat(argument -> isBundleContentEqual(defaultTwtStats, argument))); + // Make a session + mTwtManager.setupTwtSession(WIFI_IFACE_NAME, twtRequest, iTwtCallback, + Binder.getCallingUid(), TEST_BSSID); + inOrderBinder.verify(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderAlarm.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), + anyString(), any(AlarmManager.OnAlarmListener.class), eq(mHandler)); + mWifiNativeTwtEventsArgumentCaptor.getValue().onTwtSessionCreate(TEST_TWT_CMD_ID, 100, 1000, + 1, TEST_TWT_SESSION_ID); + verify(iTwtCallback).onCreate(eq(100), eq(1000L), eq(1), eq(Binder.getCallingUid()), + eq(TEST_TWT_SESSION_ID)); + // Test get stats on the session + mTwtManager.getStatsTwtSession(WIFI_IFACE_NAME, iTwtStatsListener, TEST_TWT_SESSION_ID); + Bundle twtStats = getMockTwtStats(); + mWifiNativeTwtEventsArgumentCaptor.getValue().onTwtSessionStats(TEST_TWT_CMD_ID, + TEST_TWT_SESSION_ID, twtStats); + inOrderListener.verify(iTwtStatsListener).onResult( + argThat(argument -> isBundleContentEqual(twtStats, argument))); + } + + @Test + public void testDisconnect() throws RemoteException { + ITwtCallback iTwtCallback = mock(ITwtCallback.class); + TwtRequest twtRequest = mock(TwtRequest.class); + when(iTwtCallback.asBinder()).thenReturn(mAppBinder); + InOrder inOrderCallback = inOrder(iTwtCallback); + InOrder inOrderBinder = inOrder(mAppBinder); + InOrder inOrderAlarm = inOrder(mAlarmManager); + when(mClientModeManager.getInterfaceName()).thenReturn("wlan0"); + when(mClientModeManager.getRole()).thenReturn(ActiveModeManager.ROLE_CLIENT_PRIMARY); + // Setup TWT session + when(mWifiNative.setupTwtSession(eq(1), eq(WIFI_IFACE_NAME), eq(twtRequest))).thenReturn( + true); + mTwtManager.setupTwtSession(WIFI_IFACE_NAME, twtRequest, iTwtCallback, + Binder.getCallingUid(), TEST_BSSID); + inOrderBinder.verify(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderAlarm.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), + anyString(), any(AlarmManager.OnAlarmListener.class), eq(mHandler)); + // Disconnect and check the cleanup + mCmiListenerCaptor.getValue().onConnectionEnd(mClientModeManager); + inOrderCallback.verify(iTwtCallback).onFailure(TwtSessionCallback.TWT_ERROR_CODE_FAIL); + inOrderBinder.verify(mAppBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + inOrderAlarm.verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class)); + } +} diff --git a/service/tests/wifitests/src/com/android/server/wifi/UntrustedWifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/UntrustedWifiNetworkFactoryTest.java index f28628a517..51fe0fecff 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/UntrustedWifiNetworkFactoryTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/UntrustedWifiNetworkFactoryTest.java @@ -23,7 +23,8 @@ import android.content.Context; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import org.junit.After; import org.junit.Before; diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java index 644d022cdd..cd4a3fe773 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.server.wifi; import static android.net.wifi.SoftApConfiguration.RANDOMIZATION_NON_PERSISTENT; @@ -23,6 +22,7 @@ import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE; import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION; import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STATIC_CHIP_INFO; import static com.google.common.truth.Truth.assertThat; @@ -33,9 +33,11 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -110,6 +112,8 @@ public class WifiApConfigStoreTest extends WifiBaseTest { @Mock private ActiveModeWarden mActiveModeWarden; @Mock private PackageManager mPackageManager; @Mock private SoftApCapability mSoftApCapability; + @Mock private HalDeviceManager mHalDeviceManager; + @Mock private WifiSettingsConfigStore mWifiSettingsConfigStore; private Random mRandom; private MockResources mResources; @@ -118,6 +122,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest { private SoftApStoreData.DataSource mDataStoreSource; private ArrayList<Integer> mKnownGood2GChannelList; + final ArgumentCaptor<WifiSettingsConfigStore.OnSettingsChangedListener> + mStaticChipInfoListenerCaptor = + ArgumentCaptor.forClass(WifiSettingsConfigStore.OnSettingsChangedListener.class); + @Before public void setUp() throws Exception { mLooper = new TestLooper(); @@ -125,7 +133,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest { MockitoAnnotations.initMocks(this); mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.P; when(mContext.getApplicationInfo()).thenReturn(mMockApplInfo); - + when(mWifiInjector.getSettingsConfigStore()).thenReturn(mWifiSettingsConfigStore); + when(mWifiInjector.getHalDeviceManager()).thenReturn(mHalDeviceManager); + // Default assume true for all old test cases. + when(mHalDeviceManager.isConcurrencyComboLoadedFromDriver()).thenReturn(true); /* Setup expectations for Resources to return some default settings. */ mResources = new MockResources(); mResources.setString(R.string.config_wifiSoftap2gChannelList, @@ -187,7 +198,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest { ArgumentCaptor.forClass(SoftApStoreData.DataSource.class); verify(mWifiInjector).makeSoftApStoreData(dataStoreSourceArgumentCaptor.capture()); mDataStoreSource = dataStoreSourceArgumentCaptor.getValue(); - + verify(mWifiSettingsConfigStore).registerChangeListener( + eq(WIFI_STATIC_CHIP_INFO), + mStaticChipInfoListenerCaptor.capture(), + any(Handler.class)); return store; } @@ -223,7 +237,6 @@ public class WifiApConfigStoreTest extends WifiBaseTest { verifyDefaultApConfig(config, expectedSsid, isSaeSupport, true, false); } - private void verifyDefaultApConfig(SoftApConfiguration config, String expectedSsid, boolean isSaeSupport, boolean isMacRandomizationSupport, boolean isBridgedApSupport) { String[] splitSsid = config.getWifiSsid().getUtf8Text().toString().split("_"); @@ -1472,4 +1485,43 @@ public class WifiApConfigStoreTest extends WifiBaseTest { .setSsid(TEST_DEFAULT_HOTSPOT_SSID).build()); assertEquals(lastPassphrase, store.getLastConfiguredTetheredApPassphraseSinceBoot()); } + + @Test + public void testChipSupportBridgedButStaticChipUpdatedAfterGeneratingDefaultConfig() + throws Exception { + assumeTrue(SdkLevel.isAtLeastS()); + when(mHalDeviceManager.isConcurrencyComboLoadedFromDriver()).thenReturn(false); + mResources.setBoolean(R.bool.config_wifiBridgedSoftApSupported, true); + WifiApConfigStore store = createWifiApConfigStore(); + verifyDefaultApConfig(store.getApConfiguration(), + TEST_DEFAULT_AP_SSID, false, true, true); + mLooper.dispatchAll(); + mStaticChipInfoListenerCaptor.getValue() + .onSettingsChanged(WIFI_STATIC_CHIP_INFO, "new static chip info"); + mLooper.dispatchAll(); + // Chip supports bridged mode, so no extra saveToStore when chip info is updated. + verify(mWifiConfigManager).saveToStore(true); + } + + @Test + public void testChipNotSupportButStaticChipUpdatedAfterGeneratingDefaultConfig() + throws Exception { + assumeTrue(SdkLevel.isAtLeastS()); + reset(mWifiNative); + when(mWifiNative.canDeviceSupportCreateTypeCombo(any())).thenReturn(false); + when(mHalDeviceManager.isConcurrencyComboLoadedFromDriver()).thenReturn(false); + mResources.setBoolean(R.bool.config_wifiBridgedSoftApSupported, true); + WifiApConfigStore store = createWifiApConfigStore(); + // Verify default band is bridged mode + verifyDefaultApConfig(store.getApConfiguration(), + TEST_DEFAULT_AP_SSID, false, true, true); + mLooper.dispatchAll(); + mStaticChipInfoListenerCaptor.getValue() + .onSettingsChanged(WIFI_STATIC_CHIP_INFO, "new static chip info"); + mLooper.dispatchAll(); + // Chip didn't support bridged mode, so extra saveToStore for update to default band. + verify(mWifiConfigManager, times(2)).saveToStore(true); + // Verify it changes to default band. + verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID, false, true, false); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java index c500a4243e..481c8a5a4c 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java @@ -257,6 +257,7 @@ public class WifiBackupRestoreTest extends WifiBaseTest { + "<int name=\"DeletionPriority\" value=\"0\" />\n" + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + "<boolean name=\"RepeaterEnabled\" value=\"false\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"true\" />\n" + "<SecurityParamsList>\n" + "<SecurityParams>\n" + "<int name=\"SecurityType\" value=\"2\" />\n" @@ -267,6 +268,7 @@ public class WifiBackupRestoreTest extends WifiBaseTest { + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + "</SecurityParams>\n" + "</SecurityParamsList>\n" + + "<boolean name=\"SendDhcpHostname\" value=\"true\" />\n" + "<int name=\"MeteredOverride\" value=\"1\" />\n" + "</WifiConfiguration>\n" + "<IpConfiguration>\n" @@ -277,6 +279,58 @@ public class WifiBackupRestoreTest extends WifiBaseTest { + "</NetworkList>\n" + "</WifiBackupData>\n"; + private static final String WIFI_BACKUP_DATA_V1_4 = + "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + + "<WifiBackupData>\n" + + "<float name=\"Version\" value=\"1.4\" />\n" + + "<NetworkList>\n" + + "<Network>\n" + + "<WifiConfiguration>\n" + + "<string name=\"ConfigKey\">"" + + WifiConfigurationTestUtil.TEST_SSID + + ""WPA_PSK</string>\n" + + "<string name=\"SSID\">"" + + WifiConfigurationTestUtil.TEST_SSID + + ""</string>\n" + + "<null name=\"PreSharedKey\" />\n" + + "<null name=\"WEPKeys\" />\n" + + "<int name=\"WEPTxKeyIndex\" value=\"0\" />\n" + + "<boolean name=\"HiddenSSID\" value=\"false\" />\n" + + "<boolean name=\"RequirePMF\" value=\"false\" />\n" + + "<byte-array name=\"AllowedKeyMgmt\" num=\"1\">02</byte-array>\n" + + "<byte-array name=\"AllowedProtocols\" num=\"1\">03</byte-array>\n" + + "<byte-array name=\"AllowedAuthAlgos\" num=\"0\"></byte-array>\n" + + "<byte-array name=\"AllowedGroupCiphers\" num=\"1\">0f</byte-array>\n" + + "<byte-array name=\"AllowedPairwiseCiphers\" num=\"1\">06</byte-array>\n" + + "<byte-array name=\"AllowedGroupMgmtCiphers\" num=\"0\"></byte-array>\n" + + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + + "<boolean name=\"Shared\" value=\"true\" />\n" + + "<boolean name=\"AutoJoinEnabled\" value=\"false\" />\n" + + "<int name=\"Priority\" value=\"0\" />\n" + + "<int name=\"DeletionPriority\" value=\"0\" />\n" + + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + + "<boolean name=\"RepeaterEnabled\" value=\"true\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"false\" />\n" + + "<SecurityParamsList>\n" + + "<SecurityParams>\n" + + "<int name=\"SecurityType\" value=\"2\" />\n" + + "<boolean name=\"IsEnabled\" value=\"true\" />\n" + + "<boolean name=\"SaeIsH2eOnlyMode\" value=\"false\" />\n" + + "<boolean name=\"SaeIsPkOnlyMode\" value=\"false\" />\n" + + "<boolean name=\"IsAddedByAutoUpgrade\" value=\"false\" />\n" + + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + + "</SecurityParams>\n" + + "</SecurityParamsList>\n" + + "<boolean name=\"SendDhcpHostname\" value=\"false\" />\n" + + "<int name=\"MeteredOverride\" value=\"1\" />\n" + + "</WifiConfiguration>\n" + + "<IpConfiguration>\n" + + "<string name=\"IpAssignment\">DHCP</string>\n" + + "<string name=\"ProxySettings\">NONE</string>\n" + + "</IpConfiguration>\n" + + "</Network>\n" + + "</NetworkList>\n" + + "</WifiBackupData>\n"; @Mock WifiPermissionsUtil mWifiPermissionsUtil; private WifiBackupRestore mWifiBackupRestore; private boolean mCheckDump = true; @@ -1151,11 +1205,27 @@ public class WifiBackupRestoreTest extends WifiBaseTest { WifiConfigurationTestUtil.assertConfigurationsEqualForBackup( configurations, retrievedConfigurations); + } + + /** + * Verify that restoring of configuration from a 1.4 version backup data. + */ + @Test + public void testRestoreFromV1_4BackupData() { + List<WifiConfiguration> configurations = new ArrayList<>(); + configurations.add(createNetworkForConfigurationWithV1_4Data()); + + byte[] backupData = WIFI_BACKUP_DATA_V1_4.getBytes(); + List<WifiConfiguration> retrievedConfigurations = + mWifiBackupRestore.retrieveConfigurationsFromBackupData(backupData); + + WifiConfigurationTestUtil.assertConfigurationsEqualForBackup( + configurations, retrievedConfigurations); // Also, assert in the reverse direction to ensure the serialization logic matches. // Note: This will stop working when we bump up the version. Then we'll need to copy // the below assert to the test for the latest version. - assertEquals(WIFI_BACKUP_DATA_V1_3, + assertEquals(WIFI_BACKUP_DATA_V1_4, new String(mWifiBackupRestore.retrieveBackupDataFromConfigurations( retrievedConfigurations))); } @@ -1222,6 +1292,19 @@ public class WifiBackupRestoreTest extends WifiBaseTest { } /** + * Creates correct WiFiConfiguration that should be parsed out of + * {@link #WIFI_BACKUP_DATA_V1_4} configuration which contains 1.4 version backup. + */ + private static WifiConfiguration createNetworkForConfigurationWithV1_4Data() { + final WifiConfiguration config = createNetworkForConfigurationWithV1_3Data(); + // Use non-default value for testing. + config.setRepeaterEnabled(true); + config.setWifi7Enabled(false); + config.setSendDhcpHostnameEnabled(false); + return config; + } + + /** * Helper method to write a list of networks in wpa_supplicant.conf format to the output stream. */ private byte[] createWpaSupplicantConfBackupData(List<WifiConfiguration> configurations) { diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java index c44bcad857..f4efd0a4e2 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java @@ -80,6 +80,8 @@ public class WifiBlocklistMonitorTest extends WifiBaseTest { private static final int TEST_DHCP_FAILURE = WifiBlocklistMonitor.REASON_DHCP_FAILURE; private static final long TEST_MAX_DISABLE_DURATION_MILLIS = TimeUnit.HOURS.toMillis(18); // 18 hours + private static final long TEST_SHORT_MAX_DISABLE_DURATION_MILLIS = + TimeUnit.SECONDS.toMillis(10); // 10 seconds private static final long BASE_BLOCKLIST_DURATION = TimeUnit.MINUTES.toMillis(5); // 5 minutes private static final long BASE_CONNECTED_SCORE_BLOCKLIST_DURATION = TimeUnit.SECONDS.toMillis(30); @@ -88,6 +90,7 @@ public class WifiBlocklistMonitorTest extends WifiBaseTest { private static final long ABNORMAL_DISCONNECT_TIME_WINDOW_MS = TimeUnit.SECONDS.toMillis(30); private static final long ABNORMAL_DISCONNECT_RESET_TIME_MS = TimeUnit.HOURS.toMillis(3); private static final int FAILURE_STREAK_CAP = 7; + private static final int FAILURE_STREAK_CAP_LONG = 20; private static final Map<Integer, Integer> BLOCK_REASON_TO_DISABLE_THRESHOLD_MAP = Map.ofEntries( Map.entry(WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA, 1), @@ -440,7 +443,7 @@ public class WifiBlocklistMonitorTest extends WifiBaseTest { * streak), we are setting the blocklist duration using an exponential backoff technique. */ @Test - public void testBssidIsRemoveFromBlocklistAfterTimoutExponentialBackoff() { + public void testBssidIsRemoveFromBlocklistAfterTimeoutExponentialBackoff() { verifyAddTestBssidToBlocklist(); int multiplier = 2; long duration = 0; @@ -461,7 +464,7 @@ public class WifiBlocklistMonitorTest extends WifiBaseTest { multiplier *= 2; } - // finally verify that the timout is capped by the FAILURE_STREAK_CAP + // finally verify that the timeout is capped by the FAILURE_STREAK_CAP when(mWifiScoreCard.getBssidBlocklistStreak(anyString(), anyString(), anyInt())) .thenReturn(FAILURE_STREAK_CAP + 1); when(mClock.getWallClockMillis()).thenReturn(0L); @@ -473,6 +476,26 @@ public class WifiBlocklistMonitorTest extends WifiBaseTest { } /** + * Verify that when adding a AP that had already been failing (therefore has a blocklist + * streak), we are setting the blocklist duration using an exponential backoff technique, + * and the disable duration for a network is capped at WifiConfigMaxDisableDurationMs. + */ + @Test + public void testBssidIsRemoveFromBlocklistAfterTimeoutExponentialBackoffCapped() { + mResources.setInteger(R.integer.config_wifiBssidBlocklistMonitorFailureStreakCap, + FAILURE_STREAK_CAP_LONG); + when(mWifiScoreCard.getBssidBlocklistStreak(anyString(), anyString(), anyInt())) + .thenReturn(FAILURE_STREAK_CAP_LONG); + // verify that the timeout is capped at WifiConfigMaxDisableDurationMs + when(mClock.getWallClockMillis()).thenReturn(0L); + verifyAddTestBssidToBlocklist(); + when(mClock.getWallClockMillis()).thenReturn(TEST_MAX_DISABLE_DURATION_MILLIS); + assertTrue(mWifiBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); + when(mClock.getWallClockMillis()).thenReturn(TEST_MAX_DISABLE_DURATION_MILLIS + 1); + assertEquals(0, mWifiBlocklistMonitor.updateAndGetBssidBlocklist().size()); + } + + /** * Verify that consecutive failures will add a BSSID to blocklist. */ @Test @@ -1622,6 +1645,24 @@ public class WifiBlocklistMonitorTest extends WifiBaseTest { } /** + * Verify the disable duration for a network is capped at + * a short WifiConfigMaxDisableDurationMs. + */ + @Test + public void testTryEnableNetworkCappedByShortMaxDisableDuration() { + WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); + int disableReason = NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION; + when(mWifiGlobals.getWifiConfigMaxDisableDurationMs()) + .thenReturn(TEST_SHORT_MAX_DISABLE_DURATION_MILLIS); + verifyDisableNetwork(openNetwork, disableReason); + + // verify the exponential backoff is capped at WifiConfigMaxDisableDurationMs + verifyNetworkIsEnabledAfter(openNetwork, + TEST_ELAPSED_UPDATE_NETWORK_SELECTION_TIME_MILLIS + + TEST_SHORT_MAX_DISABLE_DURATION_MILLIS); + } + + /** * Verifies that a network is disabled for the base duration even when there are no BSSIDs * blocked. */ diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiCarrierInfoManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiCarrierInfoManagerTest.java index 24c5898a40..3fd252d03e 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiCarrierInfoManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiCarrierInfoManagerTest.java @@ -28,6 +28,8 @@ import static com.android.server.wifi.WifiCarrierInfoManager.NOTIFICATION_USER_C import static com.android.server.wifi.WifiCarrierInfoManager.NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION; import static com.android.server.wifi.WifiCarrierInfoManager.NOTIFICATION_USER_DISMISSED_INTENT_ACTION; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -110,6 +112,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; import javax.crypto.BadPaddingException; @@ -156,6 +159,9 @@ public class WifiCarrierInfoManagerTest extends WifiBaseTest { @Mock SubscriptionInfo mNonDataSubscriptionInfo; @Mock WifiConfigStore mWifiConfigStore; @Mock WifiInjector mWifiInjector; + @Mock WifiNetworkFactory mWifiNetworkFactory; + @Mock UntrustedWifiNetworkFactory mUntrustedWifiNetworkFactory; + @Mock RestrictedWifiNetworkFactory mRestrictedWifiNetworkFactory; @Mock WifiConfigManager mWifiConfigManager; @Mock WifiCarrierInfoStoreManagerData mWifiCarrierInfoStoreManagerData; @@ -224,6 +230,11 @@ public class WifiCarrierInfoManagerTest extends WifiBaseTest { when(mWifiInjector.getWifiNetworkSuggestionsManager()) .thenReturn(mWifiNetworkSuggestionsManager); when(mWifiInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); + when(mWifiInjector.getWifiNetworkFactory()).thenReturn(mWifiNetworkFactory); + when(mWifiInjector.getUntrustedWifiNetworkFactory()) + .thenReturn(mUntrustedWifiNetworkFactory); + when(mWifiInjector.getRestrictedWifiNetworkFactory()) + .thenReturn(mRestrictedWifiNetworkFactory); when(mContext.getStringResourceWrapper(anyInt(), anyInt())) .thenReturn(mWifiStringResourceWrapper); mWifiCarrierInfoManager = new WifiCarrierInfoManager(mTelephonyManager, @@ -2496,4 +2507,28 @@ public class WifiCarrierInfoManagerTest extends WifiBaseTest { assertTrue(mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(1)); } + + @Test + public void testActiveSubsChangeUpdateWifiNetworkFactory() { + SubscriptionInfo subInfo1 = mock(SubscriptionInfo.class); + when(subInfo1.getSubscriptionId()).thenReturn(DATA_SUBID); + SubscriptionInfo subInfo2 = mock(SubscriptionInfo.class); + when(subInfo2.getSubscriptionId()).thenReturn(NON_DATA_SUBID); + when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()) + .thenReturn(Arrays.asList(subInfo1, subInfo2)); + mListenerArgumentCaptor.getValue().onSubscriptionsChanged(); + mLooper.dispatchAll(); + ArgumentCaptor<Set<Integer>> restrictedWifiCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor<Set<Integer>> untrustedWifiCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor<Set<Integer>> wifiCaptor = ArgumentCaptor.forClass(Set.class); + verify(mRestrictedWifiNetworkFactory, times(2)).updateSubIdsInCapabilitiesFilter( + restrictedWifiCaptor.capture()); + assertThat(restrictedWifiCaptor.getValue()).containsExactly(DATA_SUBID, NON_DATA_SUBID); + verify(mUntrustedWifiNetworkFactory, times(2)).updateSubIdsInCapabilitiesFilter( + untrustedWifiCaptor.capture()); + assertThat(restrictedWifiCaptor.getValue()).containsExactly(DATA_SUBID, NON_DATA_SUBID); + verify(mWifiNetworkFactory, times(2)).updateSubIdsInCapabilitiesFilter( + wifiCaptor.capture()); + assertThat(wifiCaptor.getValue()).containsExactly(DATA_SUBID, NON_DATA_SUBID); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java index 84e12e6018..7d12e157b0 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java @@ -63,6 +63,7 @@ import android.content.pm.PackageManager; import android.net.DhcpOption; import android.net.IpConfiguration; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.SecurityParams; import android.net.wifi.WifiConfiguration; @@ -319,6 +320,8 @@ public class WifiConfigManagerTest extends WifiBaseTest { when(mWifiPermissionsUtil.isProfileOwner(anyInt(), any())).thenReturn(false); when(mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(anyInt())) .thenReturn(true); + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(false); when(mWifiPermissionsUtil.isDeviceInDemoMode(any())).thenReturn(false); when(mWifiPermissionsUtil.isSystem(any(), anyInt())).thenReturn(true); when(mWifiLastResortWatchdog.shouldIgnoreSsidUpdate()).thenReturn(false); @@ -1291,6 +1294,29 @@ public class WifiConfigManagerTest extends WifiBaseTest { } /** + * Test that configs containing vendor data can only be added/updated if the + * caller has the proper permissions. + */ + @Test + public void testAddNetworkWithVendorDataPermissionCheck() { + assumeTrue(SdkLevel.isAtLeastV()); + WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork(); + configuration.setVendorData(Arrays.asList(mock(OuiKeyedData.class))); + + // Expect failure if the caller does not have the permission. + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(false); + NetworkUpdateResult result = addNetworkToWifiConfigManager(configuration, + configuration.creatorUid); + assertEquals(WifiConfiguration.INVALID_NETWORK_ID, result.getNetworkId()); + + // Expect success if the caller has the permission. + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(true); + verifyAddNetworkToWifiConfigManager(configuration); + } + + /** * Verifies that the modification of a single open network using * {@link WifiConfigManager#addOrUpdateNetwork(WifiConfiguration, int)} with the creator UID * should always succeed. @@ -1818,7 +1844,8 @@ public class WifiConfigManagerTest extends WifiBaseTest { NetworkUpdateResult result = verifyAddNetworkToWifiConfigManager(openNetwork); mWifiConfigManager - .updateBeforeConnect(result.getNetworkId(), TEST_CREATOR_UID, TEST_PACKAGE_NAME); + .updateBeforeConnect(result.getNetworkId(), TEST_CREATOR_UID, TEST_PACKAGE_NAME, + true); WifiConfiguration retrievedNetwork = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()); @@ -6657,7 +6684,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { .thenReturn(true); mWifiConfigManager.updateBeforeConnect(config.networkId, TEST_CREATOR_UID, - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, true); config = mWifiConfigManager.getConfiguredNetwork(config.networkId); // network became enabled @@ -6695,7 +6722,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { .thenReturn(false); mWifiConfigManager.updateBeforeConnect(config.networkId, TEST_CREATOR_UID, - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, true); config = mWifiConfigManager.getConfiguredNetwork(config.networkId); // network became enabled @@ -6730,7 +6757,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { when(mUserManager.isSameProfileGroup(any(), any())).thenReturn(false); mWifiConfigManager.updateBeforeConnect(config.networkId, TEST_OTHER_USER_UID, - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, true); // network still disabled assertFalse(config.getNetworkSelectionStatus().isNetworkEnabled()); @@ -8218,7 +8245,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(eapPeapNetId); assertFalse(config.enterpriseConfig.isTrustOnFirstUseEnabled()); assertFalse(config.enterpriseConfig.isUserApproveNoCaCert()); - assertEquals("", config.enterpriseConfig.getDomainSuffixMatch()); + assertEquals("mockServerCert", config.enterpriseConfig.getDomainSuffixMatch()); assertEquals("DNS:wifi.android;EMAIL:test@wifi.com;DNS:network.android;" + "URI:http://test.android.com", config.enterpriseConfig.getAltSubjectMatch()); @@ -8444,4 +8471,60 @@ public class WifiConfigManagerTest extends WifiBaseTest { // Verify operation still fails assertFalse(addNetworkToWifiConfigManager(config).isSuccess()); } + + /** + * Verify that the send DHCP hostname setting is correctly updated + */ + @Test + public void testAddNetworkUpdatesSendDhcpHostname() { + WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); + config.setSendDhcpHostnameEnabled(false); + + NetworkUpdateResult result = addNetworkToWifiConfigManager(config); + + assertTrue(result.isSuccess()); + config = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()); + assertFalse(config.isSendDhcpHostnameEnabled()); + + config.setSendDhcpHostnameEnabled(true); + result = updateNetworkToWifiConfigManager(config); + + assertTrue(result.isSuccess()); + config = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()); + assertTrue(config.isSendDhcpHostnameEnabled()); + } + + /** + * Verify that changing the DHCP hostname setting fails without NETWORK_SETTINGS or + * NETWORK_SETUP_WIZARD permissions. + */ + @Test + public void testUpdateSendDhcpHostnameFailsWithoutSettingsOrSuwPermission() { + when(mWifiPermissionsUtil.checkNetworkSettingsPermission(TEST_CREATOR_UID)) + .thenReturn(false); + when(mWifiPermissionsUtil.checkNetworkSetupWizardPermission(TEST_CREATOR_UID)) + .thenReturn(false); + when(mWifiPermissionsUtil.checkNetworkSettingsPermission(TEST_UPDATE_UID)) + .thenReturn(false); + when(mWifiPermissionsUtil.checkNetworkSetupWizardPermission(TEST_UPDATE_UID)) + .thenReturn(false); + WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); + + // Fail to add if dhcp hostname setting is set to DO_NOT_SEND + config.setSendDhcpHostnameEnabled(false); + NetworkUpdateResult result = addNetworkToWifiConfigManager(config); + assertFalse(result.isSuccess()); + + // Can add if dhcp hostname setting is reset to default SEND + config.setSendDhcpHostnameEnabled(true); + result = addNetworkToWifiConfigManager(config); + assertTrue(result.isSuccess()); + config = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()); + assertTrue(config.isSendDhcpHostnameEnabled()); + + // Fail to update if dchp hostname setting is set to DO_NOT_SEND + config.setSendDhcpHostnameEnabled(false); + result = updateNetworkToWifiConfigManager(config); + assertFalse(result.isSuccess()); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java index c7fa102633..dd930430fd 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java @@ -106,6 +106,7 @@ public class WifiConfigStoreTest extends WifiBaseTest { + "<int name=\"DeletionPriority\" value=\"0\" />\n" + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" + "<boolean name=\"RepeaterEnabled\" value=\"false\" />\n" + + "<boolean name=\"EnableWifi7\" value=\"true\" />\n" + "<SecurityParamsList>\n" + "<SecurityParams>\n" + "<int name=\"SecurityType\" value=\"0\" />\n" @@ -124,6 +125,7 @@ public class WifiConfigStoreTest extends WifiBaseTest { + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" + "</SecurityParams>\n" + "</SecurityParamsList>\n" + + "<boolean name=\"SendDhcpHostname\" value=\"true\" />\n" + "<boolean name=\"Trusted\" value=\"true\" />\n" + "<boolean name=\"IsRestricted\" value=\"false\" />\n" + "<boolean name=\"OemPaid\" value=\"false\" />\n" diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java index 42f9c6ae38..8d29edb679 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java @@ -77,6 +77,9 @@ public class WifiConfigurationTestUtil { public static final String[] TEST_WEP_KEYS = {"\"WifiTestWep12\"", "\"WifiTestWep34\"", "45342312ab", "45342312ab45342312ab34ac12"}; + public static final String[] TEST_WEP_KEYS_WITH_NULL = { + "\"WifiTestWep12\"", "\"WifiTestWep34\"", "45342312ab45342312ab34ac12", null + }; public static final String TEST_EAP_PASSWORD = "WifiConfigurationTestUtilEapPassword"; public static final int TEST_WEP_TX_KEY_INDEX = 1; public static final String TEST_FQDN = "WifiConfigurationTestUtilFQDN"; @@ -797,6 +800,9 @@ public class WifiConfigurationTestUtil { expected.getNetworkSelectionStatus(), actual.getNetworkSelectionStatus()); assertWifiEnterpriseConfigEqualForConfigStore( expected.enterpriseConfig, actual.enterpriseConfig); + if (SdkLevel.isAtLeastV()) { + assertEquals(expected.getVendorData(), actual.getVendorData()); + } } /** diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java index ece4ea1ebd..f2461fee37 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java @@ -503,9 +503,17 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { // This unfortunately needs to be a somewhat valid scan result, otherwise // |ScanDetailUtil.toScanDetail| raises exceptions. final ScanResult[] scanResults = new ScanResult[1]; - scanResults[0] = new ScanResult(WifiSsid.fromUtf8Text(CANDIDATE_SSID), - CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", - -78, 2450, 1025, 22, 33, 20, 0, 0, true); + scanResults[0] = new ScanResult.Builder( + WifiSsid.fromUtf8Text(CANDIDATE_SSID), CANDIDATE_BSSID) + .setHessid(1245) + .setCaps("some caps") + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); scanResults[0].informationElements = new InformationElement[1]; scanResults[0].informationElements[0] = new InformationElement(); scanResults[0].informationElements[0].id = InformationElement.EID_SSID; @@ -1341,9 +1349,16 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { when(candidate.isOemPrivate()).thenReturn(false); // Set up the scan candidates - ScanResult result = new ScanResult(WifiSsid.fromString(ssid), - ssid, bssid, 1245, 0, "some caps", rssi, frequency, - 1025, 22, 33, 20, 0, 0, true); + ScanResult result = new ScanResult.Builder(WifiSsid.fromString(ssid), bssid) + .setHessid(1245) + .setCaps("some caps") + .setRssi(rssi) + .setFrequency(frequency) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build(); ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(result); WifiCandidates.Key key = new WifiCandidates.Key(matchInfo, MacAddress.fromString(bssid), networkId, WifiConfiguration.SECURITY_TYPE_PSK); @@ -1408,10 +1423,17 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { private void setupMockPrimaryNetworkSelect(int networkId, String bssid, int rssi, int frequency) { WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId); - config.getNetworkSelectionStatus().setCandidate( - new ScanResult(WifiSsid.fromUtf8Text(config.SSID), - config.SSID, bssid, 1245, 0, "some caps", rssi, frequency, - 1025, 22, 33, 20, 0, 0, true)); + config.getNetworkSelectionStatus().setCandidate(new ScanResult.Builder( + WifiSsid.fromUtf8Text(config.SSID), bssid) + .setHessid(1245) + .setCaps("some caps") + .setRssi(rssi) + .setFrequency(frequency) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build()); // Selection for primary when(mWifiNS.selectNetwork(any())) .then(new AnswerWithArguments() { @@ -1443,11 +1465,18 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { // Will return the first candidate matching networkId if (networkId == candidate.getKey().networkId) { config.getNetworkSelectionStatus().setCandidate( - new ScanResult(WifiSsid.fromUtf8Text(config.SSID), - config.SSID, candidate.getKey().bssid - .toString(), 1245, 0, "some caps", rssi, - candidate.getFrequency(), 1025, 22, 33, - 20, 0, 0, true)); + new ScanResult.Builder( + WifiSsid.fromUtf8Text(config.SSID), + candidate.getKey().bssid.toString()) + .setHessid(1245) + .setCaps("some caps") + .setRssi(rssi) + .setFrequency(candidate.getFrequency()) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build()); return config; } } @@ -2666,10 +2695,18 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { List<ScanDetail> expectedOpenNetworks = new ArrayList<>(); expectedOpenNetworks.add( - new ScanDetail( - new ScanResult(WifiSsid.fromUtf8Text(CANDIDATE_SSID), - CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", -78, 2450, - 1025, 22, 33, 20, 0, 0, true))); + new ScanDetail(new ScanResult.Builder( + WifiSsid.fromUtf8Text(CANDIDATE_SSID), + CANDIDATE_BSSID) + .setHessid(1245) + .setCaps("some caps") + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build())); when(mWifiNS.getFilteredScanDetailsForOpenUnsavedNetworks()) .thenReturn(expectedOpenNetworks); @@ -2696,9 +2733,18 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { List<ScanDetail> expectedOpenNetworks = new ArrayList<>(); expectedOpenNetworks.add( new ScanDetail( - new ScanResult(WifiSsid.fromUtf8Text(CANDIDATE_SSID), - CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", -78, 2450, - 1025, 22, 33, 20, 0, 0, true))); + new ScanResult.Builder( + WifiSsid.fromUtf8Text(CANDIDATE_SSID), + CANDIDATE_BSSID) + .setHessid(1245) + .setCaps("some caps") + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setIs80211McRTTResponder(true) + .build())); when(mWifiNS.getFilteredScanDetailsForOpenUnsavedNetworks()) .thenReturn(expectedOpenNetworks); @@ -2959,8 +3005,8 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { // The actual interval should be same as scheduled. final long delta = Math.abs(expectedInterval * 1000L - intervals.get(0)); - assertTrue("Interval " + " (" + delta + ") not in 1ms error margin", - delta < 2); + assertTrue("Interval " + " (" + delta + ") not in 2ms error margin", + delta <= 2); } /** @@ -4730,9 +4776,8 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null, WifiConfigurationTestUtil.SECURITY_NONE); candidate.BSSID = CANDIDATE_BSSID; // config specified - ScanResult candidateScanResult = new ScanResult(); - candidateScanResult.SSID = CANDIDATE_SSID; - candidateScanResult.BSSID = CANDIDATE_BSSID; + ScanResult candidateScanResult = new ScanResult.Builder( + WifiSsid.fromUtf8Text(CANDIDATE_SSID), CANDIDATE_BSSID).build(); candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); when(mWifiNS.selectNetwork(any())).thenReturn(candidate); @@ -4788,9 +4833,8 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null, WifiConfigurationTestUtil.SECURITY_NONE); candidate.BSSID = CANDIDATE_BSSID; // config specified - ScanResult candidateScanResult = new ScanResult(); - candidateScanResult.SSID = CANDIDATE_SSID; - candidateScanResult.BSSID = CANDIDATE_BSSID; + ScanResult candidateScanResult = new ScanResult.Builder( + WifiSsid.fromUtf8Text(CANDIDATE_SSID), CANDIDATE_BSSID).build(); candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); when(mWifiNS.selectNetwork(any())).thenReturn(candidate); @@ -4867,10 +4911,9 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null, WifiConfigurationTestUtil.SECURITY_NONE); candidate.BSSID = CANDIDATE_BSSID; // config specified - ScanResult candidateScanResult = new ScanResult(); - candidateScanResult.SSID = CANDIDATE_SSID; // Set up the scan result BSSID to be different from the config specified one. - candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID; + ScanResult candidateScanResult = new ScanResult.Builder( + WifiSsid.fromUtf8Text(CANDIDATE_SSID), INVALID_SCAN_RESULT_BSSID).build(); candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); when(mWifiNS.selectNetwork(any())).thenReturn(candidate); @@ -4908,10 +4951,9 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { TEST_CONNECTED_NETWORK_ID, 0, CANDIDATE_SSID, false, true, null, null, WifiConfigurationTestUtil.SECURITY_NONE); candidate.BSSID = CANDIDATE_BSSID; // config specified - ScanResult candidateScanResult = new ScanResult(); - candidateScanResult.SSID = CANDIDATE_SSID; // Set up the scan result BSSID to be different from the config specified one. - candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID; + ScanResult candidateScanResult = new ScanResult.Builder( + WifiSsid.fromUtf8Text(CANDIDATE_SSID), INVALID_SCAN_RESULT_BSSID).build(); candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); when(mWifiNS.selectNetwork(any())).thenReturn(candidate); @@ -6060,12 +6102,13 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { mLooper.dispatchAll(); List<WifiNetworkSelector.ClientModeManagerState> expectedCmmStates = Arrays.asList(new WifiNetworkSelector.ClientModeManagerState( - "wlan0", false, true, wifiInfo1, false), + "wlan0", false, true, wifiInfo1, false, ROLE_CLIENT_PRIMARY), new WifiNetworkSelector.ClientModeManagerState( - "wlan1", false, true, wifiInfo2, false)); + "wlan1", false, true, wifiInfo2, false, + ROLE_CLIENT_SECONDARY_LONG_LIVED)); verify(mWifiNS).getCandidatesFromScan(any(), any(), eq(expectedCmmStates), anyBoolean(), anyBoolean(), anyBoolean(), any(), - anyBoolean()); + eq(false)); } @Test @@ -6095,14 +6138,42 @@ public class WifiConnectivityManagerTest extends WifiBaseTest { primaryCmm, WifiConnectivityManager.WIFI_STATE_DISCONNECTED); mLooper.dispatchAll(); - List<WifiNetworkSelector.ClientModeManagerState> expectedCmmStates = - Arrays.asList(new WifiNetworkSelector.ClientModeManagerState( - "wlan0", false, true, wifiInfo1, false), - new WifiNetworkSelector.ClientModeManagerState( - "unknown", false, true, new WifiInfo(), false)); verify(mWifiNS).getCandidatesFromScan(any(), any(), - eq(expectedCmmStates), anyBoolean(), anyBoolean(), anyBoolean(), any(), - anyBoolean()); + any(), anyBoolean(), anyBoolean(), anyBoolean(), any(), + eq(true)); + } + + @Test + public void testMbbAvailableWillSkipSufficiencyCheck() { + // Set screen to on + setScreenState(true); + // set OEM paid connection allowed. + WorkSource oemPaidWs = new WorkSource(); + mWifiConnectivityManager.setOemPaidConnectionAllowed(true, oemPaidWs); + + ConcreteClientModeManager primaryCmm = mock(ConcreteClientModeManager.class); + WifiInfo wifiInfo1 = mock(WifiInfo.class); + when(primaryCmm.getInterfaceName()).thenReturn("wlan0"); + when(primaryCmm.getRole()).thenReturn(ROLE_CLIENT_PRIMARY); + when(primaryCmm.isConnected()).thenReturn(false); + when(primaryCmm.isDisconnected()).thenReturn(true); + when(primaryCmm.getConnectionInfo()).thenReturn(wifiInfo1); + + when(mActiveModeWarden.getInternetConnectivityClientModeManagers()) + .thenReturn(Arrays.asList(primaryCmm)); + // Second STA creation is allowed. + when(mActiveModeWarden.canRequestMoreClientModeManagersInRole( + eq(ActiveModeWarden.INTERNAL_REQUESTOR_WS), eq(ROLE_CLIENT_SECONDARY_TRANSIENT), + eq(false))).thenReturn(true); + + // Set WiFi to disconnected state to trigger scan + mWifiConnectivityManager.handleConnectionStateChanged( + primaryCmm, + WifiConnectivityManager.WIFI_STATE_DISCONNECTED); + mLooper.dispatchAll(); + verify(mWifiNS).getCandidatesFromScan(any(), any(), + any(), anyBoolean(), anyBoolean(), anyBoolean(), any(), + eq(true)); } /** diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java index 5212b0ffd1..e9ba8d3b68 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java @@ -41,6 +41,7 @@ import static org.mockito.Mockito.when; import android.app.test.MockAnswerUtil.AnswerWithArguments; import android.content.Context; +import android.content.pm.PackageManager; import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -79,6 +80,9 @@ import java.util.Locale; public class WifiCountryCodeTest extends WifiBaseTest { private static final String TAG = "WifiCountryCodeTest"; + /* TODO: replace with PackageManager.FEATURE_TELEPHONY_CALLING once + * wifi-module-sdk-version-defaults min_sdk_version bumps to API 33. */ + private static final String FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling"; private static final String TEST_COUNTRY_CODE = "JP"; private static final String TEST_COUNTRY_CODE_2 = "CN"; private static final int TEST_ACTIVE_SUBSCRIPTION_ID = 1; @@ -92,9 +96,11 @@ public class WifiCountryCodeTest extends WifiBaseTest { // Default assume true since it was a design before R private boolean mDriverSupportedNl80211RegChangedEvent = false; private boolean mForcedSoftApRestateWhenCountryCodeChanged = false; + private boolean mCallingSupported; @Mock Context mContext; MockResources mResources = new MockResources(); @Mock TelephonyManager mTelephonyManager; + @Mock PackageManager mPackageManager; @Mock ActiveModeWarden mActiveModeWarden; @Mock ConcreteClientModeManager mClientModeManager; @Mock SoftApManager mSoftApManager; @@ -153,6 +159,9 @@ public class WifiCountryCodeTest extends WifiBaseTest { when(mWifiInfo.getSuccessfulRxPacketsPerSecond()).thenReturn(5.0); when(mContext.getSystemService(Context.TELEPHONY_SERVICE)) .thenReturn(mTelephonyManager); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + + setCallingSupported(true); doAnswer(new AnswerWithArguments() { public void answer(WifiSettingsConfigStore.Key<String> key, Object countryCode) { @@ -180,6 +189,11 @@ public class WifiCountryCodeTest extends WifiBaseTest { mScanDetails = setupScanDetails(TEST_COUNTRY_CODE); } + private void setCallingSupported(boolean supported) { + mCallingSupported = supported; + when(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY_CALLING)).thenReturn(supported); + } + @After public void cleanUp() throws Exception { mStaticMockSession.finishMocking(); @@ -293,7 +307,7 @@ public class WifiCountryCodeTest extends WifiBaseTest { // Wifi get L2 connected. mClientModeImplListenerCaptor.getValue().onConnectionStart(mClientModeManager); - verify(mClientModeManager, times(3)).setCountryCode(anyString()); + verify(mClientModeManager, times(2)).setCountryCode(anyString()); assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentDriverCountryCode()); } @@ -318,15 +332,16 @@ public class WifiCountryCodeTest extends WifiBaseTest { // Wifi get L2 connected. mClientModeImplListenerCaptor.getValue().onConnectionStart(mClientModeManager); - verify(mClientModeManager, times(3)).setCountryCode(anyString()); + // Set twice, one is mDefaultCountryCode and another on is mTelephonyCountryCode + verify(mClientModeManager, times(2)).setCountryCode(anyString()); assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentDriverCountryCode()); // Remove mode manager. mModeChangeCallbackCaptor.getValue().onActiveModeManagerRemoved(mClientModeManager); - // Send Telephony country code again - should be ignored. + // Send Telephony country code again - should be ignored, times keep 2. mWifiCountryCode.setTelephonyCountryCodeAndUpdate(mTelephonyCountryCode); - verify(mClientModeManager, times(3)).setCountryCode(anyString()); + verify(mClientModeManager, times(2)).setCountryCode(anyString()); assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCode()); // Now try removing the mode manager again - should not crash. @@ -375,8 +390,10 @@ public class WifiCountryCodeTest extends WifiBaseTest { } // Telephony country code still won't be applied. assertEquals("00", mWifiCountryCode.getCurrentDriverCountryCode()); - // Wifi is forced to disconnect - verify(mClientModeManager, times(1)).disconnect(); + if (mCallingSupported) { + // Wifi is forced to disconnect + verify(mClientModeManager, times(1)).disconnect(); + } mClientModeImplListenerCaptor.getValue().onConnectionEnd(mClientModeManager); // Telephony country is applied after supplicant is ready. @@ -384,6 +401,12 @@ public class WifiCountryCodeTest extends WifiBaseTest { assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentDriverCountryCode()); } + @Test + public void telephonyCountryCodeChangeAfterL2ConnectedWithoutCalling() throws Exception { + setCallingSupported(false); + telephonyCountryCodeChangeAfterL2Connected(); + } + /** * Test if we receive country code from Telephony after we get L2 connected on 2 STA interfaces. * @throws Exception @@ -643,7 +666,8 @@ public class WifiCountryCodeTest extends WifiBaseTest { mModeChangeCallbackCaptor.getValue().onActiveModeManagerAdded(mClientModeManager); // Verify the SoftApManager doesn't impact when client mode changed verify(mSoftApManager, never()).updateCountryCode(anyString()); - verify(mClientModeManager, times(2)).setCountryCode(anyString()); + // The mode change should not set country code again + verify(mClientModeManager).setCountryCode(anyString()); // Override the mClientModeManager.setCountryCode mock in setUp, do not update driver // country code, so both client mode manager and ap mode manager will update country code. diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java index bf347639f7..257e7b9e70 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java @@ -60,6 +60,7 @@ import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -82,6 +83,9 @@ public class WifiDialogManagerTest extends WifiBaseTest { @Mock FrameworkFacade mFrameworkFacade; @Mock Resources mResources; @Mock ActivityManager mActivityManager; + @Mock WifiInjector mWifiInjector; + @Mock WifiDeviceStateChangeManager mWifiDeviceStateChangeManager; + @Captor ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor; private WifiDialogManager mDialogManager; @Before @@ -90,11 +94,15 @@ public class WifiDialogManagerTest extends WifiBaseTest { when(mWifiContext.getWifiDialogApkPkgName()).thenReturn(WIFI_DIALOG_APK_PKG_NAME); when(mWifiContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager); when(mWifiContext.getResources()).thenReturn(mResources); + when(mWifiInjector.getWifiDeviceStateChangeManager()) + .thenReturn(mWifiDeviceStateChangeManager); doThrow(SecurityException.class).when(mWifiContext).startActivityAsUser(any(), any(), any()); - mDialogManager = - new WifiDialogManager(mWifiContext, mWifiThreadRunner, mFrameworkFacade); + mDialogManager = new WifiDialogManager(mWifiContext, mWifiThreadRunner, mFrameworkFacade, + mWifiInjector); mDialogManager.enableVerboseLogging(true); + verify(mWifiContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), + eq(SdkLevel.isAtLeastT() ? Context.RECEIVER_EXPORTED : 0)); } private void dispatchMockWifiThreadRunner(WifiThreadRunner wifiThreadRunner) { @@ -750,11 +758,7 @@ public class WifiDialogManagerTest extends WifiBaseTest { // ACTION_CLOSE_SYSTEM_DIALOGS with EXTRA_CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI should be // ignored. - ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass( - BroadcastReceiver.class); - verify(mWifiContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), - eq(SdkLevel.isAtLeastT() ? Context.RECEIVER_EXPORTED : 0)); - broadcastReceiverCaptor.getValue().onReceive(mWifiContext, + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mWifiContext, new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) .putExtra(WifiManager.EXTRA_CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI, true)); dispatchMockWifiThreadRunner(mWifiThreadRunner); @@ -762,7 +766,7 @@ public class WifiDialogManagerTest extends WifiBaseTest { verify(dialog, never()).cancel(); // ACTION_CLOSE_SYSTEM_DIALOGS without the extra should cancel the dialog. - broadcastReceiverCaptor + mBroadcastReceiverArgumentCaptor .getValue() .onReceive(mWifiContext, new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); dispatchMockWifiThreadRunner(mWifiThreadRunner); @@ -799,15 +803,13 @@ public class WifiDialogManagerTest extends WifiBaseTest { launchDialogSynchronous(dialogHandle, TIMEOUT_MILLIS, mWifiThreadRunner); verify(window).setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - // Receive ACTION_SCREEN_OFF. + // Receive screen off event. when(dialog.isShowing()).thenReturn(true); - ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass( - BroadcastReceiver.class); - verify(mWifiContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), - eq(SdkLevel.isAtLeastT() ? Context.RECEIVER_EXPORTED : 0)); - broadcastReceiverCaptor.getValue().onReceive(mWifiContext, - new Intent(Intent.ACTION_SCREEN_OFF)); - dispatchMockWifiThreadRunner(mWifiThreadRunner); + ArgumentCaptor<WifiDeviceStateChangeManager.StateChangeCallback> callbackArgumentCaptor = + ArgumentCaptor.forClass(WifiDeviceStateChangeManager.StateChangeCallback.class); + verify(mWifiDeviceStateChangeManager).registerStateChangeCallback( + callbackArgumentCaptor.capture()); + callbackArgumentCaptor.getValue().onScreenStateChanged(false); // Verify dialog was dismissed and relaunched with window type TYPE_APPLICATION_OVERLAY. verify(dialog, never()).cancel(); diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiGlobalsTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiGlobalsTest.java index 919a7a2940..3a29bbf1bc 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiGlobalsTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiGlobalsTest.java @@ -290,6 +290,17 @@ public class WifiGlobalsTest extends WifiBaseTest { assertFalse(mWifiGlobals.isWepAllowed()); } + + @Test + public void isSwPnoEnabled() { + mResources.setBoolean(R.bool.config_wifiSwPnoEnabled, true); + mWifiGlobals = new WifiGlobals(mContext); + assertTrue(mWifiGlobals.isSwPnoEnabled()); + mResources.setBoolean(R.bool.config_wifiSwPnoEnabled, false); + mWifiGlobals = new WifiGlobals(mContext); + assertFalse(mWifiGlobals.isSwPnoEnabled()); + } + /** * Verify Force Overlay Config Value */ @@ -340,4 +351,23 @@ public class WifiGlobalsTest extends WifiBaseTest { "true", true)); assertTrue(mWifiGlobals.isBackgroundScanSupported()); } + + @Test + public void testIsD2dSupportedWhenInfraStaDisabled() { + mResources.setBoolean(R.bool.config_wifiD2dAllowedControlSupportedWhenInfraStaDisabled, + false); + mWifiGlobals = new WifiGlobals(mContext); + mWifiGlobals.setD2dStaConcurrencySupported(true); + assertFalse(mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()); + mWifiGlobals.setD2dStaConcurrencySupported(false); + assertFalse(mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()); + + mResources.setBoolean(R.bool.config_wifiD2dAllowedControlSupportedWhenInfraStaDisabled, + true); + mWifiGlobals = new WifiGlobals(mContext); + mWifiGlobals.setD2dStaConcurrencySupported(true); + assertFalse(mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()); + mWifiGlobals.setD2dStaConcurrencySupported(false); + assertTrue(mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java index 4736dfbd32..f6192bd1c8 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java @@ -291,7 +291,7 @@ public class WifiMetricsTest extends WifiBaseTest { //Start and end Connection event mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE, WifiMetricsProto.ConnectionEvent.HLF_DHCP, @@ -306,10 +306,10 @@ public class WifiMetricsTest extends WifiBaseTest { //start two ConnectionEvents in a row mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "BLUE", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "GREEN", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); } private static final long TEST_RECORD_DURATION_SEC = 12 * 60 * 60; @@ -523,7 +523,6 @@ public class WifiMetricsTest extends WifiBaseTest { private static final long NUM_WATCHDOG_SUCCESS_DURATION_MS = 65; private static final long WIFI_POWER_METRICS_LOGGING_DURATION = 280; private static final long WIFI_POWER_METRICS_SCAN_TIME = 33; - private static final boolean WIFI_IS_UNUSABLE_EVENT_LOGGING_SETTING = true; private static final boolean LINK_SPEED_COUNTS_LOGGING_SETTING = true; private static final int DATA_STALL_MIN_TX_BAD_SETTING = 5; private static final int DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX_SETTING = 75; @@ -1088,8 +1087,6 @@ public class WifiMetricsTest extends WifiBaseTest { addWifiHealthMetrics(); - mResources.setBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled, - WIFI_IS_UNUSABLE_EVENT_LOGGING_SETTING); mResources.setBoolean(R.bool.config_wifiLinkSpeedMetricsEnabled, LINK_SPEED_COUNTS_LOGGING_SETTING); mResources.setInteger(R.integer.config_wifiDataStallMinTxBad, @@ -1596,8 +1593,6 @@ public class WifiMetricsTest extends WifiBaseTest { mDecodedProto.wifiRadioUsage.loggingDurationMs); assertEquals(WIFI_POWER_METRICS_SCAN_TIME, mDecodedProto.wifiRadioUsage.scanTimeMs); - assertEquals(WIFI_IS_UNUSABLE_EVENT_LOGGING_SETTING, - mDecodedProto.experimentValues.wifiIsUnusableLoggingEnabled); assertEquals(LINK_SPEED_COUNTS_LOGGING_SETTING, mDecodedProto.experimentValues.linkSpeedCountsLoggingEnabled); assertEquals(DATA_STALL_MIN_TX_BAD_SETTING, @@ -1873,7 +1868,7 @@ public class WifiMetricsTest extends WifiBaseTest { //Create a connection event using only the config mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "Red", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -1887,7 +1882,7 @@ public class WifiMetricsTest extends WifiBaseTest { //Create a connection event using the config and a scan detail mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "Green", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionScanDetail(TEST_IFACE_NAME, scanDetail); mWifiMetrics.logBugReport(); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, @@ -1975,7 +1970,7 @@ public class WifiMetricsTest extends WifiBaseTest { // Create a connection event using only the config mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "Red", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -1995,7 +1990,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testMetricsAssociationTimedOut() throws Exception { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2031,7 +2026,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2059,7 +2054,7 @@ public class WifiMetricsTest extends WifiBaseTest { when(securityParams.isEnterpriseSecurityType()).thenReturn(false); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2079,11 +2074,11 @@ public class WifiMetricsTest extends WifiBaseTest { WifiConfiguration config1 = WifiConfigurationTestUtil.createPskNetwork(); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config1, "RED", WifiMetricsProto.ConnectionEvent.ROAM_DBDC, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); WifiConfiguration config2 = WifiConfigurationTestUtil.createOpenNetwork(); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME2, config2, "BLUE", WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionScanDetail(TEST_IFACE_NAME, mock(ScanDetail.class)); mWifiMetrics.setConnectionPmkCache(TEST_IFACE_NAME, false); @@ -2135,11 +2130,11 @@ public class WifiMetricsTest extends WifiBaseTest { WifiConfiguration config1 = WifiConfigurationTestUtil.createPskNetwork(); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config1, "RED", WifiMetricsProto.ConnectionEvent.ROAM_DBDC, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); WifiConfiguration config2 = WifiConfigurationTestUtil.createOpenNetwork(); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME2, config2, "BLUE", WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionScanDetail(TEST_IFACE_NAME, mock(ScanDetail.class)); mWifiMetrics.setConnectionPmkCache(TEST_IFACE_NAME, false); @@ -2189,7 +2184,7 @@ public class WifiMetricsTest extends WifiBaseTest { WifiConfiguration config1 = WifiConfigurationTestUtil.createPskNetwork(); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config1, "RED", WifiMetricsProto.ConnectionEvent.ROAM_DBDC, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionScanDetail(TEST_IFACE_NAME, mock(ScanDetail.class)); mWifiMetrics.setConnectionPmkCache(TEST_IFACE_NAME, false); mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps(TEST_IFACE_NAME, 100, 50); @@ -2202,7 +2197,7 @@ public class WifiMetricsTest extends WifiBaseTest { WifiConfiguration config2 = WifiConfigurationTestUtil.createOpenNetwork(); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME2, config2, "BLUE", WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionScanDetail(TEST_IFACE_NAME2, mock(ScanDetail.class)); mWifiMetrics.setConnectionPmkCache(TEST_IFACE_NAME2, true); mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps(TEST_IFACE_NAME2, 400, 200); @@ -2240,6 +2235,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.setConnectionScanDetail("nonexistentIface", mock(ScanDetail.class)); mWifiMetrics.setConnectionPmkCache("nonexistentIface", false); mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps("nonexistentIface", 100, 50); + mWifiMetrics.setConnectionChannelWidth("nonexistentIface", ScanResult.CHANNEL_WIDTH_160MHZ); mWifiMetrics.endConnectionEvent("nonexistentIface", WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, WifiMetricsProto.ConnectionEvent.HLF_DHCP, @@ -2256,7 +2252,7 @@ public class WifiMetricsTest extends WifiBaseTest { config.carrierMerged = true; mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2289,7 +2285,7 @@ public class WifiMetricsTest extends WifiBaseTest { config.fromWifiNetworkSuggestion = false; mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2301,7 +2297,7 @@ public class WifiMetricsTest extends WifiBaseTest { config.carrierId = 123; mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2313,7 +2309,7 @@ public class WifiMetricsTest extends WifiBaseTest { config.carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2338,7 +2334,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testMetricsAuthenticationFailureReason() throws Exception { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2414,7 +2410,7 @@ public class WifiMetricsTest extends WifiBaseTest { // Create 3 ConnectionEvents mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2422,7 +2418,7 @@ public class WifiMetricsTest extends WifiBaseTest { TEST_CONNECTION_FAILURE_STATUS_CODE); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "YELLOW", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2430,7 +2426,7 @@ public class WifiMetricsTest extends WifiBaseTest { TEST_CONNECTION_FAILURE_STATUS_CODE); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "GREEN", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2438,7 +2434,7 @@ public class WifiMetricsTest extends WifiBaseTest { TEST_CONNECTION_FAILURE_STATUS_CODE); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "ORANGE", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2456,7 +2452,7 @@ public class WifiMetricsTest extends WifiBaseTest { // Create 2 ConnectionEvents mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "BLUE", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2464,7 +2460,7 @@ public class WifiMetricsTest extends WifiBaseTest { TEST_CONNECTION_FAILURE_STATUS_CODE); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2485,7 +2481,7 @@ public class WifiMetricsTest extends WifiBaseTest { // Start and end Connection event mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE, WifiMetricsProto.ConnectionEvent.HLF_DHCP, @@ -2504,7 +2500,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(true), eq(false), eq(1), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), anyInt(), anyInt(), anyInt(), - anyInt(), anyInt())); + anyInt(), anyInt(), eq(TEST_UID))); } /** @@ -2516,7 +2512,7 @@ public class WifiMetricsTest extends WifiBaseTest { // Create 2 complete ConnectionEvents and 1 ongoing un-ended ConnectionEvent mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2524,7 +2520,7 @@ public class WifiMetricsTest extends WifiBaseTest { TEST_CONNECTION_FAILURE_STATUS_CODE); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "YELLOW", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -2532,7 +2528,7 @@ public class WifiMetricsTest extends WifiBaseTest { TEST_CONNECTION_FAILURE_STATUS_CODE); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, null, "GREEN", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); // Dump proto and deserialize // This should clear the metrics in mWifiMetrics, @@ -3393,7 +3389,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.setNetworkSelectorExperimentId(id); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, mTestWifiConfig, "TestNetwork", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -3410,7 +3406,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testConnectionWithPmkCache() throws Exception { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, mTestWifiConfig, "TestNetwork", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionPmkCache(TEST_IFACE_NAME, true); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -3431,7 +3427,7 @@ public class WifiMetricsTest extends WifiBaseTest { .thenReturn(2); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, mTestWifiConfig, "TestNetwork", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps(TEST_IFACE_NAME, MAX_SUPPORTED_TX_LINK_SPEED_MBPS, MAX_SUPPORTED_RX_LINK_SPEED_MBPS); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, @@ -3515,7 +3511,7 @@ public class WifiMetricsTest extends WifiBaseTest { when(securityParams.isEnterpriseSecurityType()).thenReturn(true); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "TestNetwork", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); if (completeConnectionEvent) { if (successfulConnectionEvent) { mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, @@ -3716,22 +3712,10 @@ public class WifiMetricsTest extends WifiBaseTest { } /** - * Verify that no WifiIsUnusableEvent is generated when it is disabled in the settings - */ - @Test - public void testNoUnusableEventLogWhenDisabled() throws Exception { - mResources.setBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled, false); - generateAllUnusableEvents(mWifiMetrics); - dumpProtoAndDeserialize(); - assertEquals(0, mDecodedProto.wifiIsUnusableEventList.length); - } - - /** * Generate WifiIsUnusableEvent and verify that they are logged correctly */ @Test public void testUnusableEventLogSerializeDeserialize() throws Exception { - mResources.setBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled, true); generateAllUnusableEvents(mWifiMetrics); dumpProtoAndDeserialize(); verifyDeserializedUnusableEvents(mDecodedProto); @@ -3743,7 +3727,6 @@ public class WifiMetricsTest extends WifiBaseTest { */ @Test public void testWifiIsUnUsableReportedWithNoExternalScorer() throws Exception { - mResources.setBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled, true); generateAllUnusableEvents(mWifiMetrics); for (int i = 0; i < mTestUnusableEvents.length; i++) { int index = i; @@ -3759,7 +3742,6 @@ public class WifiMetricsTest extends WifiBaseTest { */ @Test public void testWifiIsUnUsableReportedWithExternalScorer() throws Exception { - mResources.setBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled, true); mWifiMetrics.setIsExternalWifiScorerOn(true, TEST_UID); mWifiMetrics.setScorerPredictedWifiUsabilityState(TEST_IFACE_NAME, WifiMetrics.WifiUsabilityState.USABLE); @@ -3777,7 +3759,6 @@ public class WifiMetricsTest extends WifiBaseTest { */ @Test public void testUnusableEventBounding() throws Exception { - mResources.setBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled, true); for (int i = 0; i < (WifiMetrics.MAX_UNUSABLE_EVENTS + 2); i++) { generateAllUnusableEvents(mWifiMetrics); } @@ -3791,7 +3772,6 @@ public class WifiMetricsTest extends WifiBaseTest { */ @Test public void testUnusableEventTimeThrottleForDataStall() throws Exception { - mResources.setBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled, true); generateUnusableEventAtGivenTime(0, 0); // should be time throttled generateUnusableEventAtGivenTime(1, 1); @@ -6270,12 +6250,12 @@ public class WifiMetricsTest extends WifiBaseTest { when(mClock.getElapsedSinceBootMillis()).thenReturn((long) 0); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, mTestWifiConfig, "TestNetwork", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); when(mClock.getElapsedSinceBootMillis()).thenReturn((long) 1000); // Connection event 2 overlaps with 1 assertEquals(1000, mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, mTestWifiConfig, "TestNetwork", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY)); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID)); // Connection event 2 ends mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, @@ -6287,7 +6267,7 @@ public class WifiMetricsTest extends WifiBaseTest { // Connection event 3 doesn't overlap with 2 assertEquals(0, mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, mTestWifiConfig, "TestNetwork", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY)); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID)); } @Test @@ -6317,7 +6297,7 @@ public class WifiMetricsTest extends WifiBaseTest { config.updateIdentifier = "7"; mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -6419,12 +6399,13 @@ public class WifiMetricsTest extends WifiBaseTest { public void testWifiConnectionResultAtomNotEmittedWithNoConnectionEndEvent() { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); ExtendedMockito.verify(() -> WifiStatsLog.write( eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED), anyBoolean(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyInt(), anyBoolean(), - anyBoolean(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt()), + anyBoolean(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), + eq(TEST_UID)), times(0)); } @@ -6439,7 +6420,8 @@ public class WifiMetricsTest extends WifiBaseTest { ExtendedMockito.verify(() -> WifiStatsLog.write( eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED), anyBoolean(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyInt(), anyBoolean(), - anyBoolean(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt()), + anyBoolean(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), + eq(TEST_UID)), times(0)); } @@ -6447,7 +6429,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testWifiConnectionResultAtomEmittedOnlyOnceWithMultipleConnectionEndEvents() { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); for (int i = 0; i < 5; i++) { mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, @@ -6466,7 +6448,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_BOOT), eq(true), eq(0), eq(true), eq(false), eq(1), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()), + anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(TEST_UID)), times(1)); } @@ -6481,11 +6463,11 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config1, "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config2, "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, true, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE, @@ -6502,7 +6484,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_BOOT), eq(true), eq(0), eq(true), eq(true), eq(1), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()), + anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(TEST_UID)), times(1)); } @@ -6510,7 +6492,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testWifiConnectionResultAtomHasCorrectTriggers() { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -6526,11 +6508,11 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_BOOT), anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), anyInt(), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), anyInt(), anyInt(), anyInt(), anyInt(), - anyInt())); + anyInt(), eq(TEST_UID))); mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -6546,7 +6528,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__RECONNECT_SAME_NETWORK), anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), anyInt(), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), anyInt(), anyInt(), anyInt(), anyInt(), - anyInt())); + anyInt(), eq(TEST_UID))); WifiConfiguration configOtherNetwork = createComplexWifiConfig(); configOtherNetwork.networkId = 21; @@ -6556,7 +6538,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, configOtherNetwork, "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -6572,7 +6554,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_CONFIGURED_NETWORK), anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), anyInt(), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), anyInt(), anyInt(), anyInt(), anyInt(), - anyInt())); + anyInt(), eq(TEST_UID))); WifiConfiguration config = createComplexWifiConfig(); config.networkId = 42; @@ -6581,7 +6563,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "GREEN", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -6595,14 +6577,14 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__MANUAL), anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), anyInt(), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), anyInt(), anyInt(), anyInt(), anyInt(), - anyInt())); + anyInt(), eq(TEST_UID))); } @Test public void testWifiDisconnectAtomEmittedOnDisconnectFromSuccessfulSession() { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); long connectionEndTimeMs = 1000; when(mClock.getElapsedSinceBootMillis()).thenReturn(connectionEndTimeMs); @@ -6637,7 +6619,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testWifiDisconnectAtomNotEmittedOnDisconnectFromNotConnectedSession() { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); long connectionEndTimeMs = 1000; when(mClock.getElapsedSinceBootMillis()).thenReturn(connectionEndTimeMs); @@ -6677,7 +6659,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testWifiStateChangedAtomEmittedOnSuccessfulConnectAndDisconnect() { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -6709,7 +6691,7 @@ public class WifiMetricsTest extends WifiBaseTest { public void testWifiStateChangedAtomNotEmittedOnNotSuccessfulConnectAndDisconnect() { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE, @@ -6728,12 +6710,12 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.reportNetworkDisconnect(TEST_IFACE_NAME, reason, TEST_CANDIDATE_LEVEL, linkSpeed, 0); - // But we still expect FALSE to be emitted + // FALSE should not be emitted since wifi was never connected ExtendedMockito.verify(() -> WifiStatsLog.write( - WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED, - false, - 0, - 0)); + eq(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED), + eq(false), + anyInt(), + anyInt()), times(0)); } @Test @@ -6742,7 +6724,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -6756,7 +6738,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_BOOT), anyBoolean(), eq(10), anyBoolean(), anyBoolean(), anyInt(), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), anyInt(), anyInt(), anyInt(), anyInt(), - anyInt())); + anyInt(), eq(TEST_UID))); mWifiMetrics.reportNetworkDisconnect(TEST_IFACE_NAME, 0, 0, 0, 0); @@ -6764,7 +6746,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, createComplexWifiConfig(), "RED", WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, @@ -6778,7 +6760,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__RECONNECT_SAME_NETWORK), anyBoolean(), eq(20), anyBoolean(), anyBoolean(), anyInt(), eq(TEST_CONNECTION_FAILURE_STATUS_CODE), anyInt(), anyInt(), anyInt(), anyInt(), - anyInt())); + anyInt(), eq(TEST_UID))); mWifiMetrics.reportNetworkDisconnect(TEST_IFACE_NAME, 0, 0, 0, 0); } @@ -7134,7 +7116,7 @@ public class WifiMetricsTest extends WifiBaseTest { mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "RED", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -7275,7 +7257,8 @@ public class WifiMetricsTest extends WifiBaseTest { when(networkDetail.isIndividualTwtSupported()).thenReturn(true); when(networkDetail.isTwtRequired()).thenReturn(true); when(networkDetail.isFilsCapable()).thenReturn(true); - when(networkDetail.is11azSupported()).thenReturn(true); + when(networkDetail.is80211azNtbResponder()).thenReturn(true); + when(networkDetail.is80211azTbResponder()).thenReturn(false); when(networkDetail.is80211McResponderSupport()).thenReturn(true); when(networkDetail.isEpcsPriorityAccessSupported()).thenReturn(true); when(networkDetail.getHSRelease()).thenReturn(NetworkDetail.HSRelease.Unknown); @@ -7291,11 +7274,12 @@ public class WifiMetricsTest extends WifiBaseTest { //Create a connection event using only the config mWifiMetrics.startConnectionEvent(TEST_IFACE_NAME, config, "Red", WifiMetricsProto.ConnectionEvent.ROAM_NONE, false, - WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY); + WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_PRIMARY, TEST_UID); mWifiMetrics.setConnectionScanDetail(TEST_IFACE_NAME, scanDetail); mWifiMetrics.logBugReport(); mWifiMetrics.logStaEvent(TEST_IFACE_NAME, StaEvent.TYPE_CMD_START_ROAM, StaEvent.DISCONNECT_UNKNOWN, null); + mWifiMetrics.setConnectionChannelWidth(TEST_IFACE_NAME, ScanResult.CHANNEL_WIDTH_160MHZ); mWifiMetrics.endConnectionEvent(TEST_IFACE_NAME, WifiMetrics.ConnectionEvent.FAILURE_NONE, WifiMetricsProto.ConnectionEvent.HLF_NONE, @@ -7329,6 +7313,7 @@ public class WifiMetricsTest extends WifiBaseTest { eq(WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__PASSPOINT_RELEASE__PASSPOINT_RELEASE_UNKNOWN), eq(false), // isPasspointHomeProvider eq(WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__AP_TYPE_6GHZ__AP_TYPE_6GHZ_STANDARD_POWER), - eq(true))); // mIsEcpsPriorityAccessSupported + eq(true), // mIsEcpsPriorityAccessSupported + eq(WifiStatsLog.WIFI_AP_CAPABILITIES_REPORTED__CHANNEL_WIDTH_MHZ__CHANNEL_WIDTH_160MHZ))); // mChannelWidth } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNativeInterfaceManagementTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNativeInterfaceManagementTest.java index 0d48157005..2481f066e6 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiNativeInterfaceManagementTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNativeInterfaceManagementTest.java @@ -16,8 +16,12 @@ package com.android.server.wifi; +import static com.android.server.wifi.p2p.WifiP2pNative.P2P_IFACE_NAME; +import static com.android.server.wifi.p2p.WifiP2pNative.P2P_INTERFACE_PROPERTY; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -53,6 +57,7 @@ import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener; import com.android.server.wifi.WifiNative.SupplicantDeathEventHandler; import com.android.server.wifi.WifiNative.VendorHalDeathEventHandler; +import com.android.server.wifi.p2p.WifiP2pNative; import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.NetdWrapper.NetdEventObserver; import com.android.wifi.resources.R; @@ -88,6 +93,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { private static final int SOFTAP_FAILURE_CODE_START_DAEMON = 2; private static final int SOFTAP_FAILURE_CODE_CREATE_IFACE = 3; private static final int SOFTAP_FAILURE_CODE_BRIDGED_AP_INSTANCES = 4; + private static final int P2P_FAILURE_CODE_CREATE_INTERFACE = 1; private static final int TEST_SUPPORTED_BANDS = 15; MockResources mResources; @@ -103,11 +109,15 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { @Mock BuildProperties mBuildProperties; @Mock private WifiInjector mWifiInjector; @Mock private WifiContext mContext; + @Mock private HalDeviceManager mHalDeviceManager; + @Mock private WifiP2pNative mWifiP2pNative; @Mock private WifiNative.StatusListener mStatusListener; @Mock private WifiNative.InterfaceCallback mIfaceCallback0; @Mock private WifiNative.InterfaceCallback mIfaceCallback1; @Mock private WifiNative.InterfaceEventCallback mIfaceEventCallback0; + @Mock private HalDeviceManager.InterfaceDestroyedListener mP2pInterfaceDestroyedListener; + @Mock private Handler mP2pEventHandler; @Mock private WifiSettingsConfigStore mWifiSettingsConfigStore; @Mock private WifiGlobals mWifiGlobals; @@ -116,6 +126,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { @Mock DeviceConfigFacade mDeviceConfigFacade; private TestLooper mLooper; + private WifiNative.Iface mActiveP2pIface; private ArgumentCaptor<VendorHalDeathEventHandler> mWifiVendorHalDeathHandlerCaptor = ArgumentCaptor.forClass(VendorHalDeathEventHandler.class); @@ -206,6 +217,8 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { when(mWifiInjector.getSettingsConfigStore()).thenReturn(mWifiSettingsConfigStore); when(mWifiInjector.getContext()).thenReturn(mContext); when(mWifiInjector.getWifiGlobals()).thenReturn(mWifiGlobals); + when(mWifiInjector.getHalDeviceManager()).thenReturn(mHalDeviceManager); + when(mWifiInjector.getWifiP2pNative()).thenReturn(mWifiP2pNative); mResources = getMockResources(); mResources.setBoolean(R.bool.config_wifiNetworkCentricQosPolicyFeatureEnabled, false); mResources.setString( @@ -223,7 +236,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal, mHostapdHal, mWifiMonitor, mNetdWrapper, mIfaceCallback0, mIfaceCallback1, mIfaceEventCallback0, - mWifiMetrics); + mWifiMetrics, mWifiP2pNative); mWifiNative = new WifiNative( mWifiVendorHal, mSupplicantStaIfaceHal, mHostapdHal, mWificondControl, @@ -237,6 +250,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mWificondDeathHandlerCaptor.capture()); mInOrder.verify(mWificondControl).tearDownInterfaces(); mInOrder.verify(mWifiVendorHal).registerRadioModeChangeHandler(any()); + mActiveP2pIface = null; } @After @@ -269,6 +283,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { @Test public void testSetupClientInterfaceWithQosPolicyFeatureEnabled() throws Exception { mResources.setBoolean(R.bool.config_wifiNetworkCentricQosPolicyFeatureEnabled, true); + when(mSupplicantStaIfaceHal.isAidlService()).thenReturn(true); when(mSupplicantStaIfaceHal .setNetworkCentricQosPolicyFeatureEnabled(anyString(), anyBoolean())) .thenReturn(true); @@ -276,6 +291,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0, mNetworkObserverCaptor0); assertEquals(Set.of(IFACE_NAME_0), mWifiNative.getClientInterfaceNames()); + verify(mSupplicantStaIfaceHal).isAidlService(); verify(mSupplicantStaIfaceHal) .setNetworkCentricQosPolicyFeatureEnabled(IFACE_NAME_0, true); } @@ -491,6 +507,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { verify(mNetdWrapper).unregisterObserver(mNetworkObserverCaptor1.getValue()); verify(mSupplicantStaIfaceHal).teardownIface(IFACE_NAME_1); verify(mWificondControl).tearDownClientInterface(IFACE_NAME_1); + verify(mSupplicantStaIfaceHal, atLeastOnce()).isInitializationStarted(); verify(mSupplicantStaIfaceHal).deregisterDeathHandler(); verify(mSupplicantStaIfaceHal).terminate(); verify(mIfaceCallback1).onDestroyed(IFACE_NAME_1); @@ -555,11 +572,14 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mWifiVendorHal).isVendorHalSupported(); mInOrder.verify(mWifiVendorHal).replaceStaIfaceRequestorWs(ifaceName, workSource); mInOrder.verify(mSupplicantStaIfaceHal).teardownIface(ifaceName); + mInOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted(); mInOrder.verify(mSupplicantStaIfaceHal).deregisterDeathHandler(); + mInOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted(); mInOrder.verify(mSupplicantStaIfaceHal).terminate(); mInOrder.verify(mSupplicantStaIfaceHal).getAdvancedCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getSupportedFeatureSet(ifaceName); mInOrder.verify(mSupplicantStaIfaceHal).getWpaDriverFeatureSet(ifaceName); + mInOrder.verify(mWifiVendorHal).getTwtCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getUsableChannels(anyInt(), anyInt(), anyInt()); } @@ -587,6 +607,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mSupplicantStaIfaceHal).getAdvancedCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getSupportedFeatureSet(ifaceName); mInOrder.verify(mSupplicantStaIfaceHal).getWpaDriverFeatureSet(ifaceName); + mInOrder.verify(mWifiVendorHal).getTwtCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getUsableChannels(anyInt(), anyInt(), anyInt()); mInOrder.verify(mWifiVendorHal).enableStaChannelForPeerNetwork(anyBoolean(), anyBoolean()); } @@ -599,6 +620,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mSupplicantStaIfaceHal).getAdvancedCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getSupportedFeatureSet(ifaceName); mInOrder.verify(mSupplicantStaIfaceHal).getWpaDriverFeatureSet(ifaceName); + mInOrder.verify(mWifiVendorHal).getTwtCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getUsableChannels(anyInt(), anyInt(), anyInt()); } @@ -1338,6 +1360,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { } mInOrder.verify(mSupplicantStaIfaceHal).isInitializationComplete(); mInOrder.verify(mSupplicantStaIfaceHal).registerDeathHandler(any()); + when(mSupplicantStaIfaceHal.isInitializationStarted()).thenReturn(true); } mInOrder.verify(mSupplicantStaIfaceHal).setupIface(ifaceName); if (failureCode == STA_FAILURE_CODE_SETUP_INTERFACE) { @@ -1348,6 +1371,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mSupplicantStaIfaceHal).getAdvancedCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getSupportedFeatureSet(ifaceName); mInOrder.verify(mSupplicantStaIfaceHal).getWpaDriverFeatureSet(ifaceName); + mInOrder.verify(mWifiVendorHal).getTwtCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getUsableChannels(anyInt(), anyInt(), anyInt()); } } @@ -1393,6 +1417,88 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { assertEquals(Set.of(IFACE_NAME_0, IFACE_NAME_1), mWifiNative.getClientInterfaceNames()); } + @Test + public void testSetupP2pInterfaceAndTeardownP2p() throws Exception { + executeAndValidateCreateP2pInterface(false, false, false, P2P_IFACE_NAME, true, 0); + executeAndValidateTeardownP2pInterface(false, false, false, false, false, + mActiveP2pIface, true); + } + + @Test + public void testSetupP2pInterfaceAndTeardownP2pWhenClientInterfaceExist() throws Exception { + // Start client interface + executeAndValidateSetupClientInterface( + false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0, + mNetworkObserverCaptor0); + assertEquals(Set.of(IFACE_NAME_0), mWifiNative.getClientInterfaceNames()); + executeAndValidateCreateP2pInterface(true, false, false, P2P_IFACE_NAME, true, 0); + assertTrue(mWifiNative.hasAnyP2pIface()); + executeAndValidateTeardownP2pInterface(true, true, true, false, false, + mActiveP2pIface, true); + assertFalse(mWifiNative.hasAnyP2pIface()); + verify(mWifiVendorHal, never()).stopVendorHal(); + } + + /** + * Verifies the setup of a single client interface and teardown by P2P on. + */ + @Test + public void testSetupClientInterfaceAndTeardownP2p() throws Exception { + executeAndValidateCreateP2pInterface(false, false, false, P2P_IFACE_NAME, true, 0); + // Trigger the P2P interface teardown when STA interface is created. + // The iface name will remain the same. + doAnswer(new MockAnswerUtil.AnswerWithArguments() { + public String answer(InterfaceDestroyedListener destroyedListener, WorkSource ws, + ConcreteClientModeManager concreteClientModeManager) { + mWifiNative.teardownP2pIface(mActiveP2pIface.id); + return IFACE_NAME_0; + } + }).when(mWifiVendorHal).createStaIface(any(), any(), eq(mConcreteClientModeManager)); + + assertEquals(IFACE_NAME_0, + mWifiNative.setupInterfaceForClientInScanMode(mIfaceCallback0, TEST_WORKSOURCE, + mConcreteClientModeManager)); + assertEquals(Set.of(IFACE_NAME_0), mWifiNative.getClientInterfaceNames()); + validateSetupClientInterfaceForScan( + false, false, true, IFACE_NAME_0, mIfaceDestroyedListenerCaptor0, + mNetworkObserverCaptor0, true, 0); + verify(mSupplicantStaIfaceHal, atLeastOnce()).isInitializationStarted(); + verify(mWifiVendorHal, never()).stopVendorHal(); + verify(mWifiP2pNative).stopP2pSupplicantIfNecessary(); + } + + /** + * Verifies the setup of a single client interface (for scan) and teardown by P2P on. + */ + @Test + public void testCreateP2pIfaceAndTeardownClientIface() throws Exception { + executeAndValidateSetupClientInterface( + false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0, + mNetworkObserverCaptor0); + assertEquals(Set.of(IFACE_NAME_0), mWifiNative.getClientInterfaceNames()); + // Trigger the STA interface teardown when P2p interface is created. + // The iface name will remain the same. + doAnswer(new MockAnswerUtil.AnswerWithArguments() { + public String answer( + HalDeviceManager.InterfaceDestroyedListener p2pInterfaceDestroyedListener, + Handler handler, WorkSource requestorWs) { + mIfaceDestroyedListenerCaptor0.getValue().onDestroyed(IFACE_NAME_0); + return P2P_IFACE_NAME; + } + }).when(mHalDeviceManager).createP2pIface(any(), any(), any()); + mActiveP2pIface = mWifiNative.createP2pIface(mP2pInterfaceDestroyedListener, + mP2pEventHandler, TEST_WORKSOURCE); + assertEquals(P2P_IFACE_NAME, mActiveP2pIface.name); + // Creation of P2P interface should trigger the STA interface destroy + verify(mWifiVendorHal, atLeastOnce()).isVendorHalSupported(); + verify(mWifiVendorHal, atLeastOnce()).isVendorHalReady(); + validateOnDestroyedClientInterface(false, false, true, + IFACE_NAME_0, mIfaceCallback0, mNetworkObserverCaptor0.getValue()); + validateCreateP2pInterface(true, false, false, P2P_IFACE_NAME, true, 0); + executeAndValidateTeardownP2pInterface(false, false, false, false, false, + mActiveP2pIface, true); + } + private void executeAndValidateSetupClientInterface( boolean hasStaIface, boolean hasApIface, String ifaceName, @Mock WifiNative.InterfaceCallback callback, @@ -1409,10 +1515,21 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean vendorHalSupported, int failureCode) throws Exception { + executeAndValidateSetupClientInterface(hasStaIface, hasApIface, false, ifaceName, callback, + destroyedListenerCaptor, + networkObserverCaptor, vendorHalSupported, failureCode); + } + + private void executeAndValidateSetupClientInterface( + boolean hasStaIface, boolean hasApIface, boolean hasP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, + ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean vendorHalSupported, + int failureCode) throws Exception { when(mWifiVendorHal.createStaIface(any(), any(), eq(mConcreteClientModeManager))) .thenReturn(ifaceName); executeAndValidateSetupClientInterfaceForScan( - hasStaIface, hasApIface, ifaceName, callback, destroyedListenerCaptor, + hasStaIface, hasApIface, hasP2pIface, ifaceName, callback, destroyedListenerCaptor, networkObserverCaptor, vendorHalSupported, failureCode); executeAndValidateSwitchClientInterfaceToConnectivityMode(hasStaIface, hasApIface, ifaceName, TEST_WORKSOURCE, vendorHalSupported, failureCode); @@ -1423,6 +1540,16 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { String ifaceName, @Mock WifiNative.InterfaceCallback callback, InterfaceDestroyedListener destroyedListener, NetdEventObserver networkObserver) throws Exception { + executeAndValidateTeardownClientInterface(anyOtherStaIface, anyOtherApIface, + false /* anyOtherP2pIface */, ifaceName, callback, destroyedListener, + networkObserver); + } + + private void executeAndValidateTeardownClientInterface( + boolean anyOtherStaIface, boolean anyOtherApIface, boolean anyOtherP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + InterfaceDestroyedListener destroyedListener, + NetdEventObserver networkObserver) throws Exception { mWifiNative.teardownInterface(ifaceName); mInOrder.verify(mWifiVendorHal).isVendorHalSupported(); @@ -1432,13 +1559,23 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { destroyedListener.onDestroyed(ifaceName); validateOnDestroyedClientInterface( - anyOtherStaIface, anyOtherApIface, ifaceName, callback, networkObserver); + anyOtherStaIface, anyOtherApIface, anyOtherP2pIface, + ifaceName, callback, networkObserver); } private void validateOnDestroyedClientInterface( boolean anyOtherStaIface, boolean anyOtherApIface, String ifaceName, @Mock WifiNative.InterfaceCallback callback, NetdEventObserver networkObserver) throws Exception { + validateOnDestroyedClientInterface( + anyOtherStaIface, anyOtherApIface, false /* anyOtherP2pIface */, + ifaceName, callback, networkObserver); + } + + private void validateOnDestroyedClientInterface( + boolean anyOtherStaIface, boolean anyOtherApIface, boolean anyOtherP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + NetdEventObserver networkObserver) throws Exception { mInOrder.verify(mWifiMonitor).stopMonitoring(ifaceName); if (networkObserver != null) { mInOrder.verify(mNetdWrapper).unregisterObserver(networkObserver); @@ -1447,10 +1584,15 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mWificondControl).tearDownClientInterface(ifaceName); if (!anyOtherStaIface) { + mInOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted(); mInOrder.verify(mSupplicantStaIfaceHal).deregisterDeathHandler(); - mInOrder.verify(mSupplicantStaIfaceHal).terminate(); + if (!anyOtherP2pIface) { + mInOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted(); + mInOrder.verify(mSupplicantStaIfaceHal).terminate(); + } + when(mSupplicantStaIfaceHal.isInitializationStarted()).thenReturn(false); } - if (!anyOtherStaIface && !anyOtherApIface) { + if (!anyOtherStaIface && !anyOtherApIface && !anyOtherP2pIface) { mInOrder.verify(mWificondControl).tearDownInterfaces(); mInOrder.verify(mWifiVendorHal).isVendorHalSupported(); mInOrder.verify(mWifiVendorHal).stopVendorHal(); @@ -1474,6 +1616,17 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean vendorHalSupported, int failureCode) throws Exception { + executeAndValidateSetupClientInterfaceForScan(hasStaIface, hasApIface, + false /* hasP2pIface */, ifaceName, callback, + destroyedListenerCaptor, networkObserverCaptor, vendorHalSupported, failureCode); + } + + private void executeAndValidateSetupClientInterfaceForScan( + boolean hasStaIface, boolean hasApIface, boolean hasP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, + ArgumentCaptor<NetdEventObserver> networkObserverCaptor, + boolean vendorHalSupported, int failureCode) throws Exception { if (failureCode != STA_FAILURE_CODE_CREAT_IFACE) { when(mWifiVendorHal.createStaIface(any(), any(), eq(mConcreteClientModeManager))) .thenReturn(ifaceName); @@ -1483,7 +1636,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mConcreteClientModeManager)); validateSetupClientInterfaceForScan( - hasStaIface, hasApIface, ifaceName, destroyedListenerCaptor, + hasStaIface, hasApIface, hasP2pIface, ifaceName, destroyedListenerCaptor, networkObserverCaptor, vendorHalSupported, failureCode); } @@ -1508,7 +1661,17 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { String ifaceName, ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean vendorHalSupported, int failureCode) throws Exception { - validateStartHal(hasStaIface || hasApIface, vendorHalSupported); + validateSetupClientInterfaceForScan(hasStaIface, hasApIface, false /* hasP2pIfacd */, + ifaceName, destroyedListenerCaptor, networkObserverCaptor, vendorHalSupported, + failureCode); + } + + private void validateSetupClientInterfaceForScan( + boolean hasStaIface, boolean hasApIface, boolean hasP2pIface, + String ifaceName, ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, + ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean vendorHalSupported, + int failureCode) throws Exception { + validateStartHal(hasStaIface || hasApIface || hasP2pIface, vendorHalSupported); if (vendorHalSupported) { mInOrder.verify(mWifiVendorHal).createStaIface( destroyedListenerCaptor.capture(), eq(TEST_WORKSOURCE), @@ -1546,6 +1709,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mSupplicantStaIfaceHal).getAdvancedCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getSupportedFeatureSet(ifaceName); mInOrder.verify(mSupplicantStaIfaceHal).getWpaDriverFeatureSet(ifaceName); + mInOrder.verify(mWifiVendorHal).getTwtCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getUsableChannels(anyInt(), anyInt(), anyInt()); mInOrder.verify(mWifiVendorHal).enableStaChannelForPeerNetwork(anyBoolean(), anyBoolean()); } @@ -1555,6 +1719,16 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { String ifaceName, @Mock WifiNative.InterfaceCallback callback, InterfaceDestroyedListener destroyedListener, NetdEventObserver networkObserver) throws Exception { + executeAndValidateTeardownClientInterfaceForScan(anyOtherStaIface, anyOtherApIface, + false /* anyOtherP2pIface */, ifaceName, callback, destroyedListener, + networkObserver); + } + + private void executeAndValidateTeardownClientInterfaceForScan( + boolean anyOtherStaIface, boolean anyOtherApIface, boolean anyOtherP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + InterfaceDestroyedListener destroyedListener, + NetdEventObserver networkObserver) throws Exception { mWifiNative.teardownInterface(ifaceName); mInOrder.verify(mWifiVendorHal).isVendorHalSupported(); @@ -1564,20 +1738,30 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { destroyedListener.onDestroyed(ifaceName); validateOnDestroyedClientInterfaceForScan( - anyOtherStaIface, anyOtherApIface, ifaceName, callback, networkObserver); + anyOtherStaIface, anyOtherApIface, anyOtherP2pIface, + ifaceName, callback, networkObserver); } private void validateOnDestroyedClientInterfaceForScan( boolean anyOtherStaIface, boolean anyOtherApIface, String ifaceName, @Mock WifiNative.InterfaceCallback callback, NetdEventObserver networkObserver) throws Exception { + validateOnDestroyedClientInterfaceForScan( + anyOtherStaIface, anyOtherApIface, false /* anyOtherP2pIface */, + ifaceName, callback, networkObserver); + } + + private void validateOnDestroyedClientInterfaceForScan( + boolean anyOtherStaIface, boolean anyOtherApIface, boolean anyOtherP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + NetdEventObserver networkObserver) throws Exception { mInOrder.verify(mWifiMonitor).stopMonitoring(ifaceName); if (networkObserver != null) { mInOrder.verify(mNetdWrapper).unregisterObserver(networkObserver); } mInOrder.verify(mWificondControl).tearDownClientInterface(ifaceName); - if (!anyOtherStaIface && !anyOtherApIface) { + if (!anyOtherStaIface && !anyOtherApIface && !anyOtherP2pIface) { mInOrder.verify(mWificondControl).tearDownInterfaces(); mInOrder.verify(mWifiVendorHal).isVendorHalSupported(); mInOrder.verify(mWifiVendorHal).stopVendorHal(); @@ -1601,6 +1785,17 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean isBridged, boolean vendorHalSupported, int failureCode) throws Exception { + executeAndValidateSetupSoftApInterface(hasStaIface, hasApIface, false /* hasP2pIface */, + ifaceName, callback, destroyedListenerCaptor, networkObserverCaptor, + isBridged, vendorHalSupported, failureCode); + } + + private void executeAndValidateSetupSoftApInterface( + boolean hasStaIface, boolean hasApIface, boolean hasP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, + ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean isBridged, + boolean vendorHalSupported, int failureCode) throws Exception { when(mWifiVendorHal.createApIface(any(), any(), anyInt(), eq(isBridged), any(), anyList())) .thenReturn(ifaceName); assertEquals(failureCode == 0 ? ifaceName : null, mWifiNative.setupInterfaceForSoftApMode( @@ -1617,7 +1812,17 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { String ifaceName, ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean isBridged, boolean vendorHalSupported, int failureCode) throws Exception { - validateStartHal(hasStaIface || hasApIface, vendorHalSupported); + validateSetupSoftApInterface(hasStaIface, hasApIface, false /* hasP2pIface */, + ifaceName, destroyedListenerCaptor, + networkObserverCaptor, isBridged, vendorHalSupported, failureCode); + } + + private void validateSetupSoftApInterface( + boolean hasStaIface, boolean hasApIface, boolean hasP2pIface, + String ifaceName, ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor, + ArgumentCaptor<NetdEventObserver> networkObserverCaptor, boolean isBridged, + boolean vendorHalSupported, int failureCode) throws Exception { + validateStartHal(hasStaIface || hasApIface || hasP2pIface, vendorHalSupported); if (!hasApIface) { mInOrder.verify(mHostapdHal).isInitializationStarted(); mInOrder.verify(mHostapdHal).initialize(); @@ -1649,8 +1854,11 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { } mInOrder.verify(mWificondControl).tearDownClientInterface(ifaceName); if (mWifiNative.hasAnyStaIfaceForConnectivity()) { + mInOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted(); mInOrder.verify(mSupplicantStaIfaceHal).deregisterDeathHandler(); + mInOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted(); mInOrder.verify(mSupplicantStaIfaceHal).terminate(); + when(mSupplicantStaIfaceHal.isInitializationStarted()).thenReturn(false); } mInOrder.verify(mWifiVendorHal).isVendorHalReady(); mInOrder.verify(mIfaceCallback0).onDestroyed(ifaceName); @@ -1676,6 +1884,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mSupplicantStaIfaceHal).getAdvancedCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getSupportedFeatureSet(ifaceName); mInOrder.verify(mSupplicantStaIfaceHal).getWpaDriverFeatureSet(ifaceName); + mInOrder.verify(mWifiVendorHal).getTwtCapabilities(ifaceName); mInOrder.verify(mWifiVendorHal).getUsableChannels(anyInt(), anyInt(), anyInt()); } @@ -1693,13 +1902,23 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { destroyedListener.onDestroyed(ifaceName); validateOnDestroyedSoftApInterface( - anyOtherStaIface, anyOtherApIface, ifaceName, callback, networkObserver); + anyOtherStaIface, anyOtherApIface, false /* anyOtherP2pIface */, + ifaceName, callback, networkObserver); } private void validateOnDestroyedSoftApInterface( boolean anyOtherStaIface, boolean anyOtherApIface, String ifaceName, @Mock WifiNative.InterfaceCallback callback, NetdEventObserver networkObserver) throws Exception { + validateOnDestroyedSoftApInterface( + anyOtherStaIface, anyOtherApIface, false /* anyOtherP2pIface */, + ifaceName, callback, networkObserver); + } + + private void validateOnDestroyedSoftApInterface( + boolean anyOtherStaIface, boolean anyOtherApIface, boolean anyOtherP2pIface, + String ifaceName, @Mock WifiNative.InterfaceCallback callback, + NetdEventObserver networkObserver) throws Exception { if (networkObserver != null) { mInOrder.verify(mNetdWrapper).unregisterObserver(networkObserver); } @@ -1710,7 +1929,7 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mInOrder.verify(mHostapdHal).deregisterDeathHandler(); mInOrder.verify(mHostapdHal).terminate(); } - if (!anyOtherStaIface && !anyOtherApIface) { + if (!anyOtherStaIface && !anyOtherApIface && !anyOtherP2pIface) { mInOrder.verify(mWificondControl).tearDownInterfaces(); mInOrder.verify(mWifiVendorHal).isVendorHalSupported(); mInOrder.verify(mWifiVendorHal).stopVendorHal(); @@ -1733,4 +1952,77 @@ public class WifiNativeInterfaceManagementTest extends WifiBaseTest { mLooper.dispatchAll(); mInOrder.verify(mIfaceEventCallback0).onInterfaceAdded(ifaceName); } + + private void executeAndValidateCreateP2pInterface( + boolean hasStaIface, boolean hasApIface, boolean hasP2pIface, + String ifaceName, boolean vendorHalSupported, int failureCode) throws Exception { + if (failureCode != P2P_FAILURE_CODE_CREATE_INTERFACE) { + if (vendorHalSupported) { + when(mHalDeviceManager.createP2pIface(any(), any(), any())) + .thenReturn(ifaceName); + } else { + when(mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME)) + .thenReturn(ifaceName); + } + } + mActiveP2pIface = mWifiNative.createP2pIface(mP2pInterfaceDestroyedListener, + mP2pEventHandler, TEST_WORKSOURCE); + if (failureCode == 0) { + assertNotNull(mActiveP2pIface); + assertEquals(mActiveP2pIface.name, ifaceName); + } else { + assertNull(mActiveP2pIface); + } + validateCreateP2pInterface(hasStaIface, hasApIface, hasP2pIface, + ifaceName, vendorHalSupported, failureCode); + } + + private void validateCreateP2pInterface( + boolean hasStaIface, boolean hasApIface, boolean hasP2pIface, + String ifaceName, boolean vendorHalSupported, int failureCode) throws Exception { + validateStartHal(hasStaIface || hasApIface || hasP2pIface, vendorHalSupported); + if (vendorHalSupported) { + verify(mHalDeviceManager).createP2pIface(eq(mP2pInterfaceDestroyedListener), + eq(mP2pEventHandler), eq(TEST_WORKSOURCE)); + if (failureCode == P2P_FAILURE_CODE_CREATE_INTERFACE) { + verify(mWifiMetrics).incrementNumSetupP2pInterfaceFailureDueToHal(); + } + } else { + verify(mPropertyService).getString(eq(P2P_INTERFACE_PROPERTY), eq(P2P_IFACE_NAME)); + } + } + + private void executeAndValidateTeardownP2pInterface( + boolean anyOtherStaIface, boolean anyOtherConnectivityStaIface, + boolean isSupplicantStartedBefore, boolean anyOtherApIface, + boolean anyOtherP2pIface, WifiNative.Iface iface, boolean vendorHalSupported) + throws Exception { + mWifiNative.teardownP2pIface(iface.id); + + validateOnDestroyedP2pInterface(anyOtherStaIface, anyOtherConnectivityStaIface, + isSupplicantStartedBefore, anyOtherApIface, + anyOtherP2pIface, vendorHalSupported); + } + + private void validateOnDestroyedP2pInterface( + boolean anyOtherStaIface, boolean anyOtherConnectivityStaIface, + boolean isSupplicantStartedBefore, boolean anyOtherApIface, + boolean anyOtherP2pIface, boolean vendorHalSupported) throws Exception { + if (vendorHalSupported && !anyOtherStaIface && !anyOtherApIface && !anyOtherP2pIface) { + mInOrder.verify(mWificondControl).tearDownInterfaces(); + mInOrder.verify(mWifiVendorHal).isVendorHalSupported(); + mInOrder.verify(mWifiVendorHal).stopVendorHal(); + } + if (!anyOtherConnectivityStaIface) { + mInOrder.verify(mSupplicantStaIfaceHal, atLeastOnce()).isInitializationStarted(); + if (isSupplicantStartedBefore) { + mInOrder.verify(mSupplicantStaIfaceHal).deregisterDeathHandler(); + mInOrder.verify(mSupplicantStaIfaceHal).terminate(); + } else { + if (!anyOtherP2pIface) { + mInOrder.verify(mWifiP2pNative).stopP2pSupplicantIfNecessary(); + } + } + } + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java index 63389f8dbc..492770024d 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java @@ -51,7 +51,9 @@ import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiContext; +import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; +import android.net.wifi.WifiScanner.ScanData; import android.net.wifi.WifiSsid; import android.net.wifi.nl80211.NativeScanResult; import android.net.wifi.nl80211.RadioChainInfo; @@ -350,6 +352,7 @@ public class WifiNativeTest extends WifiBaseTest { mHandler, mRandom, mBuildProperties, mWifiInjector); mWifiNative.enableVerboseLogging(true, true); mWifiNative.initialize(); + assertNull(mWifiNative.mUnknownAkmMap); } @After @@ -1643,6 +1646,48 @@ public class WifiNativeTest extends WifiBaseTest { } @Test + public void testGetCachedScanResultsLocationDisabledOrInvalidTimestamp() throws Exception { + ScanResult[] scanResults = new ScanResult[2]; + for (int i = 0; i < 2; i++) { + ScanResult scanResult = new ScanResult(); + scanResult.timestamp = 0; + scanResults[i] = scanResult; + } + ScanData testScanData = new ScanData(0, 0, + 0, WifiScanner.WIFI_BAND_UNSPECIFIED, scanResults); + when(mWifiVendorHal.getCachedScanData(any())).thenReturn(testScanData); + + mWifiNative.setLocationModeEnabled(false); + ScanData scanData = mWifiNative.getCachedScanResults(WIFI_IFACE_NAME); + // Get no scan result because the location mode is disabled + assertEquals(0, scanData.getResults().length); + + mWifiNative.setLocationModeEnabled(true); + scanData = mWifiNative.getCachedScanResults(WIFI_IFACE_NAME); + // Get no scan result because the scan timestamp is too new + assertEquals(0, scanData.getResults().length); + } + + @Test + public void testGetCachedScanResultsLocationEnabledValidTimestamp() throws Exception { + ScanResult[] scanResults = new ScanResult[3]; + for (int i = 0; i < 3; i++) { + ScanResult scanResult = new ScanResult(); + // 1st ScanResult has invalid timestamp + scanResult.timestamp = (i > 0) ? Long.MAX_VALUE : 0; + scanResults[i] = scanResult; + } + ScanData testScanData = new ScanData(0, 0, + 0, WifiScanner.WIFI_BAND_UNSPECIFIED, scanResults); + when(mWifiVendorHal.getCachedScanData(any())).thenReturn(testScanData); + + mWifiNative.setLocationModeEnabled(true); + ScanData scanData = mWifiNative.getCachedScanResults(WIFI_IFACE_NAME); + // Get the last two scan results which has the valid timestamp + assertEquals(2, scanData.getResults().length); + } + + @Test public void testEnableStaChannelForPeerNetworkWithOverride() throws Exception { mResources.setBoolean(R.bool.config_wifiEnableStaIndoorChannelForPeerNetwork, true); mResources.setBoolean(R.bool.config_wifiEnableStaDfsChannelForPeerNetwork, true); @@ -1659,4 +1704,118 @@ public class WifiNativeTest extends WifiBaseTest { mWifiNative.setAfcChannelAllowance(mAfcChannelAllowance); verify(mWifiVendorHal).setAfcChannelAllowance(mAfcChannelAllowance); } + + /** + * Verifies that overlay config item config_wifiUnknownAkmToKnownAkmMapping is parsed correctly + * and an expected value is set in unknown AKM map. + */ + @Test + public void testConfigWifiUnknownAkmToKnownAkmMapping() throws Exception { + // Test that UnknownAkmMap is not set if two values are not added in the config. + mResources.setStringArray( + R.array.config_wifiUnknownAkmToKnownAkmMapping, new String[] {"1234"}); + WifiNative wifiNativeInstance = + new WifiNative( + mWifiVendorHal, + mStaIfaceHal, + mHostapdHal, + mWificondControl, + mWifiMonitor, + mPropertyService, + mWifiMetrics, + mHandler, + mRandom, + mBuildProperties, + mWifiInjector); + assertNull(wifiNativeInstance.mUnknownAkmMap); + + // Test that UnknownAkmMap is not set if non-integer values are added in the config. + mResources.setStringArray( + R.array.config_wifiUnknownAkmToKnownAkmMapping, new String[] {"1234, bad"}); + wifiNativeInstance = + new WifiNative( + mWifiVendorHal, + mStaIfaceHal, + mHostapdHal, + mWificondControl, + mWifiMonitor, + mPropertyService, + mWifiMetrics, + mHandler, + mRandom, + mBuildProperties, + mWifiInjector); + assertNull(wifiNativeInstance.mUnknownAkmMap); + + // Test that UnknownAkmMap is not set when an invalid AKM is set in the known AKM field + // known AKM - 555 (which is not a valid AKM suite specifier) + mResources.setStringArray( + R.array.config_wifiUnknownAkmToKnownAkmMapping, new String[] {"9846784, 555"}); + wifiNativeInstance = + new WifiNative( + mWifiVendorHal, + mStaIfaceHal, + mHostapdHal, + mWificondControl, + mWifiMonitor, + mPropertyService, + mWifiMetrics, + mHandler, + mRandom, + mBuildProperties, + mWifiInjector); + assertNull(wifiNativeInstance.mUnknownAkmMap); + + // Test that UnknownAkmMap is set for a valid configuration + // known AKM - 28053248 (which corresponds to ScanResult.KEY_MGMT_EAP) + mResources.setStringArray( + R.array.config_wifiUnknownAkmToKnownAkmMapping, new String[] {"9846784, 28053248"}); + wifiNativeInstance = + new WifiNative( + mWifiVendorHal, + mStaIfaceHal, + mHostapdHal, + mWificondControl, + mWifiMonitor, + mPropertyService, + mWifiMetrics, + mHandler, + mRandom, + mBuildProperties, + mWifiInjector); + assertEquals(1, wifiNativeInstance.mUnknownAkmMap.size()); + assertEquals(ScanResult.KEY_MGMT_EAP, wifiNativeInstance.mUnknownAkmMap.get(9846784)); + + // Test that UnknownAkmMap is set for multiple valid configuration entries + // known AKM - 28053248 (which corresponds to ScanResult.KEY_MGMT_EAP) + // known AKM - 413929216 (which corresponds to ScanResult.KEY_MGMT_SAE_EXT_KEY) + mResources.setStringArray( + R.array.config_wifiUnknownAkmToKnownAkmMapping, + new String[] {"9846784, 28053248", "1234, 413929216"}); + wifiNativeInstance = + new WifiNative( + mWifiVendorHal, + mStaIfaceHal, + mHostapdHal, + mWificondControl, + mWifiMonitor, + mPropertyService, + mWifiMetrics, + mHandler, + mRandom, + mBuildProperties, + mWifiInjector); + assertEquals(2, wifiNativeInstance.mUnknownAkmMap.size()); + assertEquals(ScanResult.KEY_MGMT_EAP, wifiNativeInstance.mUnknownAkmMap.get(9846784)); + assertEquals(ScanResult.KEY_MGMT_SAE_EXT_KEY, wifiNativeInstance.mUnknownAkmMap.get(1234)); + } + + @Test + public void testSetRoamingMode() throws Exception { + int status = 0; + when(mWifiVendorHal.setRoamingMode(eq(WIFI_IFACE_NAME), anyInt())).thenReturn(status); + assertEquals(status, mWifiNative.setRoamingMode(WIFI_IFACE_NAME, + WifiManager.ROAMING_MODE_NORMAL)); + verify(mWifiVendorHal).setRoamingMode(WIFI_IFACE_NAME, WifiManager.ROAMING_MODE_NORMAL); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java index d4db3789a2..d2e20cdfc7 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java @@ -93,10 +93,11 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.WorkSource; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; import android.util.Pair; import android.util.Xml; +import androidx.test.filters.SmallTest; + import com.android.internal.util.FastXmlSerializer; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.WifiNetworkFactory.AccessPoint; @@ -1339,7 +1340,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mClientModeManager).disconnect(); verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1)); + mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1), any()); } /** @@ -1444,7 +1445,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mClientModeManager).disconnect(); verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1)); + mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1), any()); } /** @@ -1494,7 +1495,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mClientModeManager).disconnect(); verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1)); + mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1), any()); } /** @@ -1545,7 +1546,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mClientModeManager).disconnect(); verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1)); + mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1), any()); } /** @@ -1606,7 +1607,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mClientModeManager).disconnect(); verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1)); + mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1), any()); } /** @@ -1673,7 +1674,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mClientModeManager).disconnect(); verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1)); + mConnectListenerArgumentCaptor.capture(), anyInt(), eq(TEST_PACKAGE_NAME_1), any()); } /** @@ -2468,7 +2469,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mConnectHelper).connectToNetwork( eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } /** @@ -2957,7 +2958,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ModeImplProxy. verify(mConnectHelper, never()).connectToNetwork(any(), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } /** @@ -3001,7 +3002,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeManager. verify(mConnectHelper, never()).connectToNetwork(any(), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } /** @@ -3042,7 +3043,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeManager. verify(mConnectHelper, never()).connectToNetwork(any(), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } /** @@ -3080,7 +3081,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { // Connection does not happen yet since it is waiting for scan results. verify(mConnectHelper, never()).connectToNetwork(any(), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); // simulate scan results coming in and verify we auto connect to the network when(mNetworkRequestMatchCallback.asBinder()).thenReturn(mAppBinder); @@ -3100,7 +3101,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { if (bypassActivated) { assertNotNull(configurationArgumentCaptor.getAllValues().get(1).BSSID); verify(mConnectHelper).connectToNetwork(any(), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } } @@ -3161,7 +3162,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeManager. verify(mConnectHelper, never()).connectToNetwork(any(), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } /** @@ -3205,7 +3206,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeManager. verify(mConnectHelper, never()).connectToNetwork(any(), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } /** @@ -3239,9 +3240,17 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { @Test public void testNetworkSpecifierUserApprovalConfigStoreLoad() throws Exception { + // Setup scan data for WPA-PSK networks. + setupScanData(SCAN_RESULT_TYPE_WPA_PSK, + TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); + + // Choose the matching scan result. + ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; + when(mWifiScanner.getSingleScanResults()) + .thenReturn(Arrays.asList(mTestScanDatas[0].getResults())); Map<String, Set<AccessPoint>> approvedAccessPointsMapToRead = new HashMap<>(); Set<AccessPoint> approvedAccessPoints = Set.of( - new AccessPoint(TEST_SSID_1, MacAddress.fromString(TEST_BSSID_1), + new AccessPoint(TEST_SSID_1, MacAddress.fromString(matchingScanResult.BSSID), WifiConfiguration.SECURITY_TYPE_PSK)); approvedAccessPointsMapToRead.put(TEST_PACKAGE_NAME_1, approvedAccessPoints); mDataSource.fromDeserialized(approvedAccessPointsMapToRead); @@ -3250,7 +3259,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair<MacAddress, MacAddress> bssidPatternMatch = - Pair.create(MacAddress.fromString(TEST_BSSID_1), + Pair.create(MacAddress.fromString(matchingScanResult.BSSID), MacAddress.BROADCAST_ADDRESS); attachWifiNetworkSpecifierAndAppInfo( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), @@ -3264,7 +3273,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mNetworkRequestMatchCallback, never()).onMatch(anyList()); // Verify that we sent a connection attempt to ClientModeManager verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); } /** @@ -3312,6 +3321,8 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { // 2. Second request for the same access point (user approval bypass). ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; + when(mWifiScanner.getSingleScanResults()) + .thenReturn(Arrays.asList(mTestScanDatas[0].getResults())); PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); @@ -3334,7 +3345,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { // Verify that we sent a connection attempt to ClientModeManager if (bypassActivated) { verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); verify(mWifiMetrics).incrementNetworkRequestApiNumUserApprovalBypass(); } @@ -3368,6 +3379,8 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { // Choose the matching scan result. ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; + when(mWifiScanner.getSingleScanResults()) + .thenReturn(Arrays.asList(mTestScanDatas[0].getResults())); // Setup CDM approval for the scan result. when(mCompanionDeviceManager.isDeviceAssociatedForWifiConnection( @@ -3394,7 +3407,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mNetworkRequestMatchCallback, never()).onMatch(anyList()); // Verify that we sent a connection attempt to ClientModeManager verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); verify(mWifiMetrics).incrementNetworkRequestApiNumUserApprovalBypass(); } @@ -3431,6 +3444,8 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { // Choose the matching scan result. ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; + when(mWifiScanner.getSingleScanResults()) + .thenReturn(Arrays.asList(mTestScanDatas[0].getResults())); // Setup shell approval for the scan result. mWifiNetworkFactory.setUserApprovedApp(TEST_PACKAGE_NAME_1, true); @@ -3454,7 +3469,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mNetworkRequestMatchCallback, never()).onMatch(anyList()); // Verify that we sent a connection attempt to ClientModeManager verify(mConnectHelper).connectToNetwork(eq(mClientModeManager), any(), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); verify(mWifiMetrics).incrementNetworkRequestApiNumUserApprovalBypass(); } @@ -3563,7 +3578,8 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { // Verify no reconnection verify(mWifiConnectivityManager, never()).setSpecificNetworkRequestInProgress(true); verify(mClientModeManager, never()).disconnect(); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), any(), anyInt(), any(), + any()); // Verify the network will be shared with new request. assertEquals(2, mWifiNetworkFactory @@ -3630,7 +3646,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { // Verify disconnect and reconnect verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(true); verify(mClientModeManager).disconnect(); - verify(mConnectHelper).connectToNetwork(any(), any(), any(), anyInt(), any()); + verify(mConnectHelper).connectToNetwork(any(), any(), any(), anyInt(), any(), any()); // Verify the network will be only available to car mode app. assertEquals(1, mWifiNetworkFactory @@ -3687,7 +3703,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mConnectHelper, atLeastOnce()).connectToNetwork( eq(mPrimaryClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); verify(mWifiMetrics, atLeastOnce()).incrementNetworkRequestApiNumConnectOnPrimaryIface(); // Start the connection timeout alarm. @@ -3751,7 +3767,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { verify(mConnectHelper, atLeastOnce()).connectToNetwork( eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), - mConnectListenerArgumentCaptor.capture(), anyInt(), any()); + mConnectListenerArgumentCaptor.capture(), anyInt(), any(), any()); if (mClientModeManager.getRole() == ActiveModeManager.ROLE_CLIENT_PRIMARY) { verify(mWifiMetrics, atLeastOnce()) .incrementNetworkRequestApiNumConnectOnPrimaryIface(); @@ -3993,7 +4009,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { eq(mClientModeManager), eq(new NetworkUpdateResult(TEST_NETWORK_ID_1)), mConnectListenerArgumentCaptor.capture(), - anyInt(), any()); + anyInt(), any(), any()); // Start the new connection timeout alarm. mInOrder.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java index 7d819b94ef..47b105f948 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java @@ -19,6 +19,8 @@ package com.android.server.wifi; import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE; +import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY; +import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED; import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_EAP; import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE; import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_OWE; @@ -552,7 +554,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); @@ -586,12 +588,12 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); assertTrue(mWifiNetworkSelector.getConnectableScanDetails().isEmpty()); - verify(mPasspointNetworkNominateHelper).updatePasspointConfig(any()); + verify(mPasspointNetworkNominateHelper, never()).updatePasspointConfig(any()); verify(mPasspointNetworkNominateHelper, never()).getPasspointNetworkCandidates(any()); } @@ -623,9 +625,10 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); + assertNotNull(candidate); when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS - 2000); @@ -634,16 +637,16 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, true, false, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); - assertEquals("Expect null configuration", null, candidate); + assertNull("Expect null configuration", candidate); assertTrue(mWifiNetworkSelector.getConnectableScanDetails().isEmpty()); verify(mWifiConfigManager, atLeast(2)) .updateScanDetailCacheFromScanDetailForSavedNetwork(any()); - verify(mPasspointNetworkNominateHelper, times(2)).updatePasspointConfig(any()); + verify(mPasspointNetworkNominateHelper).updatePasspointConfig(any()); verify(mPasspointNetworkNominateHelper).getPasspointNetworkCandidates(any()); } @@ -676,7 +679,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate); @@ -688,7 +691,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -728,7 +731,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); when(mWifiInfo.getSupplicantState()).thenReturn(SupplicantState.COMPLETED); @@ -746,7 +749,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, true, false, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -788,7 +791,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); when(mWifiInfo.getSupplicantState()).thenReturn(SupplicantState.COMPLETED); @@ -814,7 +817,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, true, false, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -850,7 +853,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); verify(mWifiMetrics).incrementNetworkSelectionFilteredBssidCount(0); @@ -891,7 +894,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); verify(mWifiMetrics).incrementNetworkSelectionFilteredBssidCount(1); @@ -931,7 +934,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); @@ -969,7 +972,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); @@ -1009,7 +1012,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); @@ -1052,7 +1055,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); @@ -1101,7 +1104,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); } @@ -1135,7 +1138,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); @@ -1170,7 +1173,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect null configuration", null, candidate); @@ -1205,7 +1208,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals(ssids[0], candidate.SSID); @@ -1239,7 +1242,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -1265,7 +1268,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, true, false, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -1304,7 +1307,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -1335,7 +1338,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, true, false, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertEquals(2, candidates.size()); assertEquals(100, candidates.get(0).getPredictedThroughputMbps()); @@ -1375,7 +1378,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -1401,7 +1404,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -1454,7 +1457,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); WifiConfigurationTestUtil.assertConfigurationEqual(userChoice, candidate); @@ -1469,7 +1472,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); WifiConfigurationTestUtil.assertConfigurationEqual(networkSelectorChoice, candidate); @@ -1510,7 +1513,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); WifiConfigurationTestUtil.assertConfigurationEqual(userChoice, candidate); @@ -1523,7 +1526,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -1565,7 +1568,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); WifiConfigurationTestUtil.assertConfigurationEqual(userChoice, candidate); @@ -1576,7 +1579,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); WifiConfigurationTestUtil.assertConfigurationEqual(networkSelectorChoice, candidate); @@ -1611,7 +1614,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertFalse(candidates.isEmpty()); @@ -1628,7 +1631,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertFalse(candidates.isEmpty()); @@ -1678,7 +1681,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -1894,7 +1897,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); //WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals(1, candidates.size()); @@ -1906,7 +1909,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); //WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals(1, candidates.size()); @@ -2022,7 +2025,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), true, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertNotNull("Result should be not null", candidate); @@ -2064,7 +2067,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, true, false, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), true, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -2102,7 +2105,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); List<ScanDetail> expectedOpenUnsavedNetworks = new ArrayList<>(); @@ -2137,7 +2140,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( unSavedScanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertEquals("Expect open unsaved networks", @@ -2152,7 +2155,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { candidates = mWifiNetworkSelector.getCandidatesFromScan( savedScanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); candidate = mWifiNetworkSelector.selectNetwork(candidates); // Saved networks are filtered out. @@ -2182,7 +2185,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); List<ScanDetail> expectedOpenUnsavedNetworks = new ArrayList<>(); @@ -2214,7 +2217,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); assertTrue(mWifiNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks().isEmpty()); @@ -2256,7 +2259,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); List<ScanDetail> expectedOpenUnsavedNetworks = new ArrayList<>(); @@ -2292,7 +2295,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); List<ScanDetail> expectedOpenUnsavedNetworks = new ArrayList<>(); @@ -2323,7 +2326,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { setUpTwoNetworks(-35, -40), EMPTY_BLOCKLIST, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), true, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -2461,7 +2464,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), true, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); // Check if the wifiConfig is updated with the latest @@ -2492,7 +2495,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); // Expect one privileged and one regular candidate. assertEquals(2, candidates.size()); @@ -2542,7 +2545,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); verify(mWifiMetrics, times(1)) @@ -2666,10 +2669,10 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState( - TEST_IFACE_NAME, true, false, mWifiInfo, false), + TEST_IFACE_NAME, true, false, mWifiInfo, false, ROLE_CLIENT_PRIMARY), new ClientModeManagerState( TEST_IFACE_NAME_SECONDARY, true, false, mSecondaryWifiInfo, - false)), + false, ROLE_CLIENT_SECONDARY_LONG_LIVED)), false, true, true, Collections.emptySet(), false); WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates); @@ -2730,16 +2733,33 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000); - // Do network selection. - List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( - scanDetails, blocklist, + List<ClientModeManagerState> cmmStates = Arrays.asList(new ClientModeManagerState( - TEST_IFACE_NAME, true, false, mWifiInfo, false), + TEST_IFACE_NAME, true, false, mWifiInfo, false, ROLE_CLIENT_PRIMARY), new ClientModeManagerState( - TEST_IFACE_NAME_SECONDARY, true, false, mSecondaryWifiInfo, - false)), - false, true, true, Collections.emptySet(), false); - assertNull(mWifiNetworkSelector.selectNetwork(candidates)); + TEST_IFACE_NAME_SECONDARY, true, false, mSecondaryWifiInfo, false, + ROLE_CLIENT_SECONDARY_LONG_LIVED)); + + // Do network selection. + List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( + scanDetails, blocklist, cmmStates, false, true, true, Collections.emptySet(), + false); + assertNull(candidates); + + // Mock that the primary connection has a user connect choice pointing something + // Verify candidate return is not null in this case + WifiConfiguration primaryConfig = mock(WifiConfiguration.class); + WifiConfiguration.NetworkSelectionStatus networkSelectionStatus = mock( + WifiConfiguration.NetworkSelectionStatus.class); + when(networkSelectionStatus.getConnectChoice()).thenReturn("\"ConnectChoiceTest\"NONE"); + when(primaryConfig.getNetworkSelectionStatus()).thenReturn(networkSelectionStatus); + when(mWifiConfigManager.getConfiguredNetwork(mWifiInfo.getNetworkId())).thenReturn( + primaryConfig); + candidates = mWifiNetworkSelector.getCandidatesFromScan( + scanDetails, blocklist, cmmStates, false, true, true, Collections.emptySet(), + false); + // Candidate should not be null + assertNotNull(candidates); } private void runNetworkSelectionWith(ScanDetailsAndWifiConfigs scanDetailsAndConfigs) { @@ -2747,7 +2767,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { scanDetailsAndConfigs.getScanDetails(), new HashSet<>(), // blocklist Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), true, // untrustedNetworkAllowed true, // oemPaid true, // oemPrivate @@ -2806,7 +2826,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertEquals(2, candidates.size()); @@ -2862,7 +2882,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); // PSK type is disabled, PSK network is not matched. assertEquals(1, candidates.size()); @@ -2896,7 +2916,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertEquals(2, candidates.size()); @@ -2929,7 +2949,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); // The SAE-only network should be filtered. assertEquals(1, candidates.size()); @@ -2964,7 +2984,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertEquals(2, candidates.size()); @@ -3008,7 +3028,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); // OPEN type is disabled, OPEN network is not matched. assertEquals(1, candidates.size()); @@ -3041,7 +3061,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertEquals(2, candidates.size()); @@ -3074,7 +3094,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); // The OWE-only network should be filtered. assertEquals(1, candidates.size()); @@ -3107,7 +3127,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertEquals(2, candidates.size()); @@ -3151,7 +3171,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); // WPA2 Enterprise type is disabled, WPA2 Enterprise network is not matched. assertEquals(1, candidates.size()); @@ -3223,7 +3243,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertNotNull(candidates); if (expectedSecurityParamType == -1) { @@ -3262,7 +3282,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, new HashSet<>(), Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); assertEquals(2, candidates.size()); @@ -3306,10 +3326,11 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { * * @param maxMloStrLinkCount - Maximum STR link count supported for the test. * @param bandMatrix - Simultaneous band combination matrix for the test. + * @param enableWifi7 - Enable Wi-Fi 7 or not * @return A list of Wi-Fi candidates. */ private List<WifiCandidates.Candidate> getWifiCandidates(final int maxMloStrLinkCount, - Set<List<Integer>> bandMatrix) { + Set<List<Integer>> bandMatrix, boolean enableWifi7) { // Static configuration for the test. String[] ssids = {"\"mlo\"", "\"mlo\"", "\"mlo\"", "\"legacy\""}; String[] bssids = @@ -3361,11 +3382,15 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { when(mWifiNative.getSupportedBandCombinations(anyString())).thenReturn(bandMatrix); // Mock interface name when(mClientModeManager.getInterfaceName()).thenReturn(TEST_IFACE_NAME); + // Enable Wi-Fi 7 + for (WifiConfiguration config : scanDetailsAndConfigs.getWifiConfigs()) { + when(mWifiConfigManager.isWifi7Enabled(config.networkId)).thenReturn(enableWifi7); + } // Select network. List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan( scanDetails, blocklist, Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo, - false)), + false, ROLE_CLIENT_PRIMARY)), false, true, true, Collections.emptySet(), false); return candidates; } @@ -3417,19 +3442,19 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { // Scenario: Chip doesn't support Simultaneous Transmit and Receive (STR). // Expectation: no change in multi-link attributes. - for (WifiCandidates.Candidate c : getWifiCandidates(-1, bandMatrix)) { + for (WifiCandidates.Candidate c : getWifiCandidates(-1, bandMatrix, true)) { validateDefaultMultiLinkAttributes(c); } // Scenario: STR link count = 1. // Expectation: no change in multi-link attributes. - for (WifiCandidates.Candidate c : getWifiCandidates(1, bandMatrix)) { + for (WifiCandidates.Candidate c : getWifiCandidates(1, bandMatrix, true)) { validateDefaultMultiLinkAttributes(c); } // Scenario: No band combination info. // Expectation: no change in multi-link attributes. - for (WifiCandidates.Candidate c : getWifiCandidates(2, null)) { + for (WifiCandidates.Candidate c : getWifiCandidates(2, null, true)) { validateDefaultMultiLinkAttributes(c); } } @@ -3456,7 +3481,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { Arrays.asList(WifiScanner.WIFI_BAND_5_GHZ, WifiScanner.WIFI_BAND_6_GHZ))); // Validate multi-link candidates are grouped and predicted multi-link throughput is // updated properly for each group. - for (WifiCandidates.Candidate c : getWifiCandidates(2, bandMatrix)) { + for (WifiCandidates.Candidate c : getWifiCandidates(2, bandMatrix, true)) { switch (c.getKey().bssid.toString()) { case CandidateParams.BSSID_1: assertTrue(c.isMultiLinkCapable()); @@ -3504,7 +3529,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { WifiScanner.WIFI_BAND_6_GHZ))); // Validate multi-link candidates are grouped and predicted multi-link throughput is // updated properly for each group. - for (WifiCandidates.Candidate c : getWifiCandidates(3, bandMatrix)) { + for (WifiCandidates.Candidate c : getWifiCandidates(3, bandMatrix, true)) { switch (c.getKey().bssid.toString()) { case CandidateParams.BSSID_1: // fall through @@ -3541,20 +3566,20 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { // STR not supported. WifiConfiguration candidate; - candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(-1, bandMatrix)); + candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(-1, bandMatrix, true)); assertEquals("\"legacy\"", candidate.SSID); // Max STR link count = 1. - candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(1, bandMatrix)); + candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(1, bandMatrix, true)); assertEquals("\"legacy\"", candidate.SSID); // No band matrix. - candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(2, null)); + candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(2, null, true)); assertEquals("\"legacy\"", candidate.SSID); // Legacy AP is better than MLO. CandidateParams.throughput_4 = 300; - candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(2, bandMatrix)); + candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(2, bandMatrix, true)); assertEquals("\"legacy\"", candidate.SSID); // Revert the throughput change. CandidateParams.throughput_4 = 150; @@ -3581,7 +3606,7 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { Arrays.asList(WifiScanner.WIFI_BAND_5_GHZ, WifiScanner.WIFI_BAND_6_GHZ))); WifiConfiguration candidate; - candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(2, bandMatrix)); + candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(2, bandMatrix, true)); assertEquals("\"mlo\"", candidate.SSID); } @@ -3609,7 +3634,34 @@ public class WifiNetworkSelectorTest extends WifiBaseTest { Arrays.asList(WifiScanner.WIFI_BAND_24_GHZ, WifiScanner.WIFI_BAND_5_GHZ, WifiScanner.WIFI_BAND_6_GHZ))); WifiConfiguration candidate; - candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(3, bandMatrix)); + candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(3, bandMatrix, true)); assertEquals("\"mlo\"", candidate.SSID); } + + /** + * Test Network selection with Wi-Fi7 disabled. + * + * Test scenario: + * Band Supported: {{2.4}, {5}, {6}, {2.4, 5}, {2.4, 6}, {5, 6}, {2.4, 5, 6}} + * APs: AP1 - {2.4 Ghz, 5 Ghz, 6 Ghz} , AP2 - 5 Ghz + * Max STR link count: 3 (tri-band) + */ + @Test + public void testNetworkSelectionDisableWifi7() { + Set<List<Integer>> bandMatrix = Set.of( + new ArrayList(Arrays.asList(WifiScanner.WIFI_BAND_24_GHZ)), + new ArrayList(Arrays.asList(WifiScanner.WIFI_BAND_5_GHZ)), + new ArrayList(Arrays.asList(WifiScanner.WIFI_BAND_6_GHZ)), new ArrayList( + Arrays.asList(WifiScanner.WIFI_BAND_24_GHZ, WifiScanner.WIFI_BAND_5_GHZ)), + new ArrayList( + Arrays.asList(WifiScanner.WIFI_BAND_24_GHZ, WifiScanner.WIFI_BAND_6_GHZ)), + new ArrayList( + Arrays.asList(WifiScanner.WIFI_BAND_5_GHZ, WifiScanner.WIFI_BAND_6_GHZ)), + new ArrayList( + Arrays.asList(WifiScanner.WIFI_BAND_24_GHZ, WifiScanner.WIFI_BAND_5_GHZ, + WifiScanner.WIFI_BAND_6_GHZ))); + WifiConfiguration candidate; + candidate = mWifiNetworkSelector.selectNetwork(getWifiCandidates(3, bandMatrix, false)); + assertEquals("\"legacy\"", candidate.SSID); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java index cbf3c06297..ade054a6c2 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java @@ -87,10 +87,11 @@ import android.os.UserHandle; import android.os.test.TestLooper; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.test.suitebuilder.annotation.SmallTest; import android.util.LocalLog; import android.view.LayoutInflater; +import androidx.test.filters.SmallTest; + import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.modules.utils.build.SdkLevel; diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiPseudonymManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiPseudonymManagerTest.java index 7257f5246a..6915f62853 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiPseudonymManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiPseudonymManagerTest.java @@ -36,7 +36,8 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiContext; import android.net.wifi.WifiEnterpriseConfig; import android.os.Looper; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import com.android.server.wifi.entitlement.CarrierSpecificServiceEntitlement; import com.android.server.wifi.entitlement.PseudonymInfo; @@ -338,7 +339,8 @@ public class WifiPseudonymManagerTest extends WifiBaseTest { any()); assertEquals(AlarmManager.RTC_WAKEUP, mAlarmTypeCaptor.getValue().intValue()); long maxStartTime = Instant.now().toEpochMilli(); - assertTrue(mWindowStartCaptor.getValue().longValue() <= maxStartTime); + assertTrue("The difference is:" + (mWindowStartCaptor.getValue() - maxStartTime), + mWindowStartCaptor.getValue() <= maxStartTime); assertEquals(CARRIER_ID, mRetrieveListenerArgumentCaptor.getValue().mCarrierId); } @@ -362,7 +364,8 @@ public class WifiPseudonymManagerTest extends WifiBaseTest { .getValidPseudonymInfo(CARRIER_ID) .get() .getLttrInMillis(); - assertTrue(mWindowStartCaptor.getValue().longValue() <= maxStartTime); + assertTrue("The difference is:" + (mWindowStartCaptor.getValue() - maxStartTime), + mWindowStartCaptor.getValue() <= maxStartTime + 2); assertEquals(CARRIER_ID, mRetrieveListenerArgumentCaptor.getValue().mCarrierId); } @@ -383,7 +386,8 @@ public class WifiPseudonymManagerTest extends WifiBaseTest { any()); assertEquals(AlarmManager.RTC_WAKEUP, mAlarmTypeCaptor.getValue().intValue()); long maxStartTime = Instant.now().toEpochMilli(); - assertTrue(mWindowStartCaptor.getValue().longValue() <= maxStartTime); + assertTrue("The difference is:" + (mWindowStartCaptor.getValue() - maxStartTime), + mWindowStartCaptor.getValue() <= maxStartTime); assertEquals(CARRIER_ID, mRetrieveListenerArgumentCaptor.getValue().mCarrierId); } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiRoamingConfigStoreTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiRoamingConfigStoreTest.java new file mode 100644 index 0000000000..e59bd4c37a --- /dev/null +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiRoamingConfigStoreTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2024 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.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.validateMockitoUsage; +import static org.mockito.Mockito.verify; + +import android.net.wifi.WifiManager; +import android.util.ArrayMap; +import android.util.Xml; + +import androidx.test.filters.SmallTest; + +import com.android.internal.util.FastXmlSerializer; +import com.android.modules.utils.build.SdkLevel; +import com.android.server.wifi.util.XmlUtil; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlSerializer; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +/** + * Unit tests for {@link com.android.server.wifi.WifiRoamingConfigStoreTest}. + */ +@SmallTest +public class WifiRoamingConfigStoreTest extends WifiBaseTest { + @Mock + private WifiConfigStore mWifiConfigStore; + @Mock + private WifiConfigManager mWifiConfigManager; + private WifiRoamingConfigStore mWifiRoamingConfigStore; + private static final String TEST_SSID = "SSID1"; + private static final int TEST_ROAMING_MODE = WifiManager.ROAMING_MODE_AGGRESSIVE; + private static final int TEST_DEFAULT_ROAMING_MODE = WifiManager.ROAMING_MODE_NORMAL; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mWifiRoamingConfigStore = + new WifiRoamingConfigStore(mWifiConfigManager, mWifiConfigStore); + } + + /** + * Called after each test + */ + @After + public void cleanup() { + validateMockitoUsage(); + } + + @Test + public void testRoamingModeByDeviceAdmin() { + assumeTrue(SdkLevel.isAtLeastV()); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_DEFAULT_ROAMING_MODE); + mWifiRoamingConfigStore.addRoamingMode(TEST_SSID, TEST_ROAMING_MODE, true); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(true).get(TEST_SSID) + == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(false).isEmpty()); + + mWifiRoamingConfigStore.removeRoamingMode(TEST_SSID, true); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_DEFAULT_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(true).isEmpty()); + + verify(mWifiConfigManager, times(2)).saveToStore(true); + } + + @Test + public void testRoamingModeByNonAdmin() { + assumeTrue(SdkLevel.isAtLeastV()); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_DEFAULT_ROAMING_MODE); + mWifiRoamingConfigStore.addRoamingMode(TEST_SSID, TEST_ROAMING_MODE, false); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(false).get(TEST_SSID) + == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(true).isEmpty()); + + mWifiRoamingConfigStore.removeRoamingMode(TEST_SSID, false); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_DEFAULT_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(false).isEmpty()); + + verify(mWifiConfigManager, times(2)).saveToStore(true); + } + + @Test + public void testSaveAndLoadFromStore() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + ArgumentCaptor<WifiConfigStore.StoreData> storeDataCaptor = ArgumentCaptor.forClass( + WifiConfigStore.StoreData.class); + verify(mWifiConfigStore).registerStoreData(storeDataCaptor.capture()); + assertNotNull(storeDataCaptor.getValue()); + + XmlPullParser in = createRoamingPolicyTestXmlForParsing( + TEST_SSID, TEST_ROAMING_MODE, true); + storeDataCaptor.getValue().resetData(); + storeDataCaptor.getValue().deserializeData(in, in.getDepth(), -1, null); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(true).get(TEST_SSID) + == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(false).isEmpty()); + + in = createRoamingPolicyTestXmlForParsing( + TEST_SSID, TEST_ROAMING_MODE, false); + storeDataCaptor.getValue().resetData(); + storeDataCaptor.getValue().deserializeData(in, in.getDepth(), -1, null); + assertTrue(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID) == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(false).get(TEST_SSID) + == TEST_ROAMING_MODE); + assertTrue(mWifiRoamingConfigStore.getPerSsidRoamingModes(true).isEmpty()); + } + + private XmlPullParser createRoamingPolicyTestXmlForParsing(String ssid, Integer roamingMode, + boolean isDeviceOwner) + throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + Map<String, Integer> roamingPolicies = new ArrayMap<>(); + // Serialize + roamingPolicies.put(ssid, roamingMode); + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, "RoamingPolicies"); + XmlUtil.writeNextValue(out, isDeviceOwner ? "DeviceAdminPolicies" : "NonAdminPolicies", + roamingPolicies); + XmlUtil.writeDocumentEnd(out, "RoamingPolicies"); + + // Start Deserializing + final XmlPullParser in = Xml.newPullParser(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + in.setInput(inputStream, StandardCharsets.UTF_8.name()); + XmlUtil.gotoDocumentStart(in, "RoamingPolicies"); + return in; + } +} diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java index 15001919e2..d06ed9f2fc 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java @@ -67,6 +67,7 @@ import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TR import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR; import static com.android.server.wifi.SelfRecovery.REASON_API_CALL; import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE; +import static com.android.server.wifi.WifiSettingsConfigStore.D2D_ALLOWED_WHEN_INFRA_STA_DISABLED; import static com.android.server.wifi.WifiSettingsConfigStore.SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI; import static com.android.server.wifi.WifiSettingsConfigStore.SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI_SET_BY_API; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STA_FACTORY_MAC_ADDRESS; @@ -145,10 +146,12 @@ import android.net.DhcpResultsParcelable; import android.net.MacAddress; import android.net.Network; import android.net.NetworkStack; +import android.net.TetheringManager; import android.net.Uri; import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.IActionListener; import android.net.wifi.IBooleanListener; +import android.net.wifi.IByteArrayListener; import android.net.wifi.ICoexCallback; import android.net.wifi.IDppCallback; import android.net.wifi.IIntegerListener; @@ -157,6 +160,7 @@ import android.net.wifi.ILastCallerListener; import android.net.wifi.IListListener; import android.net.wifi.ILocalOnlyConnectionStatusListener; import android.net.wifi.ILocalOnlyHotspotCallback; +import android.net.wifi.IMapListener; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.IOnWifiActivityEnergyInfoListener; import android.net.wifi.IOnWifiDriverCountryCodeChangedListener; @@ -169,18 +173,24 @@ import android.net.wifi.ISubsystemRestartCallback; import android.net.wifi.ISuggestionConnectionStatusListener; import android.net.wifi.ISuggestionUserApprovalStatusListener; import android.net.wifi.ITrafficStateCallback; +import android.net.wifi.ITwtCallback; +import android.net.wifi.ITwtCapabilitiesListener; +import android.net.wifi.ITwtStatsListener; import android.net.wifi.IWifiBandsListener; import android.net.wifi.IWifiConnectedNetworkScorer; import android.net.wifi.IWifiLowLatencyLockListener; import android.net.wifi.IWifiNetworkSelectionConfigListener; import android.net.wifi.IWifiNetworkStateChangedListener; import android.net.wifi.IWifiVerboseLoggingStatusChangedListener; +import android.net.wifi.MscsParams; +import android.net.wifi.QosCharacteristics; import android.net.wifi.QosPolicyParams; import android.net.wifi.ScanResult; import android.net.wifi.SecurityParams; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApInfo; +import android.net.wifi.SoftApState; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiBands; import android.net.wifi.WifiClient; @@ -200,6 +210,8 @@ import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; +import android.net.wifi.twt.TwtRequest; +import android.net.wifi.twt.TwtSessionCallback; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -222,6 +234,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.Pair; import androidx.test.filters.SmallTest; @@ -231,6 +244,7 @@ import com.android.modules.utils.ParceledListSlice; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.WifiServiceImpl.LocalOnlyRequestorCallback; import com.android.server.wifi.WifiServiceImpl.SoftApCallbackInternal; +import com.android.server.wifi.b2b.WifiRoamingModeManager; import com.android.server.wifi.coex.CoexManager; import com.android.server.wifi.entitlement.PseudonymInfo; import com.android.server.wifi.hotspot2.PasspointManager; @@ -288,6 +302,7 @@ public class WifiServiceImplTest extends WifiBaseTest { private static final String TEST_PACKAGE_NAME = "TestPackage"; private static final String TEST_PACKAGE_NAME_OTHER = "TestPackageOther"; private static final String TEST_FEATURE_ID = "TestFeature"; + private static final String TEST_FEATURE_ID_OTHER = "TestFeatureOther"; private static final String SYSUI_PACKAGE_NAME = "com.android.systemui"; private static final String CERT_INSTALLER_PACKAGE_NAME = "com.android.certinstaller"; private static final int TEST_PID = 6789; @@ -325,6 +340,9 @@ public class WifiServiceImplTest extends WifiBaseTest { SECURITY_NONE)); private static final int TEST_AP_FREQUENCY = 2412; private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ; + private static final TetheringManager.TetheringRequest TEST_TETHERING_REQUEST = + new TetheringManager.TetheringRequest.Builder(TetheringManager.TETHERING_WIFI).build(); + private static final String TEST_IFACE_NAME = "test-wlan0"; private static final int NETWORK_CALLBACK_ID = 1100; private static final String TEST_CAP = "[RSN-PSK-CCMP]"; private static final String TEST_SSID = "Sid's Place"; @@ -368,6 +386,10 @@ public class WifiServiceImplTest extends WifiBaseTest { final ArgumentCaptor<SoftApModeConfiguration> mSoftApModeConfigCaptor = ArgumentCaptor.forClass(SoftApModeConfiguration.class); + final ArgumentCaptor<WifiSettingsConfigStore.OnSettingsChangedListener> + mWepAllowedSettingChangedListenerCaptor = + ArgumentCaptor.forClass(WifiSettingsConfigStore.OnSettingsChangedListener.class); + @Mock Bundle mBundle; @Mock WifiContext mContext; @Mock Context mContextAsUser; @@ -475,9 +497,12 @@ public class WifiServiceImplTest extends WifiBaseTest { @Mock Location mLocation; @Mock WifiDeviceStateChangeManager mWifiDeviceStateChangeManager; @Mock PasspointNetworkNominateHelper mPasspointNetworkNominateHelper; + @Mock WifiRoamingModeManager mWifiRoamingModeManager; + @Mock BackupRestoreController mBackupRestoreController; + @Mock WifiSettingsBackupRestore mWifiSettingsBackupRestore; @Captor ArgumentCaptor<Intent> mIntentCaptor; @Captor ArgumentCaptor<List> mListCaptor; - + @Mock TwtManager mTwtManager; @Rule // For frameworks public TestRule compatChangeRule = new PlatformCompatChangeRule(); @@ -533,6 +558,8 @@ public class WifiServiceImplTest extends WifiBaseTest { .thenReturn(mock(HandlerThread.class)); when(mWifiInjector.getWifiDeviceStateChangeManager()) .thenReturn(mWifiDeviceStateChangeManager); + when(mWifiInjector.getWifiSettingsBackupRestore()).thenReturn(mWifiSettingsBackupRestore); + when(mWifiInjector.getBackupRestoreController()).thenReturn(mBackupRestoreController); when(mHandlerThread.getThreadHandler()).thenReturn(new Handler(mLooper.getLooper())); when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); when(mContext.getResources()).thenReturn(mResources); @@ -657,9 +684,12 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiInjector.getScoringParams()).thenReturn(mScoringParams); when(mWifiInjector.getApplicationQosPolicyRequestHandler()) .thenReturn(mApplicationQosPolicyRequestHandler); + when(mWifiInjector.getWifiRoamingModeManager()).thenReturn(mWifiRoamingModeManager); when(mLocationManager.getProviders(anyBoolean())).thenReturn(List.of( LocationManager.FUSED_PROVIDER, LocationManager.PASSIVE_PROVIDER, LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER)); + when(mWifiInjector.getWifiRoamingModeManager()).thenReturn(mWifiRoamingModeManager); + when(mWifiInjector.getTwtManager()).thenReturn(mTwtManager); doAnswer(new AnswerWithArguments() { public void answer(Runnable onStoppedListener) throws Throwable { @@ -1353,7 +1383,8 @@ public class WifiServiceImplTest extends WifiBaseTest { private void changeLohsState(int apState, int previousState, int error) { // TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, // apState, previousState, error, WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); - mLohsApCallback.onStateChanged(apState, error); + mLohsApCallback.onStateChanged(new SoftApState(apState, error, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); } /** @@ -1367,7 +1398,9 @@ public class WifiServiceImplTest extends WifiBaseTest { mLooper.dispatchAll(); verifyApRegistration(); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + mStateMachineSoftApCallback.onStateChanged( + new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); when(mContext.checkPermission( @@ -1393,7 +1426,9 @@ public class WifiServiceImplTest extends WifiBaseTest { mLooper.dispatchAll(); verifyApRegistration(); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + mStateMachineSoftApCallback.onStateChanged( + new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); when(mContext.checkPermission( eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt())) @@ -1869,8 +1904,13 @@ public class WifiServiceImplTest extends WifiBaseTest { // send an ap state change to verify WifiServiceImpl is updated verifyApRegistration(); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); + mStateMachineSoftApCallback.onStateChanged( + new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); + mStateMachineSoftApCallback.onStateChanged( + new SoftApState( + WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); mLooper.dispatchAll(); assertEquals(WifiManager.WIFI_AP_STATE_FAILED, mWifiServiceImpl.getWifiApEnabledState()); @@ -1903,7 +1943,6 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mWifiConfigManager).loadFromStore(); verify(mActiveModeWarden).start(); verify(mActiveModeWarden, never()).wifiToggled(any()); - verify(mWifiDeviceStateChangeManager).handleBootCompleted(); } @Test @@ -1935,7 +1974,6 @@ public class WifiServiceImplTest extends WifiBaseTest { mLooper.dispatchAll(); verify(mWifiConfigManager).loadFromStore(); verify(mActiveModeWarden).start(); - verify(mWifiDeviceStateChangeManager).handleBootCompleted(); } @Test @@ -1959,6 +1997,7 @@ public class WifiServiceImplTest extends WifiBaseTest { @Test public void testSetPulledAtomCallbacks() { mWifiServiceImpl.checkAndStartWifi(); + mWifiServiceImpl.handleBootCompleted(); mLooper.dispatchAll(); verify(mWifiPulledAtomLogger).setPullAtomCallback(WifiStatsLog.WIFI_MODULE_INFO); verify(mWifiPulledAtomLogger).setPullAtomCallback(WifiStatsLog.WIFI_SETTING_INFO); @@ -2093,6 +2132,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertNull(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2124,6 +2164,7 @@ public class WifiServiceImplTest extends WifiBaseTest { WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( config, mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); verify(mLastCallerInfoManager).put(eq(WifiManager.API_SOFT_AP), anyInt(), anyInt(), anyInt(), anyString(), eq(true)); } @@ -2161,6 +2202,7 @@ public class WifiServiceImplTest extends WifiBaseTest { WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( config, mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); verify(mContext).enforceCallingOrSelfPermission( eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); } @@ -2186,6 +2228,7 @@ public class WifiServiceImplTest extends WifiBaseTest { WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( config, mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2198,6 +2241,73 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertNull(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); + verify(mLastCallerInfoManager).put(eq(WifiManager.API_TETHERED_HOTSPOT), anyInt(), + anyInt(), anyInt(), anyString(), eq(true)); + } + + /** + * Verify a SecurityException is thrown when a caller without the correct permission attempts to + * call startTetheredHotspotRequest(). + */ + @Test(expected = SecurityException.class) + public void testStartTetheredHotspotRequestWithoutPermissionThrowsException() throws Exception { + when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK)) + .thenReturn(PackageManager.PERMISSION_DENIED); + doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( + eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); + mLooper.startAutoDispatch(); + TetheringManager.TetheringRequest request = new TetheringManager.TetheringRequest.Builder( + TetheringManager.TETHERING_WIFI).build(); + mWifiServiceImpl.startTetheredHotspotRequest(request, TEST_PACKAGE_NAME); + mLooper.stopAutoDispatchAndIgnoreExceptions(); + } + + /** + * Verify that startTetheredHotspotRequest() succeeds if the caller does not have the + * NETWORK_STACK permission but does have the MAINLINE_NETWORK_STACK permission. + */ + @Test + public void testStartTetheredHotspotRequestNetworkStackWithMainlineNetworkStackSucceeds() { + when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK)) + .thenReturn(PackageManager.PERMISSION_DENIED); + mLooper.startAutoDispatch(); + TetheringManager.TetheringRequest request = new TetheringManager.TetheringRequest.Builder( + TetheringManager.TETHERING_WIFI).build(); + boolean result = mWifiServiceImpl.startTetheredHotspotRequest(request, TEST_PACKAGE_NAME); + mLooper.stopAutoDispatchAndIgnoreExceptions(); + assertTrue(result); + verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), + eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); + assertThat(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()).isNull(); + assertThat(mSoftApModeConfigCaptor.getValue().getTetheringRequest()).isEqualTo(request); + verify(mContext).enforceCallingOrSelfPermission( + eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); + } + + /** + * Verify startTetheredHotspot fails with a null request. + */ + @Test(expected = IllegalArgumentException.class) + public void testStartTetheredHotspotNullRequestFails() { + mLooper.startAutoDispatch(); + mWifiServiceImpl.startTetheredHotspotRequest(null, TEST_PACKAGE_NAME); + mLooper.stopAutoDispatchAndIgnoreExceptions(); + } + + /** + * Verify caller with proper permission can call startTetheredHotspot from a TetheringRequest. + */ + @Test + public void testStartTetheredHotspotRequestWithPermissions() { + TetheringManager.TetheringRequest request = new TetheringManager.TetheringRequest.Builder( + TetheringManager.TETHERING_WIFI).build(); + boolean result = mWifiServiceImpl.startTetheredHotspotRequest(request, TEST_PACKAGE_NAME); + assertTrue(result); + verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), + eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); + assertNull(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertThat(mSoftApModeConfigCaptor.getValue().getTetheringRequest()).isEqualTo(request); verify(mLastCallerInfoManager).put(eq(WifiManager.API_TETHERED_HOTSPOT), anyInt(), anyInt(), anyInt(), anyString(), eq(true)); } @@ -2224,6 +2334,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2426,6 +2537,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2484,6 +2596,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2543,6 +2656,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2601,6 +2715,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2635,6 +2750,7 @@ public class WifiServiceImplTest extends WifiBaseTest { .setBand(SoftApConfiguration.BAND_60GHZ) .build(); boolean result = mWifiServiceImpl.startTetheredHotspot(config, TEST_PACKAGE_NAME); + assertFalse(result); verify(mActiveModeWarden, never()).startSoftAp(any(), any()); } @@ -2657,6 +2773,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2688,6 +2805,7 @@ public class WifiServiceImplTest extends WifiBaseTest { assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); verify(mContext).enforceCallingOrSelfPermission( eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -2704,6 +2822,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertNull(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -3360,6 +3479,7 @@ public class WifiServiceImplTest extends WifiBaseTest { public void testStartLocalOnlyHotspotSingleRegistrationReturnsRequestRegistered() { registerLOHSRequestFull(); verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), any()); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); } /** @@ -3459,7 +3579,10 @@ public class WifiServiceImplTest extends WifiBaseTest { WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( config, mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); + mStateMachineSoftApCallback.onStateChanged( + new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); mLooper.dispatchAll(); assertEquals(WIFI_AP_STATE_ENABLED, mWifiServiceImpl.getWifiApEnabledState()); @@ -3484,7 +3607,10 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture(), eq(new WorkSource(Binder.getCallingUid(), TEST_PACKAGE_NAME))); assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + assertNull(mSoftApModeConfigCaptor.getValue().getTetheringRequest()); + mStateMachineSoftApCallback.onStateChanged( + new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); mLooper.dispatchAll(); assertEquals(WIFI_AP_STATE_ENABLED, mWifiServiceImpl.getWifiApEnabledState()); @@ -3504,7 +3630,9 @@ public class WifiServiceImplTest extends WifiBaseTest { WifiConfiguration config = createValidWifiApConfiguration(); mLooper.startAutoDispatch(); assertTrue(mWifiServiceImpl.startSoftAp(config, TEST_PACKAGE_NAME)); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + mStateMachineSoftApCallback.onStateChanged( + new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME)); mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); mLooper.stopAutoDispatchAndIgnoreExceptions(); @@ -3917,7 +4045,7 @@ public class WifiServiceImplTest extends WifiBaseTest { .when(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); mWifiServiceImpl.registerSoftApCallback(mClientSoftApCallback); mLooper.dispatchAll(); - verify(mClientSoftApCallback, never()).onStateChanged(WIFI_AP_STATE_DISABLED, 0); + verify(mClientSoftApCallback, never()).onStateChanged(any()); verify(mClientSoftApCallback, never()).onConnectedClientsOrInfoChanged( any(), any(), anyBoolean(), anyBoolean()); verify(mClientSoftApCallback, never()).onCapabilityChanged(any()); @@ -3930,7 +4058,8 @@ public class WifiServiceImplTest extends WifiBaseTest { private void registerSoftApCallbackAndVerify(ISoftApCallback callback) throws Exception { mWifiServiceImpl.registerSoftApCallback(callback); mLooper.dispatchAll(); - verify(callback).onStateChanged(WIFI_AP_STATE_DISABLED, 0); + verify(callback).onStateChanged( + eq(new SoftApState(WIFI_AP_STATE_DISABLED, 0, null, null))); verify(callback).onConnectedClientsOrInfoChanged(new HashMap<String, SoftApInfo>(), new HashMap<String, List<WifiClient>>(), false, true); verify(callback).onCapabilityChanged(ApConfigUtil.updateCapabilityFromResource(mContext)); @@ -3986,7 +4115,9 @@ public class WifiServiceImplTest extends WifiBaseTest { reset(mClientSoftApCallback); when(mClientSoftApCallback.asBinder()).thenReturn(mAppBinder); // Change state from default before registering the second callback - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + SoftApState state = new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME); + mStateMachineSoftApCallback.onStateChanged(state); mStateMachineSoftApCallback.onConnectedClientsOrInfoChanged( mTestSoftApInfos, mTestSoftApClients, false); mStateMachineSoftApCallback.onBlockedClientConnecting(testWifiClient, 0); @@ -3995,7 +4126,7 @@ public class WifiServiceImplTest extends WifiBaseTest { // Register another callback and verify the new state is returned in the immediate callback mWifiServiceImpl.registerSoftApCallback(mAnotherSoftApCallback); mLooper.dispatchAll(); - verify(mAnotherSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); + verify(mAnotherSoftApCallback).onStateChanged(eq(state)); verify(mAnotherSoftApCallback).onConnectedClientsOrInfoChanged( eq(mTestSoftApInfos), eq(mTestSoftApClients), eq(false), eq(true)); // Verify only first callback will receive onBlockedClientConnecting since it call after @@ -4008,13 +4139,13 @@ public class WifiServiceImplTest extends WifiBaseTest { mLooper.dispatchAll(); // Update soft AP state and verify the remaining callback receives the event - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_FAILED, - SAP_START_FAILURE_NO_CHANNEL); + state = new SoftApState( + WIFI_AP_STATE_FAILED, SAP_START_FAILURE_NO_CHANNEL, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME); + mStateMachineSoftApCallback.onStateChanged(state); mLooper.dispatchAll(); - verify(mClientSoftApCallback, never()).onStateChanged(WIFI_AP_STATE_FAILED, - SAP_START_FAILURE_NO_CHANNEL); - verify(mAnotherSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, - SAP_START_FAILURE_NO_CHANNEL); + verify(mClientSoftApCallback, never()).onStateChanged(eq(state)); + verify(mAnotherSoftApCallback).onStateChanged(eq(state)); } /** @@ -4070,9 +4201,12 @@ public class WifiServiceImplTest extends WifiBaseTest { public void callsRegisteredCallbacksOnSoftApStateChangedEvent() throws Exception { registerSoftApCallbackAndVerify(mClientSoftApCallback); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + SoftApState state = new SoftApState( + WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME); + mStateMachineSoftApCallback.onStateChanged(state); mLooper.dispatchAll(); - verify(mClientSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); + verify(mClientSoftApCallback).onStateChanged(eq(state)); } /** @@ -4083,7 +4217,9 @@ public class WifiServiceImplTest extends WifiBaseTest { public void updatesSoftApStateAndConnectedClientsOnSoftApEvents() throws Exception { WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77"), WIFI_IFACE_NAME2); - mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + SoftApState state = new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME); + mStateMachineSoftApCallback.onStateChanged(state); mStateMachineSoftApCallback.onConnectedClientsOrInfoChanged( mTestSoftApInfos, mTestSoftApClients, false); mStateMachineSoftApCallback.onBlockedClientConnecting(testWifiClient, 0); @@ -4091,7 +4227,7 @@ public class WifiServiceImplTest extends WifiBaseTest { // Register callback after num clients and soft AP are changed. mWifiServiceImpl.registerSoftApCallback(mClientSoftApCallback); mLooper.dispatchAll(); - verify(mClientSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); + verify(mClientSoftApCallback).onStateChanged(eq(state)); verify(mClientSoftApCallback).onConnectedClientsOrInfoChanged( eq(mTestSoftApInfos), eq(mTestSoftApClients), eq(false), eq(true)); // Don't need to invoke callback when register. @@ -5142,11 +5278,11 @@ public class WifiServiceImplTest extends WifiBaseTest { public void testConnectNetworkWithoutPrivilegedPermission() throws Exception { try { mWifiServiceImpl.connect(mock(WifiConfiguration.class), TEST_NETWORK_ID, - mock(IActionListener.class), TEST_PACKAGE_NAME); + mock(IActionListener.class), TEST_PACKAGE_NAME, mExtras); fail(); } catch (SecurityException e) { mLooper.dispatchAll(); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); } } @@ -5196,11 +5332,11 @@ public class WifiServiceImplTest extends WifiBaseTest { config.SSID = TEST_SSID; when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(config); mWifiServiceImpl.connect(config, TEST_NETWORK_ID, mock(IActionListener.class), - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt()); verify(mConnectHelper).connectToNetwork(any(NetworkUpdateResult.class), - any(ActionListenerWrapper.class), anyInt(), any()); + any(ActionListenerWrapper.class), anyInt(), any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK), anyInt()); verify(mLastCallerInfoManager).put(eq(WifiManager.API_CONNECT_CONFIG), anyInt(), @@ -5241,7 +5377,7 @@ public class WifiServiceImplTest extends WifiBaseTest { // Verify that the secondary internet CMM is stopped when manual connection is started mWifiServiceImpl.connect( - config, TEST_NETWORK_ID, mock(IActionListener.class), TEST_PACKAGE_NAME); + config, TEST_NETWORK_ID, mock(IActionListener.class), TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); verify(primaryCmm, never()).stop(); verify(secondaryInternetCmm).stop(); @@ -5280,13 +5416,13 @@ public class WifiServiceImplTest extends WifiBaseTest { // Verify that the localOnlyCmm is not stopped since security type is different mWifiServiceImpl.connect(config, TEST_NETWORK_ID, mock(IActionListener.class), - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); verify(primaryCmm, never()).stop(); verify(localOnlyCmm, never()).stop(); verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt()); verify(mConnectHelper).connectToNetwork(any(NetworkUpdateResult.class), - any(ActionListenerWrapper.class), anyInt(), any()); + any(ActionListenerWrapper.class), anyInt(), any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK), anyInt()); @@ -5296,13 +5432,13 @@ public class WifiServiceImplTest extends WifiBaseTest { // Verify that the localOnlyCmm is stopped this time mWifiServiceImpl.connect(config, TEST_NETWORK_ID, mock(IActionListener.class), - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); verify(primaryCmm, never()).stop(); verify(localOnlyCmm).stop(); verify(mWifiConfigManager, times(2)).addOrUpdateNetwork(eq(config), anyInt()); verify(mConnectHelper, times(2)).connectToNetwork(any(NetworkUpdateResult.class), - any(ActionListenerWrapper.class), anyInt(), any()); + any(ActionListenerWrapper.class), anyInt(), any(), any()); verify(mWifiMetrics, times(2)).logUserActionEvent( eq(UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK), anyInt()); } @@ -5318,7 +5454,7 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(mWifiConfig); mWifiServiceImpl.connect(mWifiConfig, WifiConfiguration.INVALID_NETWORK_ID, - mActionListener, TEST_PACKAGE_NAME); + mActionListener, TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); ArgumentCaptor<WifiConfiguration> configCaptor = @@ -5326,7 +5462,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mWifiConfigManager).addOrUpdateNetwork(configCaptor.capture(), anyInt()); assertThat(configCaptor.getValue().networkId).isEqualTo(TEST_NETWORK_ID); - verify(mConnectHelper).connectToNetwork(eq(result), any(), anyInt(), any()); + verify(mConnectHelper).connectToNetwork(eq(result), any(), anyInt(), any(), any()); verify(mContextAsUser).sendBroadcastWithMultiplePermissions( mIntentCaptor.capture(), aryEq(new String[]{ @@ -5351,12 +5487,12 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); mWifiServiceImpl.connect(mWifiConfig, WifiConfiguration.INVALID_NETWORK_ID, - mActionListener, TEST_PACKAGE_NAME); + mActionListener, TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); verify(mWifiConfigManager).addOrUpdateNetwork(eq(mWifiConfig), anyInt()); - verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any()); + verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any(), any()); verify(mContextAsUser, never()).sendBroadcastWithMultiplePermissions(any(), any()); verify(mActionListener).onFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR); verify(mActionListener, never()).onSuccess(); @@ -5370,13 +5506,14 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(mWifiConfig); - mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME); + mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME, + mExtras); mLooper.dispatchAll(); verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt()); verify(mConnectHelper).connectToNetwork( - eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any()); + eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any(), any()); verify(mContextAsUser, never()).sendBroadcastWithMultiplePermissions(any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_MANUAL_CONNECT), anyInt()); verify(mLastCallerInfoManager).put(eq(WifiManager.API_CONNECT_NETWORK_ID), anyInt(), @@ -5395,13 +5532,14 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any())).thenReturn(TEST_SUB_ID); when(mWifiCarrierInfoManager.isSimReady(TEST_SUB_ID)).thenReturn(true); - mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME); + mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME, + mExtras); mLooper.dispatchAll(); verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt()); verify(mConnectHelper).connectToNetwork( - eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any()); + eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any(), any()); verify(mContextAsUser, never()).sendBroadcastWithMultiplePermissions(any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_MANUAL_CONNECT), anyInt()); } @@ -5418,12 +5556,13 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any())).thenReturn(TEST_SUB_ID); when(mWifiCarrierInfoManager.isSimReady(TEST_SUB_ID)).thenReturn(false); - mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME); + mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME, + mExtras); mLooper.dispatchAll(); verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt()); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); verify(mContextAsUser, never()).sendBroadcastWithMultiplePermissions(any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_MANUAL_CONNECT), anyInt()); } @@ -5442,12 +5581,13 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiCarrierInfoManager.requiresImsiEncryption(TEST_SUB_ID)).thenReturn(true); when(mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(TEST_SUB_ID)).thenReturn(false); - mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME); + mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME, + mExtras); mLooper.dispatchAll(); verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt()); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); verify(mContextAsUser, never()).sendBroadcastWithMultiplePermissions(any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_MANUAL_CONNECT), anyInt()); } @@ -5466,13 +5606,14 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(anyInt())).thenReturn(true); when(mWifiPseudonymManager.getValidPseudonymInfo(anyInt())).thenReturn(Optional.empty()); - mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME); + mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME, + mExtras); mLooper.dispatchAll(); verify(mWifiPseudonymManager).retrievePseudonymOnFailureTimeoutExpired(any()); verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt()); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); verify(mContextAsUser, never()).sendBroadcastWithMultiplePermissions(any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_MANUAL_CONNECT), anyInt()); } @@ -5492,12 +5633,13 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiPseudonymManager.getValidPseudonymInfo(anyInt())) .thenReturn(Optional.of(mock(PseudonymInfo.class))); - mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME); + mWifiServiceImpl.connect(null, TEST_NETWORK_ID, mActionListener, TEST_PACKAGE_NAME, + mExtras); mLooper.dispatchAll(); verify(mWifiPseudonymManager).updateWifiConfiguration(any()); verify(mConnectHelper).connectToNetwork( - eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any()); + eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any(), any()); verify(mContextAsUser, never()).sendBroadcastWithMultiplePermissions(any(), any()); verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_MANUAL_CONNECT), anyInt()); } @@ -5518,7 +5660,7 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiPermissionsUtil.isAdminRestrictedNetwork(mWifiConfig)).thenReturn(true); mWifiServiceImpl.connect(mWifiConfig, WifiConfiguration.INVALID_NETWORK_ID, - mActionListener, TEST_PACKAGE_NAME); + mActionListener, TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); ArgumentCaptor<WifiConfiguration> configCaptor = @@ -5527,7 +5669,7 @@ public class WifiServiceImplTest extends WifiBaseTest { assertThat(configCaptor.getValue().networkId).isEqualTo(TEST_NETWORK_ID); verify(mWifiConfigManager).addOrUpdateNetwork(eq(mWifiConfig), anyInt()); - verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any()); + verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any(), any()); verify(mActionListener).onFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR); verify(mActionListener, never()).onSuccess(); } @@ -5723,7 +5865,7 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiGlobals.isDeprecatedSecurityTypeNetwork(mWifiConfig)).thenReturn(false); mWifiServiceImpl.connect(mWifiConfig, WifiConfiguration.INVALID_NETWORK_ID, - mActionListener, TEST_PACKAGE_NAME); + mActionListener, TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); ArgumentCaptor<WifiConfiguration> configCaptor = @@ -5731,7 +5873,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mWifiConfigManager).addOrUpdateNetwork(configCaptor.capture(), anyInt()); assertThat(configCaptor.getValue().networkId).isEqualTo(TEST_NETWORK_ID); - verify(mConnectHelper).connectToNetwork(eq(result), any(), anyInt(), any()); + verify(mConnectHelper).connectToNetwork(eq(result), any(), anyInt(), any(), any()); } /** @@ -5750,7 +5892,7 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mWifiGlobals.isDeprecatedSecurityTypeNetwork(mWifiConfig)).thenReturn(true); mWifiServiceImpl.connect(mWifiConfig, WifiConfiguration.INVALID_NETWORK_ID, - mActionListener, TEST_PACKAGE_NAME); + mActionListener, TEST_PACKAGE_NAME, mExtras); mLooper.dispatchAll(); ArgumentCaptor<WifiConfiguration> configCaptor = @@ -5759,7 +5901,7 @@ public class WifiServiceImplTest extends WifiBaseTest { assertThat(configCaptor.getValue().networkId).isEqualTo(TEST_NETWORK_ID); verify(mWifiConfigManager).addOrUpdateNetwork(eq(mWifiConfig), anyInt()); - verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any()); + verify(mClientModeManager, never()).connectNetwork(any(), any(), anyInt(), any(), any()); verify(mActionListener).onFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR); verify(mActionListener, never()).onSuccess(); } @@ -6695,38 +6837,6 @@ public class WifiServiceImplTest extends WifiBaseTest { } /** - * Verify that add or update networks is allowed for apps holding system alert permission. - */ - @Test - public void testAddOrUpdateNetworkIsAllowedForAppsWithSystemAlertPermission() throws Exception { - doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) - .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); - when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any(), eq(false))).thenReturn( - new NetworkUpdateResult(0)); - - // Verify caller fails to add network as Guest user. - when(mWifiPermissionsUtil.checkSystemAlertWindowPermission( - Process.myUid(), TEST_PACKAGE_NAME)).thenReturn(true); - when(mWifiPermissionsUtil.isGuestUser()).thenReturn(true); - WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); - mLooper.startAutoDispatch(); - assertEquals(-1, - mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME, mAttribution)); - - // Verify caller successfully add network when not a Guest user. - when(mWifiPermissionsUtil.isGuestUser()).thenReturn(false); - assertEquals(0, - mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME, mAttribution)); - mLooper.stopAutoDispatchAndIgnoreExceptions(); - - verifyCheckChangePermission(TEST_PACKAGE_NAME); - verify(mWifiPermissionsUtil, times(2)) - .checkSystemAlertWindowPermission(anyInt(), anyString()); - verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), any(), eq(false)); - verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); - } - - /** * Verify that add or update networks is allowed for DeviceOwner app. */ @Test @@ -6888,18 +6998,18 @@ public class WifiServiceImplTest extends WifiBaseTest { doAnswer(new AnswerWithArguments() { public void answer(NetworkUpdateResult result, ActionListenerWrapper callback, - int callingUid, String packageName) { + int callingUid, String packageName, String attributionTag) { callback.sendSuccess(); // return success } }).when(mConnectHelper).connectToNetwork( - eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any()); + eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any(), any()); mLooper.startAutoDispatch(); assertTrue(mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME)); mLooper.stopAutoDispatch(); verify(mConnectHelper).connectToNetwork( - eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any()); + eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any(), any()); verify(mWifiMetrics).incrementNumEnableNetworkCalls(); verify(mLastCallerInfoManager).put(eq(WifiManager.API_ENABLE_NETWORK), anyInt(), anyInt(), anyInt(), anyString(), eq(true)); @@ -6920,18 +7030,18 @@ public class WifiServiceImplTest extends WifiBaseTest { doAnswer(new AnswerWithArguments() { public void answer(NetworkUpdateResult result, ActionListenerWrapper callback, - int callingUid, String packageName) { + int callingUid, String packageName, String attributionTag) { callback.sendSuccess(); // return success } }).when(mConnectHelper).connectToNetwork( - eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any()); + eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any(), any()); mLooper.startAutoDispatch(); assertTrue(mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME)); mLooper.stopAutoDispatch(); verify(mConnectHelper).connectToNetwork( - eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any()); + eq(new NetworkUpdateResult(TEST_NETWORK_ID)), any(), anyInt(), any(), any()); verify(mWifiMetrics).incrementNumEnableNetworkCalls(); } @@ -6970,7 +7080,7 @@ public class WifiServiceImplTest extends WifiBaseTest { mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME); mLooper.stopAutoDispatchAndIgnoreExceptions(); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); verify(mWifiMetrics, never()).incrementNumEnableNetworkCalls(); } @@ -6991,7 +7101,7 @@ public class WifiServiceImplTest extends WifiBaseTest { mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME); mLooper.stopAutoDispatchAndIgnoreExceptions(); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); verify(mWifiMetrics, never()).incrementNumEnableNetworkCalls(); } @@ -7011,7 +7121,7 @@ public class WifiServiceImplTest extends WifiBaseTest { mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME); mLooper.stopAutoDispatchAndIgnoreExceptions(); - verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any()); + verify(mConnectHelper, never()).connectToNetwork(any(), any(), anyInt(), any(), any()); verify(mWifiMetrics, never()).incrementNumEnableNetworkCalls(); } @@ -8455,6 +8565,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mPasspointManager).initializeProvisioner(any()); verify(mWifiP2pConnection).handleBootCompleted(); verify(mWifiCountryCode).registerListener(any(WifiCountryCode.ChangeListener.class)); + verify(mWifiDeviceStateChangeManager).handleBootCompleted(); } /** @@ -8688,6 +8799,16 @@ public class WifiServiceImplTest extends WifiBaseTest { validateWifiActivityEnergyInfo(infoCaptor.getValue()); } + /** + * Tests that {@link WifiServiceImpl#getWifiActivityEnergyInfoAsync} throws exception when + * listener is null + */ + @Test + public void getWifiActivityEnergyInfoWithNullListener() throws Exception { + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.getWifiActivityEnergyInfoAsync(null)); + } + @Test public void testCarrierConfigChangeUpdateSoftApCapability() throws Exception { lenient().when(SubscriptionManager.getActiveDataSubscriptionId()) @@ -9130,8 +9251,18 @@ public class WifiServiceImplTest extends WifiBaseTest { } private List<ScanResult> createScanResultList() { - return Collections.singletonList(new ScanResult(WifiSsid.fromUtf8Text(TEST_SSID), - TEST_SSID, TEST_BSSID, 1245, 0, TEST_CAP, -78, 2450, 1025, 22, 33, 20, 0, 0, true)); + return Collections.singletonList(new ScanResult.Builder(WifiSsid.fromUtf8Text(TEST_SSID), + TEST_BSSID) + .setHessid(1245) + .setCaps(TEST_CAP) + .setRssi(-78) + .setFrequency(2450) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setChannelWidth(20) + .setIs80211McRTTResponder(true) + .build()); } private void sendCountryCodeChangedBroadcast(String countryCode) { @@ -9815,6 +9946,10 @@ public class WifiServiceImplTest extends WifiBaseTest { */ @Test public void testDriverCountryCodeChangedStoresAvailableSoftApChannels() throws Exception { + setup5GhzSupported(); + setup24GhzSupported(); + setup6GhzSupported(); + setup60GhzSupported(); mWifiServiceImpl.handleBootCompleted(); mLooper.dispatchAll(); when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); @@ -10208,6 +10343,7 @@ public class WifiServiceImplTest extends WifiBaseTest { @Test public void testSetExternalPnoScanRequest_Success() throws Exception { assumeTrue(SdkLevel.isAtLeastT()); + when(mWifiGlobals.isBackgroundScanSupported()).thenReturn(true); when(mActiveModeWarden.getSupportedFeatureSet()) .thenReturn(WifiManager.WIFI_FEATURE_PNO); when(mWifiPermissionsUtil.checkRequestCompanionProfileAutomotiveProjectionPermission( @@ -10464,7 +10600,18 @@ public class WifiServiceImplTest extends WifiBaseTest { throws Exception { mWifiServiceImpl.registerLocalOnlyHotspotSoftApCallback(mClientSoftApCallback, bundle); mLooper.dispatchAll(); - verify(mClientSoftApCallback).onStateChanged(WIFI_AP_STATE_DISABLED, 0); + + ArgumentCaptor<SoftApState> softApStateCaptor = + ArgumentCaptor.forClass(SoftApState.class); + verify(mClientSoftApCallback).onStateChanged(softApStateCaptor.capture()); + assertThat(softApStateCaptor.getValue().getState()).isEqualTo(WIFI_AP_STATE_DISABLED); + try { + softApStateCaptor.getValue().getFailureReason(); + fail("getFailureReason should throw if not in failure state"); + } catch (IllegalStateException e) { + // Pass. + } + assertThat(softApStateCaptor.getValue().getFailureReasonInternal()).isEqualTo(0); verify(mClientSoftApCallback).onConnectedClientsOrInfoChanged( new HashMap<String, SoftApInfo>(), new HashMap<String, List<WifiClient>>(), false, true); @@ -10528,7 +10675,9 @@ public class WifiServiceImplTest extends WifiBaseTest { reset(mClientSoftApCallback); when(mClientSoftApCallback.asBinder()).thenReturn(mAppBinder); // Change state from default before registering the second callback - mLohsApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); + SoftApState state = new SoftApState(WIFI_AP_STATE_ENABLED, 0, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME); + mLohsApCallback.onStateChanged(state); mLohsApCallback.onConnectedClientsOrInfoChanged( mTestSoftApInfos, mTestSoftApClients, false); mLohsApCallback.onBlockedClientConnecting(testWifiClient, 0); @@ -10537,7 +10686,7 @@ public class WifiServiceImplTest extends WifiBaseTest { // Register another callback and verify the new state is returned in the immediate callback mWifiServiceImpl.registerLocalOnlyHotspotSoftApCallback(mAnotherSoftApCallback, mExtras); mLooper.dispatchAll(); - verify(mAnotherSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); + verify(mAnotherSoftApCallback).onStateChanged(eq(state)); verify(mAnotherSoftApCallback).onConnectedClientsOrInfoChanged( eq(mTestSoftApInfos), eq(mTestSoftApClients), eq(false), eq(true)); // Verify only first callback will receive onBlockedClientConnecting since it call after @@ -10550,13 +10699,13 @@ public class WifiServiceImplTest extends WifiBaseTest { mLooper.dispatchAll(); // Update soft AP state and verify the remaining callback receives the event - mLohsApCallback.onStateChanged(WIFI_AP_STATE_FAILED, - SAP_START_FAILURE_NO_CHANNEL); + state = new SoftApState( + WIFI_AP_STATE_FAILED, SAP_START_FAILURE_NO_CHANNEL, + TEST_TETHERING_REQUEST, TEST_IFACE_NAME); + mLohsApCallback.onStateChanged(state); mLooper.dispatchAll(); - verify(mClientSoftApCallback, never()).onStateChanged(WIFI_AP_STATE_FAILED, - SAP_START_FAILURE_NO_CHANNEL); - verify(mAnotherSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, - SAP_START_FAILURE_NO_CHANNEL); + verify(mClientSoftApCallback, never()).onStateChanged(eq(state)); + verify(mAnotherSoftApCallback).onStateChanged(eq(state)); } /** @@ -10890,6 +11039,86 @@ public class WifiServiceImplTest extends WifiBaseTest { } /** + * Verify attribution passed to WifiManager#connect is parsed when there's a chain. + */ + @Test + public void testConnectAttribution_CorrectParsingWithChain() { + assumeTrue(SdkLevel.isAtLeastS()); + AttributionSource attributionSource = mock(AttributionSource.class); + when(attributionSource.checkCallingUid()).thenReturn(true); + when(attributionSource.isTrusted(any(Context.class))).thenReturn(true); + mAttribution.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, attributionSource); + mWifiServiceImpl = spy(mWifiServiceImpl); + lenient().when(mWifiServiceImpl.getMockableCallingUid()).thenReturn(Process.SYSTEM_UID); + when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt())) + .thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID)); + + when(attributionSource.getUid()).thenReturn(TEST_UID); + when(attributionSource.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(attributionSource.getAttributionTag()).thenReturn(TEST_FEATURE_ID); + AttributionSource originalCaller = mock(AttributionSource.class); + when(originalCaller.getUid()).thenReturn(OTHER_TEST_UID); + when(originalCaller.getPackageName()).thenReturn(TEST_PACKAGE_NAME_OTHER); + when(originalCaller.getAttributionTag()).thenReturn(TEST_FEATURE_ID_OTHER); + when(originalCaller.isTrusted(any(Context.class))).thenReturn(true); + when(attributionSource.getNext()).thenReturn(originalCaller); + + WifiConfiguration config = new WifiConfiguration(); + config.SSID = TEST_SSID; + when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(config); + mWifiServiceImpl.connect(config, TEST_NETWORK_ID, mock(IActionListener.class), + TEST_PACKAGE_NAME, mAttribution); + mLooper.dispatchAll(); + verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt()); + verify(mConnectHelper).connectToNetwork(any(NetworkUpdateResult.class), + any(ActionListenerWrapper.class), eq(OTHER_TEST_UID), eq(TEST_PACKAGE_NAME_OTHER), + eq(TEST_FEATURE_ID_OTHER)); + } + + /** + * Verify attribution passed to WifiManager#connect is parsed when there's a chain. + * However, if the call is not made from the system server then the attribution is ignored and + * the attribution is simply to the calling app as before. + */ + @Test + public void testConnectAttribution_CorrectParsingWithChainButNotFromSystemServer() { + assumeTrue(SdkLevel.isAtLeastS()); + AttributionSource attributionSource = mock(AttributionSource.class); + when(attributionSource.checkCallingUid()).thenReturn(true); + when(attributionSource.isTrusted(any(Context.class))).thenReturn(true); + mAttribution.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, attributionSource); + mWifiServiceImpl = spy(mWifiServiceImpl); + lenient().when(mWifiServiceImpl.getMockableCallingUid()).thenReturn(TEST_UID); + when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt())) + .thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID)); + + when(attributionSource.getUid()).thenReturn(TEST_UID); + when(attributionSource.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(attributionSource.getAttributionTag()).thenReturn(TEST_FEATURE_ID); + AttributionSource originalCaller = mock(AttributionSource.class); + when(originalCaller.getUid()).thenReturn(OTHER_TEST_UID); + when(originalCaller.getPackageName()).thenReturn(TEST_PACKAGE_NAME_OTHER); + when(originalCaller.getAttributionTag()).thenReturn(TEST_FEATURE_ID_OTHER); + when(originalCaller.isTrusted(any(Context.class))).thenReturn(true); + when(attributionSource.getNext()).thenReturn(originalCaller); + + WifiConfiguration config = new WifiConfiguration(); + config.SSID = TEST_SSID; + when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(config); + mWifiServiceImpl.connect(config, TEST_NETWORK_ID, mock(IActionListener.class), + TEST_PACKAGE_NAME, mAttribution); + mLooper.dispatchAll(); + verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt()); + verify(mConnectHelper).connectToNetwork(any(NetworkUpdateResult.class), + any(ActionListenerWrapper.class), eq(TEST_UID), eq(TEST_PACKAGE_NAME), + eq(TEST_FEATURE_ID)); + } + + /** * Test that notifyWifiSsidPolicyChanged disconnects the current network * due to SSID allowlist restriction */ @@ -11183,6 +11412,8 @@ public class WifiServiceImplTest extends WifiBaseTest { // The supported channels in soft AP capability got invalidated. assertEquals(0, capabilityArgumentCaptor.getValue() .getSupportedChannelList(SoftApConfiguration.BAND_2GHZ).length); + verify(mWifiNative, times(2)).getUsableChannels(eq(WifiScanner.WIFI_BAND_24_GHZ), anyInt(), + anyInt()); } /** @@ -11380,18 +11611,51 @@ public class WifiServiceImplTest extends WifiBaseTest { private List<ScanResult> createChannelDataScanResults() { List<ScanResult> scanResults = new ArrayList<>(); - scanResults.add( - new ScanResult(WifiSsid.fromUtf8Text(TEST_SSID), TEST_SSID, TEST_BSSID, 1234, 0, - TEST_CAP, -78, 2412, 1024, 22, 33, 20, 0, 0, true)); - scanResults.add( - new ScanResult(WifiSsid.fromUtf8Text(TEST_SSID), TEST_SSID, TEST_BSSID, 1234, 0, - TEST_CAP, -85, 2417, 1024, 22, 33, 20, 0, 0, true)); - scanResults.add( - new ScanResult(WifiSsid.fromUtf8Text(TEST_SSID), TEST_SSID, TEST_BSSID, 1234, 0, - TEST_CAP, -60, 5805, 1024, 22, 33, 20, 0, 0, true)); - scanResults.add( - new ScanResult(WifiSsid.fromUtf8Text(TEST_SSID), TEST_SSID, TEST_BSSID, 1234, 0, - TEST_CAP, -70, 5805, 1024, 22, 33, 20, 0, 0, true)); + + scanResults.add(new ScanResult.Builder(WifiSsid.fromUtf8Text(TEST_SSID), TEST_BSSID) + .setHessid(1245) + .setCaps(TEST_CAP) + .setRssi(-78) + .setFrequency(2412) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setChannelWidth(20) + .setIs80211McRTTResponder(true) + .build()); + scanResults.add(new ScanResult.Builder(WifiSsid.fromUtf8Text(TEST_SSID), TEST_BSSID) + .setHessid(1245) + .setCaps(TEST_CAP) + .setRssi(-85) + .setFrequency(2417) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setChannelWidth(20) + .setIs80211McRTTResponder(true) + .build()); + scanResults.add(new ScanResult.Builder(WifiSsid.fromUtf8Text(TEST_SSID), TEST_BSSID) + .setHessid(1245) + .setCaps(TEST_CAP) + .setRssi(-60) + .setFrequency(5805) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setChannelWidth(20) + .setIs80211McRTTResponder(true) + .build()); + scanResults.add(new ScanResult.Builder(WifiSsid.fromUtf8Text(TEST_SSID), TEST_BSSID) + .setHessid(1245) + .setCaps(TEST_CAP) + .setRssi(-70) + .setFrequency(5805) + .setTsf(1025) + .setDistanceCm(22) + .setDistanceSdCm(33) + .setChannelWidth(20) + .setIs80211McRTTResponder(true) + .build()); return scanResults; } @@ -11402,7 +11666,7 @@ public class WifiServiceImplTest extends WifiBaseTest { .thenReturn(true); } - private List<QosPolicyParams> createQosPolicyParamsList(int size, boolean uniqueIds) { + private List<QosPolicyParams> createDownlinkQosPolicyParamsList(int size, boolean uniqueIds) { List<QosPolicyParams> policyParamsList = new ArrayList<>(); for (int i = 0; i < size; i++) { int policyId = uniqueIds ? i + 2 : 5; @@ -11415,6 +11679,22 @@ public class WifiServiceImplTest extends WifiBaseTest { return policyParamsList; } + private static List<QosPolicyParams> createUplinkQosPolicyParamsList(int size) { + List<QosPolicyParams> policyParamsList = new ArrayList<>(); + QosCharacteristics mockQosCharacteristics = mock(QosCharacteristics.class); + when(mockQosCharacteristics.validate()).thenReturn(true); + + for (int i = 0; i < size; i++) { + int policyId = i + 2; + policyParamsList.add(new QosPolicyParams.Builder( + policyId, QosPolicyParams.DIRECTION_UPLINK) + .setQosCharacteristics(mockQosCharacteristics) + .build()); + } + + return policyParamsList; + } + /** * Verify that addQosPolicies works correctly. */ @@ -11423,14 +11703,28 @@ public class WifiServiceImplTest extends WifiBaseTest { assumeTrue(SdkLevel.isAtLeastU()); enableQosPolicyFeature(); - List<QosPolicyParams> paramsList = createQosPolicyParamsList(5, true); + ConcreteClientModeManager primaryCmm = mock(ConcreteClientModeManager.class); + when(primaryCmm.isWifiStandardSupported(anyInt())).thenReturn(true); + when(mActiveModeWarden.getPrimaryClientModeManager()).thenReturn(primaryCmm); + mLooper.startAutoDispatch(); // handles call to isWifiStandardSupported + + List<QosPolicyParams> paramsList = createDownlinkQosPolicyParamsList(5, true); IBinder binder = mock(IBinder.class); IListListener listener = mock(IListListener.class); mWifiServiceImpl.addQosPolicies(paramsList, binder, TEST_PACKAGE_NAME, listener); + int expectedNumCalls = 1; + + if (SdkLevel.isAtLeastV()) { + // Uplink policies are supported on SDK >= V + paramsList = createUplinkQosPolicyParamsList(5); + mWifiServiceImpl.addQosPolicies(paramsList, binder, TEST_PACKAGE_NAME, listener); + expectedNumCalls += 1; + } mLooper.dispatchAll(); - verify(mApplicationQosPolicyRequestHandler).queueAddRequest( + verify(mApplicationQosPolicyRequestHandler, times(expectedNumCalls)).queueAddRequest( anyList(), any(), any(), anyInt()); + mLooper.stopAutoDispatchAndIgnoreExceptions(); } /** @@ -11440,7 +11734,7 @@ public class WifiServiceImplTest extends WifiBaseTest { public void testAddQosPoliciesError() throws RemoteException { assumeTrue(SdkLevel.isAtLeastU()); enableQosPolicyFeature(); - List<QosPolicyParams> paramsList = createQosPolicyParamsList(5, true); + List<QosPolicyParams> paramsList = createDownlinkQosPolicyParamsList(5, true); IBinder binder = mock(IBinder.class); IListListener listener = mock(IListListener.class); @@ -11464,25 +11758,32 @@ public class WifiServiceImplTest extends WifiBaseTest { mWifiServiceImpl.addQosPolicies(paramsList, binder, TEST_PACKAGE_NAME, null)); // Invalid QoS policy params list - List<QosPolicyParams> emptyList = createQosPolicyParamsList(0, true); - List<QosPolicyParams> largeList = createQosPolicyParamsList( + List<QosPolicyParams> emptyList = createDownlinkQosPolicyParamsList(0, true); + List<QosPolicyParams> largeList = createDownlinkQosPolicyParamsList( WifiManager.getMaxNumberOfPoliciesPerQosRequest() + 1, true); - List<QosPolicyParams> duplicatePolicyList = createQosPolicyParamsList(5, false); - List<QosPolicyParams> mixedDirectionList = createQosPolicyParamsList(1, true); - mixedDirectionList.add( - new QosPolicyParams.Builder(101, QosPolicyParams.DIRECTION_UPLINK) - .setDscp(15) - .build()); + List<QosPolicyParams> duplicatePolicyList = createDownlinkQosPolicyParamsList(5, false); assertThrows(IllegalArgumentException.class, () -> - mWifiServiceImpl.addQosPolicies(emptyList, binder, TEST_PACKAGE_NAME, listener)); + mWifiServiceImpl.addQosPolicies(emptyList, binder, TEST_PACKAGE_NAME, + listener)); assertThrows(IllegalArgumentException.class, () -> - mWifiServiceImpl.addQosPolicies(largeList, binder, TEST_PACKAGE_NAME, listener)); + mWifiServiceImpl.addQosPolicies(largeList, binder, TEST_PACKAGE_NAME, + listener)); assertThrows(IllegalArgumentException.class, () -> mWifiServiceImpl.addQosPolicies( duplicatePolicyList, binder, TEST_PACKAGE_NAME, listener)); - assertThrows(IllegalArgumentException.class, () -> - mWifiServiceImpl.addQosPolicies( - mixedDirectionList, binder, TEST_PACKAGE_NAME, listener)); + + if (SdkLevel.isAtLeastV()) { + List<QosPolicyParams> mixedDirectionList = createDownlinkQosPolicyParamsList(1, true); + QosCharacteristics mockQosCharacteristics = mock(QosCharacteristics.class); + when(mockQosCharacteristics.validate()).thenReturn(true); + mixedDirectionList.add( + new QosPolicyParams.Builder(101, QosPolicyParams.DIRECTION_UPLINK) + .setQosCharacteristics(mockQosCharacteristics) + .build()); + assertThrows(IllegalArgumentException.class, () -> + mWifiServiceImpl.addQosPolicies( + mixedDirectionList, binder, TEST_PACKAGE_NAME, listener)); + } } /** @@ -11787,22 +12088,6 @@ public class WifiServiceImplTest extends WifiBaseTest { } /** - * Verify that Pno is supported. - */ - @Test - public void testIsPnoSupported() { - when(mWifiGlobals.isBackgroundScanSupported()).thenReturn(false); - assertFalse(mWifiServiceImpl.isPnoSupported()); - when(mActiveModeWarden.getSupportedFeatureSet()).thenReturn(0L); - assertFalse(mWifiServiceImpl.isPnoSupported()); - - when(mActiveModeWarden.getSupportedFeatureSet()).thenReturn(WifiManager.WIFI_FEATURE_PNO); - assertTrue(mWifiServiceImpl.isPnoSupported()); - when(mWifiGlobals.isBackgroundScanSupported()).thenReturn(true); - assertTrue(mWifiServiceImpl.isPnoSupported()); - } - - /** * Verify that on a country code change, we inform the AFC Manager. */ @Test @@ -11845,17 +12130,34 @@ public class WifiServiceImplTest extends WifiBaseTest { mLooper.dispatchAll(); verify(mWifiSettingsConfigStore).get(eq(WIFI_WEP_ALLOWED)); verify(mWifiGlobals).setWepAllowed(eq(false)); - // verify setWepAllowed with MANAGE_WIFI_NETWORK_SELECTION + // verify setWepAllowed with MANAGE_WIFI_NETWORK_SETTING when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); mWifiServiceImpl.setWepAllowed(true); mLooper.dispatchAll(); verify(mWifiGlobals).setWepAllowed(true); verify(mWifiSettingsConfigStore).put(eq(WIFI_WEP_ALLOWED), eq(true)); + } + @Test + public void testSetWepDisAllowedWithPermission() { + when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); + ConcreteClientModeManager cmmWep = mock(ConcreteClientModeManager.class); + ConcreteClientModeManager cmmWpa = mock(ConcreteClientModeManager.class); + WifiInfo mockWifiInfoWep = mock(WifiInfo.class); + WifiInfo mockWifiInfoWpa = mock(WifiInfo.class); + List<ClientModeManager> cmms = Arrays.asList(cmmWep, cmmWpa); + when(mActiveModeWarden.getClientModeManagers()).thenReturn(cmms); + when(mockWifiInfoWep.getCurrentSecurityType()).thenReturn(WifiInfo.SECURITY_TYPE_WEP); + when(mockWifiInfoWpa.getCurrentSecurityType()).thenReturn(WifiInfo.SECURITY_TYPE_PSK); + when(cmmWep.getConnectionInfo()).thenReturn(mockWifiInfoWep); + when(cmmWpa.getConnectionInfo()).thenReturn(mockWifiInfoWpa); mWifiServiceImpl.setWepAllowed(false); mLooper.dispatchAll(); - verify(mWifiGlobals, times(2)).setWepAllowed(false); + verify(mWifiGlobals).setWepAllowed(false); verify(mWifiSettingsConfigStore).put(eq(WIFI_WEP_ALLOWED), eq(false)); + // Only WEP disconnect + verify(cmmWep).disconnect(); + verify(cmmWpa, never()).disconnect(); } @Test @@ -11891,4 +12193,488 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mWifiSettingsConfigStore, times(3)).get(eq(WIFI_WEP_ALLOWED)); inOrder.verify(listener).onResult(false); } + + @Test + public void testEnableAndDisableMscsSuccess() { + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(true); + when(mActiveModeWarden.getInternetConnectivityClientModeManagers()) + .thenReturn(Arrays.asList(mClientModeManager)); + when(mClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME); + + // Test enableMscs + MscsParams mscsParams = new MscsParams.Builder().build(); + mWifiServiceImpl.enableMscs(mscsParams); + mLooper.dispatchAll(); + verify(mWifiNative).enableMscs(eq(mscsParams), eq(WIFI_IFACE_NAME)); + + // Test disableMscs + mWifiServiceImpl.disableMscs(); + mLooper.dispatchAll(); + verify(mWifiNative).disableMscs(eq(WIFI_IFACE_NAME)); + } + + @Test + public void testEnableAndDisableMscsFailure() { + // Verify the permissions check on both methods + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(false); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.enableMscs(mock(MscsParams.class))); + assertThrows(SecurityException.class, () -> mWifiServiceImpl.disableMscs()); + + // Verify the nullity check on enableMscs + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(true); + assertThrows(NullPointerException.class, () -> mWifiServiceImpl.enableMscs(null)); + } + + @Test(expected = SecurityException.class) + public void testSetSendDhcpHostnameRestrictionWithoutPermission() { + // by default no permissions are given so the call should fail. + mWifiServiceImpl.setSendDhcpHostnameRestriction( + TEST_PACKAGE_NAME, WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetSendDhcpHostnameRestrictionInvalidFlags() { + when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + mWifiServiceImpl.setSendDhcpHostnameRestriction( + TEST_PACKAGE_NAME, -1); + } + + @Test + public void testSetSendDhcpHostnameRestrictionWithPermission() { + // verify setSendDhcpHostnameRestriction with NETWORK_SETTINGS + when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + mWifiServiceImpl.setSendDhcpHostnameRestriction( + TEST_PACKAGE_NAME, WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN); + mLooper.dispatchAll(); + verify(mWifiGlobals).setSendDhcpHostnameRestriction( + eq(WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN)); + } + + @Test + public void testQuerySendDhcpHostnameRestrictionExceptionCases() { + // null listener ==> IllegalArgumentException + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.querySendDhcpHostnameRestriction(TEST_PACKAGE_NAME, null)); + // by default no permissions are given so the call should fail. + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.querySendDhcpHostnameRestriction( + TEST_PACKAGE_NAME, mock(IIntegerListener.class))); + } + + @Test + public void testQuerySendDhcpHostnameRestrictionNormalCase() throws Exception { + when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + IIntegerListener listener = mock(IIntegerListener.class); + + InOrder inOrder = inOrder(listener); + when(mWifiGlobals.getSendDhcpHostnameRestriction()) + .thenReturn(0); + mWifiServiceImpl.querySendDhcpHostnameRestriction(TEST_PACKAGE_NAME, listener); + mLooper.dispatchAll(); + verify(mWifiGlobals).getSendDhcpHostnameRestriction(); + inOrder.verify(listener).onResult(0); + + when(mWifiGlobals.getSendDhcpHostnameRestriction()) + .thenReturn(WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN); + mWifiServiceImpl.querySendDhcpHostnameRestriction(TEST_PACKAGE_NAME, listener); + mLooper.dispatchAll(); + verify(mWifiGlobals, times(2)).getSendDhcpHostnameRestriction(); + inOrder.verify(listener).onResult(WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN); + } + + @Test + public void testSetPerSsidRoamingModeByDeviceAdmin() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + when(mActiveModeWarden.getSupportedFeatureSet()) + .thenReturn(WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.setPerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), + WifiManager.ROAMING_MODE_NORMAL, TEST_PACKAGE_NAME)); + when(mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin(anyInt(), + eq(TEST_PACKAGE_NAME))).thenReturn(true); + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.setPerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), -1, TEST_PACKAGE_NAME)); + + mWifiServiceImpl.setPerSsidRoamingMode(WifiSsid.fromString(TEST_SSID_WITH_QUOTES), + WifiManager.ROAMING_MODE_NORMAL, TEST_PACKAGE_NAME); + mLooper.dispatchAll(); + verify(mWifiRoamingModeManager).setPerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), + WifiManager.ROAMING_MODE_NORMAL, true); + } + + @Test + public void testSetPerSsidRoamingModeByNonAdmin() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + when(mActiveModeWarden.getSupportedFeatureSet()) + .thenReturn(WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.setPerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), + WifiManager.ROAMING_MODE_NORMAL, TEST_PACKAGE_NAME)); + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission( + anyInt())).thenReturn(true); + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.setPerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), -1, TEST_PACKAGE_NAME)); + + mWifiServiceImpl.setPerSsidRoamingMode(WifiSsid.fromString(TEST_SSID_WITH_QUOTES), + WifiManager.ROAMING_MODE_NORMAL, TEST_PACKAGE_NAME); + mLooper.dispatchAll(); + verify(mWifiRoamingModeManager).setPerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), + WifiManager.ROAMING_MODE_NORMAL, false); + } + + @Test + public void testRemovePerSsidRoamingModeByDeviceAdmin() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + when(mActiveModeWarden.getSupportedFeatureSet()) + .thenReturn(WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.removePerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), TEST_PACKAGE_NAME)); + when(mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin(anyInt(), + eq(TEST_PACKAGE_NAME))).thenReturn(true); + + mWifiServiceImpl.removePerSsidRoamingMode(WifiSsid.fromString(TEST_SSID_WITH_QUOTES), + TEST_PACKAGE_NAME); + mLooper.dispatchAll(); + verify(mWifiRoamingModeManager).removePerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), true); + } + + @Test + public void testRemovePerSsidRoamingModeByNonAdmin() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + when(mActiveModeWarden.getSupportedFeatureSet()) + .thenReturn(WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.removePerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), TEST_PACKAGE_NAME)); + when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); + + mWifiServiceImpl.removePerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), TEST_PACKAGE_NAME); + mLooper.dispatchAll(); + verify(mWifiRoamingModeManager).removePerSsidRoamingMode( + WifiSsid.fromString(TEST_SSID_WITH_QUOTES), false); + } + + @Test + public void testGetPerSsidRoamingModesByDeviceAdmin() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + when(mActiveModeWarden.getSupportedFeatureSet()) + .thenReturn(WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT); + IMapListener listener = mock(IMapListener.class); + InOrder inOrder = inOrder(listener); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.getPerSsidRoamingModes(TEST_PACKAGE_NAME, listener)); + when(mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin(anyInt(), + eq(TEST_PACKAGE_NAME))).thenReturn(true); + + Map<String, Integer> deviceAdminRoamingPolicies = new ArrayMap<>(); + deviceAdminRoamingPolicies.put(TEST_SSID_WITH_QUOTES, WifiManager.ROAMING_MODE_NORMAL); + when(mWifiRoamingModeManager.getPerSsidRoamingModes(eq(true))).thenReturn( + deviceAdminRoamingPolicies); + + mWifiServiceImpl.getPerSsidRoamingModes(TEST_PACKAGE_NAME, listener); + mLooper.dispatchAll(); + ArgumentCaptor<Map<String, Integer>> resultCaptor = ArgumentCaptor.forClass(Map.class); + inOrder.verify(listener).onResult(resultCaptor.capture()); + + assertEquals(resultCaptor.getValue().get(TEST_SSID_WITH_QUOTES), + deviceAdminRoamingPolicies.get(TEST_SSID_WITH_QUOTES)); + assertEquals(resultCaptor.getValue().size(), + deviceAdminRoamingPolicies.size()); + } + + @Test + public void testGetPerSsidRoamingModesByNonAdmin() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + when(mActiveModeWarden.getSupportedFeatureSet()) + .thenReturn(WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT); + IMapListener listener = mock(IMapListener.class); + InOrder inOrder = inOrder(listener); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.getPerSsidRoamingModes(TEST_PACKAGE_NAME, listener)); + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission( + anyInt())).thenReturn(true); + + Map<String, Integer> nonAdminRoamingPolicies = new ArrayMap<>(); + nonAdminRoamingPolicies.put(TEST_SSID_WITH_QUOTES, WifiManager.ROAMING_MODE_NONE); + when(mWifiRoamingModeManager.getPerSsidRoamingModes(false)).thenReturn( + nonAdminRoamingPolicies); + + mWifiServiceImpl.getPerSsidRoamingModes(TEST_PACKAGE_NAME, listener); + mLooper.dispatchAll(); + ArgumentCaptor<Map<String, Integer>> resultCaptor = ArgumentCaptor.forClass(Map.class); + inOrder.verify(listener).onResult(resultCaptor.capture()); + + assertEquals(resultCaptor.getValue().get(TEST_SSID_WITH_QUOTES), + nonAdminRoamingPolicies.get(TEST_SSID_WITH_QUOTES)); + assertEquals(resultCaptor.getValue().size(), + nonAdminRoamingPolicies.size()); + } + + private void verifyIsPnoSupported(boolean isBackgroundScanSupported, boolean isSwPnoEnabled, + boolean isPnoFeatureSet) { + when(mWifiGlobals.isBackgroundScanSupported()).thenReturn(isBackgroundScanSupported); + when(mWifiGlobals.isSwPnoEnabled()).thenReturn(isSwPnoEnabled); + if (isPnoFeatureSet) { + when(mActiveModeWarden.getSupportedFeatureSet()) + .thenReturn(WifiManager.WIFI_FEATURE_PNO); + } else { + when(mActiveModeWarden.getSupportedFeatureSet()).thenReturn(0L); + } + assertEquals(mWifiServiceImpl.isPnoSupported(), + (isBackgroundScanSupported && isPnoFeatureSet) || isSwPnoEnabled); + } + + /* + * Verify that Pno is supported. + */ + @Test + public void testIsPnoSupported() throws Exception { + verifyIsPnoSupported(false, false, false); + verifyIsPnoSupported(true, false, false); + verifyIsPnoSupported(false, true, false); + verifyIsPnoSupported(false, false, true); + verifyIsPnoSupported(true, true, false); + verifyIsPnoSupported(false, true, true); + verifyIsPnoSupported(true, false, true); + verifyIsPnoSupported(true, true, true); + } + + @Test + public void testSetD2dAllowedWhenInfraStaDisabled() throws Exception { + // by default no permissions are given so the call should fail. + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.setD2dAllowedWhenInfraStaDisabled(true)); + mWifiServiceImpl.checkAndStartWifi(); + mLooper.dispatchAll(); + // verify setD2DAllowedWhenInfraStaDisabled with MANAGE_WIFI_NETWORK_SETTING + when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + mWifiServiceImpl.setD2dAllowedWhenInfraStaDisabled(true); + mLooper.dispatchAll(); + verify(mWifiSettingsConfigStore).put(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED), eq(true)); + + mWifiServiceImpl.setD2dAllowedWhenInfraStaDisabled(false); + mLooper.dispatchAll(); + verify(mWifiSettingsConfigStore).put(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED), eq(false)); + } + + @Test + public void testQueryD2dAllowedWhenInfraStaDisabled() throws Exception { + // null listener ==> IllegalArgumentException + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.queryD2dAllowedWhenInfraStaDisabled(null)); + + mWifiServiceImpl.checkAndStartWifi(); + mLooper.dispatchAll(); + IBooleanListener listener = mock(IBooleanListener.class); + + InOrder inOrder = inOrder(listener); + when(mWifiSettingsConfigStore.get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED))) + .thenReturn(true); + mWifiServiceImpl.queryD2dAllowedWhenInfraStaDisabled(listener); + mLooper.dispatchAll(); + verify(mWifiSettingsConfigStore).get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED)); + inOrder.verify(listener).onResult(true); + + when(mWifiSettingsConfigStore.get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED))) + .thenReturn(false); + mWifiServiceImpl.queryD2dAllowedWhenInfraStaDisabled(listener); + mLooper.dispatchAll(); + verify(mWifiSettingsConfigStore, times(2)).get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED)); + inOrder.verify(listener).onResult(false); + } + + @Test + public void testGetTwtCapabilities() { + assumeTrue(SdkLevel.isAtLeastV()); + ITwtCapabilitiesListener iTwtCapabilitiesListener = mock(ITwtCapabilitiesListener.class); + // Test permission check + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_DENIED); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.getTwtCapabilities(iTwtCapabilitiesListener, mExtras)); + mWifiServiceImpl.checkAndStartWifi(); + mLooper.dispatchAll(); + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_GRANTED); + // Test with null parameters + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.getTwtCapabilities(null, mExtras)); + // Test getTwtCapabilities call + mWifiServiceImpl.getTwtCapabilities(iTwtCapabilitiesListener, mExtras); + mLooper.dispatchAll(); + verify(mTwtManager).getTwtCapabilities(eq(WIFI_IFACE_NAME), eq(iTwtCapabilitiesListener)); + } + + @Test + public void testSetupTwtSession() throws RemoteException { + assumeTrue(SdkLevel.isAtLeastV()); + ITwtCallback iTwtCallback = mock(ITwtCallback.class); + TwtRequest twtRequest = mock(TwtRequest.class); + // Test permission check + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_DENIED); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.setupTwtSession(twtRequest, iTwtCallback, mExtras)); + mWifiServiceImpl.checkAndStartWifi(); + mLooper.dispatchAll(); + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_GRANTED); + // Test with null parameters + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.setupTwtSession(null, iTwtCallback, mExtras)); + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.setupTwtSession(twtRequest, null, mExtras)); + // Test with station not connected + when(mClientModeManager.isConnected()).thenReturn(false); + mWifiServiceImpl.setupTwtSession(twtRequest, iTwtCallback, mExtras); + mLooper.dispatchAll(); + verify(iTwtCallback).onFailure(eq(TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE)); + // Test setupTwtSession with station connected + when(mClientModeManager.isConnected()).thenReturn(true); + when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID); + mWifiServiceImpl.setupTwtSession(twtRequest, iTwtCallback, mExtras); + mLooper.dispatchAll(); + verify(mTwtManager).setupTwtSession(eq(WIFI_IFACE_NAME), eq(twtRequest), eq(iTwtCallback), + eq(Binder.getCallingUid()), eq(TEST_BSSID)); + } + + @Test + public void testGetStatsTwtSession() { + assumeTrue(SdkLevel.isAtLeastV()); + int sessionId = 10; + ITwtStatsListener iTwtStatsListener = mock(ITwtStatsListener.class); + // Test permission check + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_DENIED); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.getStatsTwtSession(sessionId, iTwtStatsListener, mExtras)); + mWifiServiceImpl.checkAndStartWifi(); + mLooper.dispatchAll(); + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_GRANTED); + // Test with null parameters + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.getStatsTwtSession(sessionId, null, mExtras)); + // Test getStatsTwtSession call + mWifiServiceImpl.getStatsTwtSession(sessionId, iTwtStatsListener, mExtras); + mLooper.dispatchAll(); + verify(mTwtManager).getStatsTwtSession(eq(WIFI_IFACE_NAME), eq(iTwtStatsListener), + eq(sessionId)); + } + + @Test + public void testTeardownTwtSession() { + assumeTrue(SdkLevel.isAtLeastV()); + int sessionId = 10; + // Test permission check + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_DENIED); + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.teardownTwtSession(sessionId, mExtras)); + mWifiServiceImpl.checkAndStartWifi(); + mLooper.dispatchAll(); + when(mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)).thenReturn( + PackageManager.PERMISSION_GRANTED); + // Test teardownTwtSession call + mWifiServiceImpl.teardownTwtSession(sessionId, mExtras); + mLooper.dispatchAll(); + verify(mTwtManager).tearDownTwtSession(eq(WIFI_IFACE_NAME), eq(sessionId)); + } + + @SuppressWarnings("BoxedPrimitiveEquality") + @Test + public void testRetrieveWifiBackupData() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + // Expect exception when caller has no permission + doThrow(new SecurityException()).when(mContext) + .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + eq("WifiService")); + IByteArrayListener mockTestListener = mock(IByteArrayListener.class); + // by default no permissions are given so the call should fail. + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.retrieveWifiBackupData(mockTestListener)); + doNothing().when(mContext) + .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + eq("WifiService")); + // null listener ==> IllegalArgumentException + assertThrows(IllegalArgumentException.class, + () -> mWifiServiceImpl.retrieveWifiBackupData(null)); + mWifiServiceImpl.retrieveWifiBackupData(mockTestListener); + mLooper.dispatchAll(); + verify(mBackupRestoreController).retrieveBackupData(); + verify(mockTestListener).onResult(any()); + } + + @SuppressWarnings("BoxedPrimitiveEquality") + @Test + public void testRestoreWifiBackupData() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + byte[] mockTestRestoredData = new byte[0]; + // Expect exception when caller has no permission + doThrow(new SecurityException()).when(mContext) + .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + eq("WifiService")); + // by default no permissions are given so the call should fail. + assertThrows(SecurityException.class, + () -> mWifiServiceImpl.restoreWifiBackupData(mockTestRestoredData)); + doNothing().when(mContext) + .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + eq("WifiService")); + mWifiServiceImpl.restoreWifiBackupData(mockTestRestoredData); + mLooper.dispatchAll(); + verify(mBackupRestoreController).parserBackupDataAndDispatch(mockTestRestoredData); + } + + @Test + public void testWepAllowedChangedFromCloudRestoration() { + when(mWifiSettingsConfigStore.get(eq(WIFI_WEP_ALLOWED))).thenReturn(true); + when(mWifiGlobals.isWepAllowed()).thenReturn(true); + mWifiServiceImpl.checkAndStartWifi(); + mLooper.dispatchAll(); + verify(mWifiSettingsConfigStore).registerChangeListener( + eq(WIFI_WEP_ALLOWED), + mWepAllowedSettingChangedListenerCaptor.capture(), + any(Handler.class)); + verify(mWifiGlobals).setWepAllowed(true); + // Mock wep connection to make sure it will disconnect + ConcreteClientModeManager cmmWep = mock(ConcreteClientModeManager.class); + WifiInfo mockWifiInfoWep = mock(WifiInfo.class); + List<ClientModeManager> cmms = Arrays.asList(cmmWep); + when(mActiveModeWarden.getClientModeManagers()).thenReturn(cmms); + when(mockWifiInfoWep.getCurrentSecurityType()).thenReturn(WifiInfo.SECURITY_TYPE_WEP); + when(cmmWep.getConnectionInfo()).thenReturn(mockWifiInfoWep); + + // Test wep is changed from cloud restoration. + mWepAllowedSettingChangedListenerCaptor.getValue() + .onSettingsChanged(WIFI_WEP_ALLOWED, false); + mLooper.dispatchAll(); + verify(mWifiGlobals).setWepAllowed(false); + // Only WEP disconnect + verify(cmmWep).disconnect(); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiSettingsBackupRestoreTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiSettingsBackupRestoreTest.java new file mode 100644 index 0000000000..38b4d9e0a4 --- /dev/null +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiSettingsBackupRestoreTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2024 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.WifiSettingsBackupRestore.XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.inOrder; + +import android.util.Xml; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlSerializer; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +/** + * Unit tests for {@link com.android.server.wifi.WifiSettingsBackupRestoreTest}. + */ +@SmallTest +public class WifiSettingsBackupRestoreTest extends WifiBaseTest { + + @Mock WifiSettingsConfigStore mWifiSettingsConfigStore; + @Mock XmlPullParser mXmlPullParser; + @Mock ByteArrayOutputStream mByteArrayOutputStream; + @Mock XmlSerializer mXmlSerializer; + + @SuppressWarnings("DoubleBraceInitialization") + private static final ArrayList<WifiSettingsConfigStore.Key> TEST_KEYS = new ArrayList<>() {{ + add(WifiSettingsConfigStore.WIFI_WEP_ALLOWED); }}; + + /** + * The data we backup in this module is <WifiSettingsSection></WifiSettingsSection> + * and the depth is 1. + */ + public static String generateTestWifiSettingsTestingXml(String backupKeys) { + return "<WifiSettingsSection>\n" + + "<Settings>\n" + + "<map name=\"Values\">\n" + + backupKeys + + "</map>\n" + + "</Settings>\n" + + "</WifiSettingsSection>\n"; + } + + private WifiSettingsBackupRestore mWifiSettingsBackupRestore; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mWifiSettingsConfigStore.getAllKeys()).thenReturn(TEST_KEYS); + when(mWifiSettingsConfigStore.getAllBackupRestoreKeys()).thenReturn(TEST_KEYS); + mWifiSettingsBackupRestore = new WifiSettingsBackupRestore(mWifiSettingsConfigStore); + mWifiSettingsBackupRestore.enableVerboseLogging(true); + } + + private XmlPullParser generateTestXmlPullParser(byte[] data) throws Exception { + final XmlPullParser in = Xml.newPullParser(); + ByteArrayInputStream inputStream = + new ByteArrayInputStream(data); + in.setInput(inputStream, StandardCharsets.UTF_8.name()); + return in; + } + + @Test + public void testBackupWifiSettings() throws Exception { + InOrder order = inOrder(mXmlSerializer); + mWifiSettingsBackupRestore.retrieveBackupDataFromSettingsConfigStore( + mXmlSerializer, mByteArrayOutputStream); + order.verify(mXmlSerializer).startTag(eq(null), + eq(XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA)); + order.verify(mXmlSerializer).startTag(eq(null), + eq(WifiSettingsConfigStore.StoreData.XML_TAG_SECTION_HEADER)); + order.verify(mXmlSerializer).startTag(eq(null), eq("map")); + order.verify(mXmlSerializer).attribute(eq(null), eq("name"), + eq(WifiSettingsConfigStore.StoreData.XML_TAG_VALUES)); + for (WifiSettingsConfigStore.Key key : mWifiSettingsConfigStore.getAllKeys()) { + order.verify(mXmlSerializer).attribute(eq(null), eq("name"), eq(key.getKey())); + } + order.verify(mXmlSerializer).endTag(eq(null), eq("map")); + order.verify(mXmlSerializer).endTag(eq(null), + eq(WifiSettingsConfigStore.StoreData.XML_TAG_SECTION_HEADER)); + order.verify(mXmlSerializer).endTag(eq(null), + eq(XML_TAG_SECTION_HEADER_WIFI_SETTINGS_DATA)); + } + + @Test + public void testRestoreWifiSettings() throws Exception { + String testBackupMap = "<boolean name=\"wep_allowed\" value=\"true\" />\n"; + mWifiSettingsBackupRestore.restoreSettingsFromBackupData( + generateTestXmlPullParser( + generateTestWifiSettingsTestingXml(testBackupMap).getBytes()), + 0 /* The depth of Tag: WifiSettingsSection */); + verify(mWifiSettingsConfigStore).put(eq(WifiSettingsConfigStore.WIFI_WEP_ALLOWED), + eq(Boolean.TRUE)); + } + + @Test + public void testRestoreWifiSettingsWithUnknownTag() throws Exception { + String testBackupMap = "<boolean name=\"unknown_tag\" value=\"true\" />\n"; + mWifiSettingsBackupRestore.restoreSettingsFromBackupData( + generateTestXmlPullParser( + generateTestWifiSettingsTestingXml(testBackupMap).getBytes()), + 0 /* The depth of Tag: WifiSettingsSection */); + verify(mWifiSettingsConfigStore, never()).put(any(), any()); + } +} diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java index 07de1876f7..4783d049cf 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java @@ -105,7 +105,6 @@ public class WifiShellCommandTest extends WifiBaseTest { @Mock WifiDiagnostics mWifiDiagnostics; @Mock DeviceConfigFacade mDeviceConfig; @Mock WifiScanner mWifiScanner; - WifiShellCommand mWifiShellCommand; @Before @@ -826,7 +825,7 @@ public class WifiShellCommandTest extends WifiBaseTest { return (wifiConfiguration.SSID.equals("\"ssid1234\"") && wifiConfiguration.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_NONE); - }), eq(-1), any(), any()); + }), eq(-1), any(), any(), any()); } @Test @@ -841,7 +840,7 @@ public class WifiShellCommandTest extends WifiBaseTest { return (wifiConfiguration.SSID.equals("\"ssid1234\"") && wifiConfiguration.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_NON_PERSISTENT); - }), eq(-1), any(), any()); + }), eq(-1), any(), any(), any()); } @Test @@ -860,14 +859,14 @@ public class WifiShellCommandTest extends WifiBaseTest { new Binder(), new FileDescriptor(), new FileDescriptor(), new FileDescriptor(), new String[]{"connect-network", "012345", "open", "-x"}); verify(mWifiService, never()).connect(argThat(wifiConfiguration -> - (wifiConfiguration.SSID.equals("012345"))), eq(-1), any()); + (wifiConfiguration.SSID.equals("012345"))), eq(-1), any(), any(), any()); BinderUtil.setUid(Process.ROOT_UID); mWifiShellCommand.exec( new Binder(), new FileDescriptor(), new FileDescriptor(), new FileDescriptor(), new String[]{"connect-network", "012345", "open", "-x"}); verify(mWifiService).connect(argThat(wifiConfiguration -> - (wifiConfiguration.SSID.equals("012345"))), eq(-1), any(), any()); + (wifiConfiguration.SSID.equals("012345"))), eq(-1), any(), any(), any()); } @Test diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java index 80ab46044d..ba434a573e 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java @@ -48,6 +48,7 @@ import android.app.test.MockAnswerUtil.AnswerWithArguments; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.hardware.wifi.WifiStatusCode; import android.net.InetAddresses; import android.net.KeepalivePacketData; import android.net.MacAddress; @@ -1813,4 +1814,21 @@ public class WifiVendorHalTest extends WifiBaseTest { mWifiVendorHal.setAfcChannelAllowance(mAfcChannelAllowance); verify(mWifiChip).setAfcChannelAllowance(mAfcChannelAllowance); } + + /** + * Test setRoamingMode + * + * A call before the vendor HAL is started should return invalid interface. + * + * A call after the HAL is started should return success value. + */ + @Test + public void testSetRoamingMode() throws Exception { + assertTrue(mWifiVendorHal.setRoamingMode(TEST_IFACE_NAME, WifiManager.ROAMING_MODE_NORMAL) + == WifiStatusCode.ERROR_WIFI_IFACE_INVALID); + // Start the vendor hal + assertTrue(mWifiVendorHal.startVendorHalSta(mConcreteClientModeManager)); + assertTrue(mWifiVendorHal.setRoamingMode(TEST_IFACE_NAME, WifiManager.ROAMING_MODE_NORMAL) + == WifiStatusCode.SUCCESS); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/aware/TestUtils.java b/service/tests/wifitests/src/com/android/server/wifi/aware/TestUtils.java index bc453c8f8b..c2ceade67a 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/aware/TestUtils.java +++ b/service/tests/wifitests/src/com/android/server/wifi/aware/TestUtils.java @@ -140,13 +140,13 @@ public class TestUtils { } public boolean respondToBootstrappingRequest(short transactionId, int bootstrappingId, - boolean accept) { + boolean accept, byte pubSubId) { addTransactionId(transactionId); return true; } public boolean initiateBootstrapping(short transactionId, int peerId, byte[] peer, - int method, byte[] cookie) { + int method, byte[] cookie, byte pubSubId, boolean isComeBack) { addTransactionId(transactionId); return true; } diff --git a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java index b5db3799e4..2adab51238 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java @@ -188,6 +188,11 @@ public class WifiAwareDataPathStateManagerTest extends WifiBaseTest { Context.POWER_SERVICE); when(mMockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager); when(mMockContext.getSystemService(StatsManager.class)).thenReturn(mStatsManager); + mResources = new MockResources(); + mResources.setBoolean(R.bool.config_wifiAllowMultipleNetworksOnSameAwareNdi, false); + mResources.setBoolean(R.bool.config_wifiAwareNdpSecurityUpdateOnSameNdi, false); + mResources.setInteger(R.integer.config_wifiConfigurationWifiRunnerThresholdInMs, 4000); + when(mMockContext.getResources()).thenReturn(mResources); when(mInterfaceConflictManager.manageInterfaceConflictForStateMachine(any(), any(), any(), any(), any(), eq(HalDeviceManager.HDM_CREATE_IFACE_NAN), any(), anyBoolean())) @@ -220,11 +225,6 @@ public class WifiAwareDataPathStateManagerTest extends WifiBaseTest { mDut.mDataPathMgr.mNetdWrapper = mMockNetdWrapper; mDut.mDataPathMgr.mNiWrapper = mMockNetworkInterface; - - mResources = new MockResources(); - mResources.setBoolean(R.bool.config_wifiAllowMultipleNetworksOnSameAwareNdi, false); - mResources.setBoolean(R.bool.config_wifiAwareNdpSecurityUpdateOnSameNdi, false); - when(mMockContext.getResources()).thenReturn(mResources); } /** diff --git a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java index 2dc4e26470..8342171c42 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java @@ -18,9 +18,11 @@ package com.android.server.wifi.aware; import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_PK_PASN_128; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_AWARE_VERBOSE_LOGGING_ENABLED; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -31,6 +33,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -39,7 +42,7 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; -import android.content.res.Resources; +import android.net.wifi.OuiKeyedData; import android.net.wifi.WifiScanner; import android.net.wifi.aware.Characteristics; import android.net.wifi.aware.ConfigRequest; @@ -54,24 +57,30 @@ import android.os.Build; import android.os.Bundle; import android.os.HandlerThread; import android.os.IBinder; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.test.TestLooper; +import android.util.LocalLog; import android.util.SparseArray; import android.util.SparseIntArray; import androidx.test.filters.SmallTest; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.DeviceConfigFacade; import com.android.server.wifi.HalDeviceManager; import com.android.server.wifi.InterfaceConflictManager; +import com.android.server.wifi.MockResources; import com.android.server.wifi.WifiBaseTest; +import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; import com.android.wifi.resources.R; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -80,6 +89,9 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** @@ -118,6 +130,9 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { @Mock private WifiSettingsConfigStore mWifiSettingsConfigStore; @Mock private InterfaceConflictManager mInterfaceConflictManager; @Mock private DeviceConfigFacade mDeviceConfigFacade; + @Mock private WifiInjector mWifiInjector; + @Mock private LocalLog mLocalLog; + private StaticMockitoSession mStaticMockSession; /** * Using instead of spy to avoid native crash failures - possibly due to @@ -146,6 +161,11 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); + mStaticMockSession = mockitoSession() + .mockStatic(WifiInjector.class) + .startMocking(); + lenient().when(WifiInjector.getInstance()).thenReturn(mWifiInjector); + when(mWifiInjector.getWifiHandlerLocalLog()).thenReturn(mLocalLog); mMockLooper = new TestLooper(); when(mHandlerThreadMock.getLooper()).thenReturn(mMockLooper.getLooper()); @@ -170,10 +190,11 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { .thenReturn(InterfaceConflictManager.ICM_EXECUTE_COMMAND); mDut = new WifiAwareServiceImplSpy(mContextMock); - Resources resources = mock(Resources.class); + MockResources resources = new MockResources(); + resources.setInteger(R.integer.config_wifiVerboseLoggingAlwaysOnLevel, 0); + resources.setInteger(R.integer.config_wifiConfigurationWifiRunnerThresholdInMs, 4000); when(mContextMock.getResources()).thenReturn(resources); - when(resources.getInteger( - R.integer.config_wifiVerboseLoggingAlwaysOnLevel)).thenReturn(0); + mDut.fakeUid = mDefaultUid; mDut.start(mHandlerThreadMock, mAwareStateManagerMock, mWifiAwareShellCommandMock, mAwareMetricsMock, mWifiPermissionsUtil, mPermissionsWrapperMock, @@ -187,6 +208,11 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { eq(mInterfaceConflictManager)); } + @After + public void tearDown() throws Exception { + mStaticMockSession.finishMocking(); + } + /** * Validate isUsageEnabled() function */ @@ -237,15 +263,69 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { */ @Test public void testConnectWithConfig() { - ConfigRequest configRequest = new ConfigRequest.Builder().setMasterPreference(55).build(); + int clusterLow = 15; + ConfigRequest configRequest = new ConfigRequest.Builder() + .setClusterLow(clusterLow) + .build(); String callingPackage = "com.google.somePackage"; String callingFeatureId = "com.google.someFeature"; mDut.connect(mBinderMock, callingPackage, callingFeatureId, mCallbackMock, configRequest, false, mExtras, false); + ArgumentCaptor<ConfigRequest> configRequestCaptor = + ArgumentCaptor.forClass(ConfigRequest.class); verify(mAwareStateManagerMock).connect(anyInt(), anyInt(), anyInt(), eq(callingPackage), - eq(callingFeatureId), eq(mCallbackMock), eq(configRequest), eq(false), any(), - eq(false)); + eq(callingFeatureId), eq(mCallbackMock), configRequestCaptor.capture(), eq(false), + any(), eq(false)); + + // Since the caller has the network stack permission, + // the provided ConfigRequest should be unmodified + assertEquals(clusterLow, configRequestCaptor.getValue().mClusterLow); + } + + /** + * Validate connect() when a non-null config is passed and the caller has the + * manage network selection permission. + */ + @Test + public void testConnectWithManageNetworkSelectionPermission() { + // Caller has none of the permissions required to include a ConfigRequest + assumeTrue(SdkLevel.isAtLeastV()); + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(false); + when(mContextMock.checkCallingOrSelfPermission(anyString())) + .thenReturn(PackageManager.PERMISSION_DENIED); + + int clusterLow = 15; + OuiKeyedData vendorDataElement = + new OuiKeyedData.Builder(0x00aabbcc, new PersistableBundle()).build(); + List<OuiKeyedData> vendorData = Arrays.asList(vendorDataElement); + ConfigRequest configRequest = new ConfigRequest.Builder() + .setClusterLow(clusterLow) + .setVendorData(vendorData) + .build(); + + String callingPackage = "com.google.somePackage"; + String callingFeatureId = "com.google.someFeature"; + assertThrows(SecurityException.class, () -> + mDut.connect(mBinderMock, callingPackage, callingFeatureId, mCallbackMock, + configRequest, false, mExtras, false)); + + // Caller has the manage network selection permission + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(true); + ArgumentCaptor<ConfigRequest> configRequestCaptor = + ArgumentCaptor.forClass(ConfigRequest.class); + mDut.connect(mBinderMock, callingPackage, callingFeatureId, mCallbackMock, + configRequest, false, mExtras, false); + verify(mAwareStateManagerMock).connect(anyInt(), anyInt(), anyInt(), eq(callingPackage), + eq(callingFeatureId), eq(mCallbackMock), configRequestCaptor.capture(), + eq(false), any(), eq(false)); + + // Since the caller does not have the network stack permission, all ConfigRequest fields + // except the vendor data should be reset to a default value + assertEquals(vendorData, configRequestCaptor.getValue().getVendorData()); + assertNotEquals(clusterLow, configRequestCaptor.getValue().mClusterLow); } /** @@ -984,7 +1064,7 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { // constructed configs. PublishConfig publishConfig = new PublishConfig(serviceName.getBytes(), ssi, matchFilter, PublishConfig.PUBLISH_TYPE_UNSOLICITED, 0, true, false, false, - WifiScanner.WIFI_BAND_24_GHZ, null, null, false); + WifiScanner.WIFI_BAND_24_GHZ, null, null, false, Collections.emptyList()); int clientId = doConnect(); IWifiAwareDiscoverySessionCallback mockCallback = mock( IWifiAwareDiscoverySessionCallback.class); @@ -1001,7 +1081,7 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { // constructed configs. SubscribeConfig subscribeConfig = new SubscribeConfig(serviceName.getBytes(), ssi, matchFilter, SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE, 0, true, false, 0, false, 0, - false, WifiScanner.WIFI_BAND_24_GHZ, null, false); + false, WifiScanner.WIFI_BAND_24_GHZ, null, false, Collections.emptyList()); int clientId = doConnect(); IWifiAwareDiscoverySessionCallback mockCallback = mock( IWifiAwareDiscoverySessionCallback.class); diff --git a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java index 130fbf10bb..f1578311f0 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java @@ -65,6 +65,7 @@ import android.content.pm.PackageManager; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.wifi.IBooleanListener; +import android.net.wifi.OuiKeyedData; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; @@ -86,6 +87,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -136,6 +138,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -233,6 +236,7 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { mResources = new MockResources(); mResources.setInteger(R.integer.config_wifiAwareInstantCommunicationModeDurationMillis, 30000); + mResources.setInteger(R.integer.config_wifiConfigurationWifiRunnerThresholdInMs, 4000); when(mMockContext.getResources()).thenReturn(mResources); when(mInterfaceConflictManager.manageInterfaceConflictForStateMachine(any(), any(), any(), @@ -331,6 +335,7 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { * - Get multiple matches (PeerHandles) * - Request translation as UID of session #1 for PeerHandles of the same UID + of the other * discovery session (to which we shouldn't have access) + invalid PeerHandle. + * - Vendor data list is converted to an array for callback * -> validate results */ @Test @@ -352,6 +357,12 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { final byte[] peerMac3 = HexEncoding.decode("AABBCCDDEEFF".toCharArray(), false); final int distance = 10; + OuiKeyedData vendorDataElement = + new OuiKeyedData.Builder(0x00112233, new PersistableBundle()).build(); + List<OuiKeyedData> vendorDataList = Arrays.asList(vendorDataElement); + OuiKeyedData[] vendorDataArray = new OuiKeyedData[vendorDataList.size()]; + vendorDataList.toArray(vendorDataArray); + ConfigRequest configRequest = new ConfigRequest.Builder().build(); SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) .build(); @@ -418,22 +429,23 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (3) 2 matches on session 1 (second one with distance), 1 match on session 2 mDut.onMatchNotification(subscribeId1, requestorIdBase, peerMac1, null, null, 0, 0, - null, 0, null, null, null); + null, 0, null, null, null, vendorDataList); mDut.onMatchNotification(subscribeId1, requestorIdBase + 1, peerMac2, null, null, - NanRangingIndication.INGRESS_MET_MASK, distance, null, 0, null, null, null); + NanRangingIndication.INGRESS_MET_MASK, distance, null, 0, null, null, null, + vendorDataList); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback1).onMatch(peerIdCaptor.capture(), isNull(), - isNull(), anyInt(), isNull(), any(), any()); + isNull(), anyInt(), isNull(), any(), any(), eq(vendorDataArray)); inOrder.verify(mockSessionCallback1).onMatchWithDistance(peerIdCaptor.capture(), isNull(), - isNull(), eq(distance), anyInt(), isNull(), any(), any()); + isNull(), eq(distance), anyInt(), isNull(), any(), any(), eq(vendorDataArray)); int peerId1 = peerIdCaptor.getAllValues().get(0); int peerId2 = peerIdCaptor.getAllValues().get(1); mDut.onMatchNotification(subscribeId2, requestorIdBase + 2, peerMac3, null, null, 0, 0, - null, 0, null, null, null); + null, 0, null, null, null, vendorDataList); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback2).onMatch(peerIdCaptor.capture(), isNull(), isNull(), - anyInt(), isNull(), any(), any()); + anyInt(), isNull(), any(), any(), eq(vendorDataArray)); int peerId3 = peerIdCaptor.getAllValues().get(0); // request MAC addresses @@ -1821,20 +1833,20 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (2) 2 matches : with and w/o range mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), - peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null); + peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), - eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull()); + eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull(), isNull()); inOrderM.verify(mAwareMetricsMock).recordMatchIndicationForRangeEnabledSubscribe(false); int peerId1 = peerIdCaptor.getValue(); mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), peerMatchFilter.getBytes(), EGRESS_MET_MASK, rangedDistance, null, 0, null, null, - null); + null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatchWithDistance(peerIdCaptor.capture(), eq(peerSsi.getBytes()), eq(peerMatchFilter.getBytes()), eq(rangedDistance), - anyInt(), isNull(), isNull(), isNull()); + anyInt(), isNull(), isNull(), isNull(), isNull()); inOrderM.verify(mAwareMetricsMock).recordMatchIndicationForRangeEnabledSubscribe(true); int peerId2 = peerIdCaptor.getValue(); @@ -2134,11 +2146,11 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { eq(subscribeConfig), isNull()); mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), - peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null); + peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), - eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull()); + eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) send message to invalid peer ID mDut.sendMessage(uid, clientId, sessionId.getValue(), peerIdCaptor.getValue() + 5, @@ -2203,11 +2215,11 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { eq(subscribeConfig), isNull()); mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), - peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null); + peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), - eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull()); + eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) send 2 messages and enqueue successfully mDut.sendMessage(uid, clientId, sessionId.getValue(), peerIdCaptor.getValue(), @@ -2329,11 +2341,11 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { eq(subscribeConfig), isNull()); mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), - peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null); + peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), - eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull()); + eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) send message and enqueue successfully mDut.sendMessage(uid, clientId, sessionId.getValue(), peerIdCaptor.getValue(), @@ -2416,11 +2428,11 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { eq(subscribeConfig), isNull()); mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId); mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), - peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null); + peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture()); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), - eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull()); + eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) send message and enqueue successfully mDut.sendMessage(uid, clientId, sessionId.getValue(), peerIdCaptor.getValue(), @@ -2509,10 +2521,10 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (2) match mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null, 0, 0, - null, 0, null, null, null); + null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), isNull(), - anyInt(), isNull(), isNull(), isNull()); + anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) transmit messages SendMessageQueueModelAnswer answerObj = new SendMessageQueueModelAnswer(queueDepth, @@ -2643,16 +2655,16 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (2) match mDut.onMatchNotification(subscribeId1, requestorId1, peerMac1, null, null, 0, 0, - null, 0, null, null, null); + null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor1.capture(), isNull(), isNull(), - anyInt(), isNull(), isNull(), isNull()); + anyInt(), isNull(), isNull(), isNull(), isNull()); mDut.onMatchNotification(subscribeId2, requestorId2, peerMac2, null, null, 0, 0, - null, 0, null, null, null); + null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor2.capture(), isNull(), isNull(), - anyInt(), isNull(), isNull(), isNull()); + anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) Enqueue messages SendMessageQueueModelAnswer answerObj = new SendMessageQueueModelAnswer(queueDepth, @@ -2768,10 +2780,10 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (2) match mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null, 0, 0, - null, 0, null, null, null); + null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), isNull(), - anyInt(), isNull(), isNull(), isNull()); + anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) transmit messages: configure a mix of failures/success Set<Integer> failQueueCommandImmediately = new HashSet<>(); @@ -2903,10 +2915,10 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (2) match mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), - peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null); + peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), - eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull()); + eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull(), isNull()); // (3) message null Tx successful queuing mDut.sendMessage(uid, clientId, sessionId.getValue(), peerIdCaptor.getValue(), @@ -3055,6 +3067,12 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { } } + private List<OuiKeyedData> generateVendorData(int oui) { + OuiKeyedData vendorDataElement = + new OuiKeyedData.Builder(oui, new PersistableBundle()).build(); + return Arrays.asList(vendorDataElement); + } + /** * Test sequence of configuration: (1) config1, (2) config2 - incompatible, * (3) config3 - compatible with config1 (requiring upgrade), (4) disconnect @@ -3075,15 +3093,20 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { final int dwInterval1Band24 = 2; final int dwInterval3Band24 = 1; final int dwInterval3Band5 = 0; + final List<OuiKeyedData> vendorData1 = generateVendorData(1); + final List<OuiKeyedData> vendorData3 = generateVendorData(3); ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); ArgumentCaptor<ConfigRequest> crCapture = ArgumentCaptor.forClass(ConfigRequest.class); - ConfigRequest configRequest1 = new ConfigRequest.Builder() + ConfigRequest.Builder builder = new ConfigRequest.Builder() .setClusterLow(5).setClusterHigh(100) .setMasterPreference(masterPref1) - .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwInterval1Band24) - .build(); + .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwInterval1Band24); + if (SdkLevel.isAtLeastV()) { + builder.setVendorData(vendorData1); + } + ConfigRequest configRequest1 = builder.build(); ConfigRequest configRequest2 = new ConfigRequest.Builder() .setSupport5gBand(true) // compatible @@ -3092,7 +3115,7 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { .setMasterPreference(0) // compatible .build(); - ConfigRequest configRequest3 = new ConfigRequest.Builder() + builder = new ConfigRequest.Builder() .setSupport5gBand(true) // compatible (will use true) .setSupport6gBand(false) .setClusterLow(5).setClusterHigh(100) // identical (hence compatible) @@ -3100,8 +3123,11 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // compatible: will use min .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwInterval3Band24) // compatible: will use interval3 since interval1 not init - .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwInterval3Band5) - .build(); + .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwInterval3Band5); + if (SdkLevel.isAtLeastV()) { + builder.setVendorData(vendorData3); + } + ConfigRequest configRequest3 = builder.build(); IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class); IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class); @@ -3155,6 +3181,11 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { collector.checkThat("dw interval on 5: ~min", dwInterval3Band5, equalTo(crCapture.getValue().mDiscoveryWindowInterval[ConfigRequest .NAN_BAND_5GHZ])); + if (SdkLevel.isAtLeastV()) { + // Vendor data from the provided ConfigRequest should be prioritized during the merge + collector.checkThat("merge: vendor data 3", crCapture.getValue().getVendorData(), + equalTo(vendorData3)); + } // (4) disconnect config3: downgrade to config1 mDut.disconnect(clientId3); @@ -3469,7 +3500,7 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { mDut.onMessageSendQueuedFailResponse(transactionIdConfig, -1); mDut.onSessionConfigFailResponse(transactionIdConfig, false, -1); mDut.onMatchNotification(-1, -1, new byte[0], new byte[0], new byte[0], 0, 0, null, 0, null, - null, null); + null, null, null); mDut.onSessionTerminatedNotification(-1, -1, true); mDut.onSessionTerminatedNotification(-1, -1, false); mDut.onMessageReceivedNotification(-1, -1, new byte[0], new byte[0]); @@ -4177,20 +4208,20 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (2) 2 matches : with and w/o range mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), - peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null); + peerMatchFilter.getBytes(), 0, 0, null, 0, null, null, null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()), - eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull()); + eq(peerMatchFilter.getBytes()), anyInt(), isNull(), isNull(), isNull(), isNull()); inOrderM.verify(mAwareMetricsMock).recordMatchIndicationForRangeEnabledSubscribe(false); int peerId1 = peerIdCaptor.getValue(); mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(), peerMatchFilter.getBytes(), EGRESS_MET_MASK, rangedDistance, null, 0, null, null, - null); + null, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatchWithDistance(peerIdCaptor.capture(), eq(peerSsi.getBytes()), eq(peerMatchFilter.getBytes()), eq(rangedDistance), - anyInt(), isNull(), isNull(), isNull()); + anyInt(), isNull(), isNull(), isNull(), isNull()); inOrderM.verify(mAwareMetricsMock).recordMatchIndicationForRangeEnabledSubscribe(true); int peerId2 = peerIdCaptor.getValue(); @@ -4633,7 +4664,7 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { mMockLooper.dispatchAll(); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).respondToBootstrappingRequest(transactionId.capture(), - eq(bootstrappingId), eq(true)); + eq(bootstrappingId), eq(true), eq(publishId)); mDut.onRespondToBootstrappingIndicationResponseSuccess(transactionId.getValue()); mMockLooper.dispatchAll(); verify(mockSessionCallback).onBootstrappingVerificationConfirmed(peerIdCaptor.capture(), @@ -4891,10 +4922,10 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (3) Match peer mDut.onMatchNotification(subscribeId, peerId, peerMac, null, null, 0, 0, null, 0, null, - null, pairingConfig); + null, pairingConfig, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), - isNull(), anyInt(), isNull(), isNull(), any()); + isNull(), anyInt(), isNull(), isNull(), any(), isNull()); // (4) Initiate bootstrapping request mDut.initiateBootStrappingSetupRequest(clientId, sessionId.getValue(), @@ -4902,7 +4933,8 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { ); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).initiateBootstrapping(transactionId.capture(), eq(peerId), - eq(peerMac), eq(AwarePairingConfig.PAIRING_BOOTSTRAPPING_QR_SCAN), isNull()); + eq(peerMac), eq(AwarePairingConfig.PAIRING_BOOTSTRAPPING_QR_SCAN), isNull(), + eq(subscribeId), eq(false)); mDut.onInitiateBootStrappingResponseSuccess(transactionId.getValue(), bootstrappingId); mDut.onBootstrappingConfirmNotification(bootstrappingId, WifiAwareStateManager.NAN_BOOTSTRAPPING_ACCEPT, NanStatusCode.SUCCESS, 0, null); @@ -5027,10 +5059,10 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (3) Match peer mDut.onMatchNotification(subscribeId, peerId, peerMac1, null, null, 0, 0, null, 0, null, - null, pairingConfig); + null, pairingConfig, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), - isNull(), anyInt(), isNull(), eq(alias), any()); + isNull(), anyInt(), isNull(), eq(alias), any(), isNull()); int localPeerId = peerIdCaptor.getValue(); // (4) Initiate pairing setup request @@ -5145,10 +5177,10 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { // (3) Match peer mDut.onMatchNotification(subscribeId, peerId, peerMac, null, null, 0, 0, null, 0, null, - null, pairingConfig); + null, pairingConfig, null); mMockLooper.dispatchAll(); inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), - isNull(), anyInt(), isNull(), isNull(), any()); + isNull(), anyInt(), isNull(), isNull(), any(), isNull()); // (3) Initiate bootstrapping request mDut.initiateBootStrappingSetupRequest(clientId, sessionId.getValue(), @@ -5156,7 +5188,8 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { ); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).initiateBootstrapping(transactionId.capture(), eq(peerId), - eq(peerMac), eq(AwarePairingConfig.PAIRING_BOOTSTRAPPING_QR_SCAN), isNull()); + eq(peerMac), eq(AwarePairingConfig.PAIRING_BOOTSTRAPPING_QR_SCAN), isNull(), + eq(subscribeId), eq(false)); mDut.onInitiateBootStrappingResponseSuccess(transactionId.getValue(), bootstrappingId); // (4) Receive comeback respond, will send the request again with delay @@ -5169,7 +5202,8 @@ public class WifiAwareStateManagerTest extends WifiBaseTest { Thread.sleep(1000); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).initiateBootstrapping(transactionId.capture(), eq(peerId), - eq(peerMac), eq(AwarePairingConfig.PAIRING_BOOTSTRAPPING_QR_SCAN), isNull()); + eq(peerMac), eq(AwarePairingConfig.PAIRING_BOOTSTRAPPING_QR_SCAN), isNull(), + eq(subscribeId), eq(true)); mDut.onInitiateBootStrappingResponseSuccess(transactionId.getValue(), bootstrappingId + 1); // (5) Receive comeback respond on the followup request, will consider reject and notify the diff --git a/service/tests/wifitests/src/com/android/server/wifi/b2b/WifiRoamingModeManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/b2b/WifiRoamingModeManagerTest.java new file mode 100644 index 0000000000..f4b7bfc212 --- /dev/null +++ b/service/tests/wifitests/src/com/android/server/wifi/b2b/WifiRoamingModeManagerTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2024 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.b2b; + +import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiSsid; + +import androidx.test.filters.SmallTest; + +import com.android.modules.utils.build.SdkLevel; +import com.android.server.wifi.ActiveModeWarden; +import com.android.server.wifi.ClientModeManager; +import com.android.server.wifi.WifiBaseTest; +import com.android.server.wifi.WifiNative; +import com.android.server.wifi.WifiRoamingConfigStore; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit tests for {@link com.android.server.wifi.b2b.WifiRoamingModeManager}. + */ +@SmallTest +public class WifiRoamingModeManagerTest extends WifiBaseTest { + private static final String TEST_SSID = "\"test_ssid\""; + private static final String CURRENT_SSID = "\"current_ssid\""; + private static final String WIFI_IFACE_NAME = "wlan0"; + private static final int DEFAULT_ROAMING_MODE = WifiManager.ROAMING_MODE_NORMAL; + private static final int TEST_ROAMING_MODE = WifiManager.ROAMING_MODE_AGGRESSIVE; + @Mock ActiveModeWarden mActiveModeWarden; + @Mock ClientModeManager mClientModeManager; + @Mock WifiInfo mWifiInfo; + @Mock WifiNative mWifiNative; + @Mock WifiRoamingConfigStore mWifiRoamingConfigStore; + + WifiRoamingModeManager mWifiRoamingModeManager; + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mWifiRoamingModeManager = new WifiRoamingModeManager(mWifiNative, + mActiveModeWarden, mWifiRoamingConfigStore); + when(mActiveModeWarden.getConnectionInfo()).thenReturn(mWifiInfo); + when(mWifiInfo.getSSID()).thenReturn(CURRENT_SSID); + when(mActiveModeWarden.getPrimaryClientModeManager()).thenReturn(mClientModeManager); + when(mClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME); + } + + @Test + public void testSetPerSsidRoamingMode() { + assumeTrue(SdkLevel.isAtLeastV()); + when(mWifiRoamingConfigStore.getRoamingMode(CURRENT_SSID)).thenReturn( + TEST_ROAMING_MODE); + mWifiRoamingModeManager.setPerSsidRoamingMode(WifiSsid.fromString(CURRENT_SSID), + TEST_ROAMING_MODE, false); + verify(mWifiRoamingConfigStore).addRoamingMode(CURRENT_SSID, TEST_ROAMING_MODE, false); + verify(mActiveModeWarden).getConnectionInfo(); + // set roaming mode when current network is the updated network + verify(mWifiNative).setRoamingMode(WIFI_IFACE_NAME, TEST_ROAMING_MODE); + } + + @Test + public void testRemovePerSsidRoamingMode() { + assumeTrue(SdkLevel.isAtLeastV()); + mWifiRoamingModeManager.removePerSsidRoamingMode(WifiSsid.fromString(TEST_SSID), false); + verify(mWifiRoamingConfigStore).removeRoamingMode(TEST_SSID, false); + verify(mActiveModeWarden).getConnectionInfo(); + // do not set roaming mode when current network is not the updated network + verify(mWifiNative, never()).setRoamingMode(anyString(), anyInt()); + } + + @Test + public void testGetPerSsidRoamingMode() { + assumeTrue(SdkLevel.isAtLeastV()); + mWifiRoamingModeManager.getPerSsidRoamingModes(false); + verify(mWifiRoamingConfigStore).getPerSsidRoamingModes(false); + verify(mActiveModeWarden, never()).getConnectionInfo(); + } + + @Test + public void testApplyWifiRoamingMode() { + when(mWifiRoamingConfigStore.getRoamingMode(TEST_SSID)).thenReturn( + DEFAULT_ROAMING_MODE); + mWifiRoamingModeManager.applyWifiRoamingMode(WIFI_IFACE_NAME, TEST_SSID); + verify(mWifiNative).setRoamingMode(WIFI_IFACE_NAME, DEFAULT_ROAMING_MODE); + } +} diff --git a/service/tests/wifitests/src/com/android/server/wifi/entitlement/PseudonymInfoTest.java b/service/tests/wifitests/src/com/android/server/wifi/entitlement/PseudonymInfoTest.java index a608780bdf..d89a268dec 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/entitlement/PseudonymInfoTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/entitlement/PseudonymInfoTest.java @@ -23,7 +23,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import android.test.suitebuilder.annotation.SmallTest; +import androidx.test.filters.SmallTest; import org.junit.Test; @@ -53,7 +53,10 @@ public class PseudonymInfoTest { PseudonymInfo pseudonymInfo = new PseudonymInfo(PSEUDONYM, IMSI, TTL_IN_MILLIS); assertEquals(PSEUDONYM, pseudonymInfo.getPseudonym()); assertEquals(TTL_IN_MILLIS, pseudonymInfo.getTtlInMillis()); - assertEquals(TTL_IN_MILLIS - REFRESH_AHEAD_TIME_IN_MILLIS, pseudonymInfo.getLttrInMillis()); + final long delta = Math.abs(TTL_IN_MILLIS - REFRESH_AHEAD_TIME_IN_MILLIS + - pseudonymInfo.getLttrInMillis()); + assertTrue("(" + delta + ") not in 1ms error margin", + delta < 2); assertFalse(pseudonymInfo.hasExpired()); assertFalse(pseudonymInfo.isOldEnoughToRefresh()); } @@ -81,6 +84,9 @@ public class PseudonymInfoTest { public void pseudonymInfoWithSmallTtl() { PseudonymInfo pseudonymInfo = new PseudonymInfo(PSEUDONYM, IMSI, TWENTY_MINUTES_IN_MILLIS); - assertTrue(pseudonymInfo.getLttrInMillis() == TWENTY_MINUTES_IN_MILLIS / 2); + final long delta = Math.abs(TWENTY_MINUTES_IN_MILLIS / 2 + - pseudonymInfo.getLttrInMillis()); + assertTrue("(" + delta + ") not in 1ms error margin", + delta < 2); } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/hal/HalTestUtils.java b/service/tests/wifitests/src/com/android/server/wifi/hal/HalTestUtils.java index abd1b1cc40..724e7cebcd 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/hal/HalTestUtils.java +++ b/service/tests/wifitests/src/com/android/server/wifi/hal/HalTestUtils.java @@ -20,9 +20,21 @@ import static junit.framework.Assert.assertEquals; import static org.mockito.Mockito.when; +import android.hardware.wifi.common.OuiKeyedData; +import android.net.wifi.util.PersistableBundleUtils; +import android.os.PersistableBundle; + +import java.util.ArrayList; +import java.util.List; import java.util.function.Supplier; public class HalTestUtils { + private static final String BUNDLE_STRING_FIELD_KEY = "stringField"; + private static final String BUNDLE_ARRAY_FIELD_KEY = "arrayField"; + + private static final String BUNDLE_STRING_FIELD_VALUE = "someString"; + private static final int[] BUNDLE_ARRAY_FIELD_VALUE = new int[] {1, 2, 3}; + /** * Check that we get the expected return value when the specified method is called. * @@ -35,4 +47,67 @@ public class HalTestUtils { T retrievedValue = calledMethod.get(); assertEquals(value, retrievedValue); } + + /** + * Generate a single PersistableBundle containing several test fields. + */ + private static PersistableBundle createTestPersistableBundle() { + PersistableBundle bundle = new PersistableBundle(); + bundle.putString(BUNDLE_STRING_FIELD_KEY, BUNDLE_STRING_FIELD_VALUE); + bundle.putIntArray(BUNDLE_ARRAY_FIELD_KEY, BUNDLE_ARRAY_FIELD_VALUE); + return bundle; + } + + /** + * Generate a list of HAL OuiKeyedData objects, each containing several test fields. + */ + public static OuiKeyedData[] createHalOuiKeyedDataList(int size) { + OuiKeyedData[] ouiKeyedDataList = new OuiKeyedData[size]; + for (int i = 0; i < size; i++) { + OuiKeyedData ouiKeyedData = new OuiKeyedData(); + ouiKeyedData.oui = i + 1; + ouiKeyedData.vendorData = createTestPersistableBundle(); + ouiKeyedDataList[i] = ouiKeyedData; + } + return ouiKeyedDataList; + } + + /** + * Generate a list of framework OuiKeyedData objects, each containing several test fields. + */ + public static List<android.net.wifi.OuiKeyedData> createFrameworkOuiKeyedDataList(int size) { + List<android.net.wifi.OuiKeyedData> ouiKeyedDataList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + android.net.wifi.OuiKeyedData ouiKeyedData = new android.net.wifi.OuiKeyedData.Builder( + i + 1, createTestPersistableBundle()).build(); + ouiKeyedDataList.add(ouiKeyedData); + } + return ouiKeyedDataList; + } + + /** + * Check whether a HAL and framework OuiKeyedData object are equivalent. + */ + public static boolean ouiKeyedDataEquals( + OuiKeyedData halData, android.net.wifi.OuiKeyedData frameworkData) { + return halData.oui == frameworkData.getOui() + && PersistableBundleUtils.isEqual(halData.vendorData, frameworkData.getData()); + } + + /** + * Check whether a list of HAL and framework OuiKeyedData objects are equivalent. + */ + public static boolean ouiKeyedDataListEquals( + OuiKeyedData[] halDataList, List<android.net.wifi.OuiKeyedData> frameworkDataList) { + if (halDataList.length != frameworkDataList.size()) { + return false; + } + + for (int i = 0; i < halDataList.length; i++) { + if (!ouiKeyedDataEquals(halDataList[i], frameworkDataList.get(i))) { + return false; + } + } + return true; + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiNanIfaceAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiNanIfaceAidlImplTest.java index 0786e60bac..192c97ac8f 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiNanIfaceAidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiNanIfaceAidlImplTest.java @@ -45,15 +45,19 @@ import android.hardware.wifi.NanRangingIndication; import android.hardware.wifi.NanRespondToPairingIndicationRequest; import android.hardware.wifi.NanSubscribeRequest; import android.net.MacAddress; +import android.net.wifi.OuiKeyedData; import android.net.wifi.aware.ConfigRequest; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.SubscribeConfig; import android.net.wifi.aware.WifiAwareDataPathSecurityConfig; +import android.os.PersistableBundle; import android.os.RemoteException; import android.util.Pair; +import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.WifiBaseTest; import com.android.server.wifi.aware.Capabilities; +import com.android.server.wifi.util.HalAidlUtil; import org.junit.Before; import org.junit.Rule; @@ -63,6 +67,10 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + public class WifiNanIfaceAidlImplTest extends WifiBaseTest { private static final Capabilities TEST_CAPABILITIES = new Capabilities(); @@ -79,6 +87,39 @@ public class WifiNanIfaceAidlImplTest extends WifiBaseTest { | WIFI_AWARE_CIPHER_SUITE_NCS_SK_256; } + private static OuiKeyedData generateFrameworkOuiKeyedData(int oui) { + PersistableBundle bundle = new PersistableBundle(); + bundle.putString("stringKey", "stringValue"); + bundle.putInt("intKey", 789); + return new OuiKeyedData.Builder(oui, bundle).build(); + } + + private static List<OuiKeyedData> generateFrameworkOuiKeyedDataList(int size) { + List<OuiKeyedData> dataList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + dataList.add(generateFrameworkOuiKeyedData(i + 1)); + } + return dataList; + } + + private static boolean compareHalOuiKeyedData(android.hardware.wifi.common.OuiKeyedData left, + android.hardware.wifi.common.OuiKeyedData right) { + return left.oui == right.oui && Objects.equals(left.vendorData, right.vendorData); + } + + private static boolean compareHalOuiKeyedDataList( + android.hardware.wifi.common.OuiKeyedData[] left, + android.hardware.wifi.common.OuiKeyedData[] right) { + // Assume both values are non-null + if (left.length != right.length) return false; + for (int i = 0; i < left.length; i++) { + if (!compareHalOuiKeyedData(left[i], right[i])) { + return false; + } + } + return true; + } + @Test public void testDiscoveryRangingSettings() throws RemoteException { short tid = 250; @@ -87,6 +128,9 @@ public class WifiNanIfaceAidlImplTest extends WifiBaseTest { int maxDistanceMm = 555; short minDistanceCm = (short) (minDistanceMm / 10); short maxDistanceCm = (short) (maxDistanceMm / 10); + List<OuiKeyedData> frameworkVendorData = generateFrameworkOuiKeyedDataList(5); + android.hardware.wifi.common.OuiKeyedData[] halVendorData = + HalAidlUtil.frameworkToHalOuiKeyedDataList(frameworkVendorData); ArgumentCaptor<NanPublishRequest> pubCaptor = ArgumentCaptor.forClass( NanPublishRequest.class); @@ -104,6 +148,22 @@ public class WifiNanIfaceAidlImplTest extends WifiBaseTest { SubscribeConfig subWithMinMax = new SubscribeConfig.Builder().setServiceName( "XXX").setMinDistanceMm(minDistanceMm).setMaxDistanceMm(maxDistanceMm).build(); + PublishConfig pubWithVendorData = null; + SubscribeConfig subWithVendorData = null; + if (SdkLevel.isAtLeastV()) { + pubWithVendorData = new PublishConfig.Builder() + .setServiceName("XXX") + .setVendorData(frameworkVendorData) + .build(); + subWithVendorData = new SubscribeConfig.Builder() + .setServiceName("XXX") + .setVendorData(frameworkVendorData) + .build(); + } + + int numPublishExpected = 2; + int numSubscribeExpected = 4; + assertTrue(mDut.publish(tid, pid, pubDefault, null)); assertTrue(mDut.publish(tid, pid, pubWithRanging, null)); assertTrue(mDut.subscribe(tid, pid, subDefault, null)); @@ -111,9 +171,16 @@ public class WifiNanIfaceAidlImplTest extends WifiBaseTest { assertTrue(mDut.subscribe(tid, pid, subWithMax, null)); assertTrue(mDut.subscribe(tid, pid, subWithMinMax, null)); - verify(mIWifiNanIfaceMock, times(2)) + if (SdkLevel.isAtLeastV()) { + assertTrue(mDut.publish(tid, pid, pubWithVendorData, null)); + assertTrue(mDut.subscribe(tid, pid, subWithVendorData, null)); + numPublishExpected += 1; + numSubscribeExpected += 1; + } + + verify(mIWifiNanIfaceMock, times(numPublishExpected)) .startPublishRequest(eq((char) tid), pubCaptor.capture()); - verify(mIWifiNanIfaceMock, times(4)) + verify(mIWifiNanIfaceMock, times(numSubscribeExpected)) .startSubscribeRequest(eq((char) tid), subCaptor.capture()); NanPublishRequest halPubReq; @@ -176,6 +243,13 @@ public class WifiNanIfaceAidlImplTest extends WifiBaseTest { equalTo((short) halSubReq.baseConfigs.distanceEgressCm)); collector.checkThat("subWithMin.baseConfigs.distanceIngressCm", maxDistanceCm, equalTo((short) halSubReq.baseConfigs.distanceIngressCm)); + + if (SdkLevel.isAtLeastV()) { + halPubReq = pubCaptor.getAllValues().get(2); + halSubReq = subCaptor.getAllValues().get(4); + assertTrue(compareHalOuiKeyedDataList(halVendorData, halPubReq.vendorData)); + assertTrue(compareHalOuiKeyedDataList(halVendorData, halSubReq.vendorData)); + } } /** @@ -476,10 +550,11 @@ public class WifiNanIfaceAidlImplTest extends WifiBaseTest { @Test public void testInitiateNanBootstrappingRequest() throws Exception { short tid = 251; + byte pid = 34; MacAddress peer = MacAddress.fromString("00:01:02:03:04:05"); ArgumentCaptor<NanBootstrappingRequest> reqCaptor = ArgumentCaptor.forClass( NanBootstrappingRequest.class); - assertTrue(mDut.initiateNanBootstrappingRequest(tid, 1, peer, 2, null)); + assertTrue(mDut.initiateNanBootstrappingRequest(tid, 1, peer, 2, null, pid, false)); verify(mIWifiNanIfaceMock).initiateBootstrappingRequest(eq((char) tid), reqCaptor.capture()); NanBootstrappingRequest request = reqCaptor.getValue(); @@ -487,19 +562,22 @@ public class WifiNanIfaceAidlImplTest extends WifiBaseTest { assertEquals(2, request.requestBootstrappingMethod); assertArrayEquals(peer.toByteArray(), request.peerDiscMacAddr); assertArrayEquals(new byte[0], request.cookie); + assertEquals(pid, request.discoverySessionId); } @Test public void testRespondToNanBootstrappingRequest() throws Exception { short tid = 251; + byte pid = 34; ArgumentCaptor<NanBootstrappingResponse> reqCaptor = ArgumentCaptor.forClass( NanBootstrappingResponse.class); - assertTrue(mDut.respondToNanBootstrappingRequest(tid, 1, true)); + assertTrue(mDut.respondToNanBootstrappingRequest(tid, 1, true, pid)); verify(mIWifiNanIfaceMock).respondToBootstrappingIndicationRequest(eq((char) tid), reqCaptor.capture()); NanBootstrappingResponse request = reqCaptor.getValue(); assertEquals(1, request.bootstrappingInstanceId); assertTrue(request.acceptRequest); + assertEquals(pid, request.discoverySessionId); } // utilities diff --git a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerAidlImplTest.java index ef10eff7c0..6b541a7bd3 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerAidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerAidlImplTest.java @@ -38,6 +38,7 @@ import android.hardware.wifi.RttType; import android.hardware.wifi.WifiChannelWidthInMhz; import android.hardware.wifi.WifiInformationElement; import android.net.MacAddress; +import android.net.wifi.ScanResult; import android.net.wifi.rtt.RangingRequest; import android.net.wifi.rtt.RangingResult; import android.net.wifi.rtt.ResponderConfig; @@ -89,6 +90,42 @@ public class WifiRttControllerAidlImplTest extends WifiBaseTest { } /** + * Verify RTT burst duration with respect to different burst sizes. + */ + @Test + public void testBurstDuration() throws Exception { + int cmdId = 55; + RangingRequest request = RttTestUtils.getDummyRangingRequestMcOnly((byte) 0, 8); + mDut.rangeRequest(cmdId, request); + verify(mIWifiRttControllerMock).rangeRequest(eq(cmdId), mRttConfigCaptor.capture()); + RttConfig[] halRequest = mRttConfigCaptor.getValue(); + RttConfig rttConfig = halRequest[0]; + collector.checkThat("(1) Rtt burst size", rttConfig.numFramesPerBurst, equalTo(8)); + collector.checkThat("(1) Rtt burst duration", rttConfig.burstDuration, equalTo(9)); + + cmdId = 56; + request = RttTestUtils.getDummyRangingRequestMcOnly((byte) 0, 20); + mDut.rangeRequest(cmdId, request); + verify(mIWifiRttControllerMock).rangeRequest(eq(cmdId), mRttConfigCaptor.capture()); + halRequest = mRttConfigCaptor.getValue(); + rttConfig = halRequest[0]; + collector.checkThat("(2) Rtt burst size", rttConfig.numFramesPerBurst, equalTo(20)); + collector.checkThat("(2) Rtt burst duration", rttConfig.burstDuration, equalTo(10)); + + cmdId = 57; + request = RttTestUtils.getDummyRangingRequestMcOnly((byte) 0, 30); + mDut.rangeRequest(cmdId, request); + verify(mIWifiRttControllerMock).rangeRequest(eq(cmdId), mRttConfigCaptor.capture()); + halRequest = mRttConfigCaptor.getValue(); + rttConfig = halRequest[0]; + collector.checkThat("(3) Rtt burst size", rttConfig.numFramesPerBurst, equalTo(30)); + collector.checkThat("(3) Rtt burst duration", rttConfig.burstDuration, equalTo(11)); + + verifyNoMoreInteractions(mIWifiRttControllerMock); + + } + + /** * Validate successful ranging flow. */ @Test @@ -286,6 +323,7 @@ public class WifiRttControllerAidlImplTest extends WifiBaseTest { res.status = RttStatus.SUCCESS; res.distanceInMm = 1500; res.timeStampInUs = 6000; + res.packetBw = RttBw.BW_80MHZ; results[0] = res; // (1) have the HAL call us with results @@ -306,7 +344,8 @@ public class WifiRttControllerAidlImplTest extends WifiBaseTest { equalTo(MacAddress.fromString("05:06:07:08:09:0A").toByteArray())); collector.checkThat("distanceCm", rttResult.getDistanceMm(), equalTo(1500)); collector.checkThat("timestamp", rttResult.getRangingTimestampMillis(), equalTo(6L)); - + collector.checkThat("channelBw", rttResult.getMeasurementBandwidth(), + equalTo(ScanResult.CHANNEL_WIDTH_80MHZ)); verifyNoMoreInteractions(mIWifiRttControllerMock); } @@ -350,12 +389,20 @@ public class WifiRttControllerAidlImplTest extends WifiBaseTest { public void testRangingWithInvalidParameterCombination() throws Exception { int cmdId = 88; RangingRequest request = new RangingRequest.Builder().build(); - ResponderConfig invalidConfig = new ResponderConfig( - MacAddress.fromString("08:09:08:07:06:88"), ResponderConfig.RESPONDER_AP, true, - ResponderConfig.CHANNEL_WIDTH_80MHZ, 0, 0, 0, ResponderConfig.PREAMBLE_HT); - ResponderConfig config = new ResponderConfig( - MacAddress.fromString("08:09:08:07:06:89"), ResponderConfig.RESPONDER_AP, true, - ResponderConfig.CHANNEL_WIDTH_80MHZ, 0, 0, 0, ResponderConfig.PREAMBLE_VHT); + ResponderConfig invalidConfig = new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromString("08:09:08:07:06:88")) + .setResponderType(ResponderConfig.RESPONDER_AP) + .set80211mcSupported(true) + .setChannelWidth(ScanResult.CHANNEL_WIDTH_80MHZ) + .setPreamble(ScanResult.PREAMBLE_HT) + .build(); + ResponderConfig config = new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromString("08:09:08:07:06:89")) + .setResponderType(ResponderConfig.RESPONDER_AP) + .set80211mcSupported(true) + .setChannelWidth(ScanResult.CHANNEL_WIDTH_80MHZ) + .setPreamble(ScanResult.PREAMBLE_VHT) + .build(); // Add a ResponderConfig with invalid parameter, should be ignored. request.mRttPeers.add(invalidConfig); diff --git a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerHidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerHidlImplTest.java index 632776095b..fdd63d31e1 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerHidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiRttControllerHidlImplTest.java @@ -41,6 +41,7 @@ import android.hardware.wifi.V1_0.WifiChannelWidthInMhz; import android.hardware.wifi.V1_0.WifiStatus; import android.hardware.wifi.V1_0.WifiStatusCode; import android.net.MacAddress; +import android.net.wifi.ScanResult; import android.net.wifi.rtt.RangingRequest; import android.net.wifi.rtt.RangingResult; import android.net.wifi.rtt.ResponderConfig; @@ -366,12 +367,20 @@ public class WifiRttControllerHidlImplTest extends WifiBaseTest { public void testRangingWithInvalidParameterCombination() throws Exception { int cmdId = 88; RangingRequest request = new RangingRequest.Builder().build(); - ResponderConfig invalidConfig = new ResponderConfig( - MacAddress.fromString("08:09:08:07:06:88"), ResponderConfig.RESPONDER_AP, true, - ResponderConfig.CHANNEL_WIDTH_80MHZ, 0, 0, 0, ResponderConfig.PREAMBLE_HT); - ResponderConfig config = new ResponderConfig(MacAddress.fromString("08:09:08:07:06:89"), - ResponderConfig.RESPONDER_AP, true, - ResponderConfig.CHANNEL_WIDTH_80MHZ, 0, 0, 0, ResponderConfig.PREAMBLE_VHT); + ResponderConfig invalidConfig = new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromString("08:09:08:07:06:88")) + .setResponderType(ResponderConfig.RESPONDER_AP) + .set80211mcSupported(true) + .setChannelWidth(ScanResult.CHANNEL_WIDTH_80MHZ) + .setPreamble(ScanResult.PREAMBLE_HT) + .build(); + ResponderConfig config = new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromString("08:09:08:07:06:89")) + .setResponderType(ResponderConfig.RESPONDER_AP) + .set80211mcSupported(true) + .setChannelWidth(ScanResult.CHANNEL_WIDTH_80MHZ) + .setPreamble(ScanResult.PREAMBLE_VHT) + .build(); // Add a ResponderConfig with invalid parameter, should be ignored. request.mRttPeers.add(invalidConfig); diff --git a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiStaIfaceAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiStaIfaceAidlImplTest.java index 0ed10caca4..95b978eb01 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/hal/WifiStaIfaceAidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/hal/WifiStaIfaceAidlImplTest.java @@ -19,11 +19,14 @@ package com.android.server.wifi.hal; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; +import android.hardware.wifi.CachedScanData; +import android.hardware.wifi.CachedScanResult; import android.hardware.wifi.IWifiStaIface; import android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats; import android.hardware.wifi.StaLinkLayerIfacePacketStats; @@ -34,8 +37,10 @@ import android.hardware.wifi.StaLinkLayerStats; import android.hardware.wifi.StaPeerInfo; import android.hardware.wifi.StaRateStat; import android.hardware.wifi.StaRoamingCapabilities; +import android.hardware.wifi.StaRoamingState; import android.hardware.wifi.WifiChannelInfo; import android.hardware.wifi.WifiChannelStats; +import android.hardware.wifi.WifiChannelWidthInMhz; import android.hardware.wifi.WifiDebugPacketFateFrameInfo; import android.hardware.wifi.WifiDebugPacketFateFrameType; import android.hardware.wifi.WifiDebugRxPacketFate; @@ -43,7 +48,12 @@ import android.hardware.wifi.WifiDebugRxPacketFateReport; import android.hardware.wifi.WifiDebugTxPacketFate; import android.hardware.wifi.WifiDebugTxPacketFateReport; import android.hardware.wifi.WifiRateInfo; +import android.hardware.wifi.WifiRatePreamble; +import android.hardware.wifi.WifiStatusCode; +import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; +import android.net.wifi.WifiScanner.ScanData; +import android.net.wifi.WifiSsid; import com.android.server.wifi.SsidTranslator; import com.android.server.wifi.WifiBaseTest; @@ -57,6 +67,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Random; @@ -313,6 +324,52 @@ public class WifiStaIfaceAidlImplTest extends WifiBaseTest { assertEquals(WifiNative.SET_FIRMWARE_ROAMING_FAILURE, mDut.setRoamingState(badState)); } + /** + * Test the retrieval of cached scan data + */ + @Test + public void testGetCachedScanData() throws Exception { + CachedScanData halData = new CachedScanData(); + CachedScanResult[] halResults = new CachedScanResult[2]; + CachedScanResult halResult = new CachedScanResult(); + halData.cachedScanResults = halResults; + halResults[0] = halResult; + halResult.timeStampInUs = 10_000_000; + halResult.bssid = new byte[]{0x61, 0x52, 0x43, 0x34, 0x25, 0x16}; + String test_ssid = "Test SSID"; + halResult.ssid = test_ssid.getBytes(StandardCharsets.UTF_8); + halResult.rssiDbm = -80; + halResult.frequencyMhz = 5260; + halResult.channelWidthMhz = WifiChannelWidthInMhz.WIDTH_80; + halResult.preambleType = WifiRatePreamble.HE; + + when(mIWifiStaIfaceMock.getCachedScanData()) + .thenReturn(halData); + when(mSsidTranslatorMock.getTranslatedSsidAndRecordBssidCharset(any(), any())) + .thenReturn(WifiSsid.fromBytes(halResult.ssid)); + + ScanData scanData = mDut.getCachedScanData(); + ScanResult[] scanResults = scanData.getResults(); + assertEquals(1, scanResults.length); + assertEquals(10_000_000, scanResults[0].timestamp); + assertEquals(-80, scanResults[0].level); + assertEquals(5260, scanResults[0].frequency); + assertEquals(ScanResult.CHANNEL_WIDTH_80MHZ, scanResults[0].channelWidth); + assertEquals(ScanResult.WIFI_STANDARD_11AX, scanResults[0].getWifiStandard()); + assertEquals("61:52:43:34:25:16", scanResults[0].BSSID); + } + + /** + * Tests setRoamingMode. + */ + @Test + public void testSetRoamingMode() throws Exception { + final int invalidRoamingMode = -1; + assertEquals(WifiStatusCode.ERROR_INVALID_ARGS, mDut.setRoamingMode(invalidRoamingMode)); + + assertEquals(WifiStatusCode.SUCCESS, mDut.setRoamingMode(WifiManager.ROAMING_MODE_NORMAL)); + verify(mIWifiStaIfaceMock).setRoamingState(StaRoamingState.ENABLED); + } // Utilities diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImplTest.java index b4a3cb03ca..208a01b912 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceCallbackAidlImplTest.java @@ -20,6 +20,7 @@ import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTL import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -30,14 +31,20 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.test.MockAnswerUtil.AnswerWithArguments; +import android.hardware.wifi.common.OuiKeyedData; import android.hardware.wifi.supplicant.P2pClientEapolIpAddressInfo; import android.hardware.wifi.supplicant.P2pDeviceFoundEventParams; +import android.hardware.wifi.supplicant.P2pGoNegotiationReqEventParams; import android.hardware.wifi.supplicant.P2pGroupStartedEventParams; +import android.hardware.wifi.supplicant.P2pInvitationEventParams; +import android.hardware.wifi.supplicant.P2pPeerClientDisconnectedEventParams; +import android.hardware.wifi.supplicant.P2pPeerClientJoinedEventParams; import android.hardware.wifi.supplicant.P2pProvDiscStatusCode; import android.hardware.wifi.supplicant.P2pProvisionDiscoveryCompletedEventParams; import android.hardware.wifi.supplicant.P2pStatusCode; import android.hardware.wifi.supplicant.WpsConfigMethods; import android.hardware.wifi.supplicant.WpsDevPasswordId; +import android.net.MacAddress; import android.net.wifi.ScanResult; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; @@ -45,11 +52,14 @@ import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pProvDiscEvent; import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; +import android.os.PersistableBundle; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.WifiBaseTest; import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus; +import com.android.server.wifi.util.HalAidlUtil; import com.android.server.wifi.util.NativeUtil; import org.junit.Before; @@ -83,6 +93,7 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { private static final String DEVICE_ADDRESS_STR = "00:01:02:03:04:05"; private static final int TEST_NETWORK_ID = 9; private static final int TEST_GROUP_FREQUENCY = 5400; + private static final int DEFAULT_SERVICE_VERSION = 2; private byte[] mTestPrimaryDeviceTypeBytes = { 0x00, 0x01, 0x02, -1, 0x04, 0x05, 0x06, 0x07 }; private String mTestPrimaryDeviceTypeString = "1-02FF0405-1543"; private String mTestDeviceName = "test device name"; @@ -91,8 +102,9 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { private int mTestGroupCapabilities = 456; private class SupplicantP2pIfaceCallbackImplSpy extends SupplicantP2pIfaceCallbackAidlImpl { - SupplicantP2pIfaceCallbackImplSpy(String iface, WifiP2pMonitor monitor) { - super(iface, monitor); + SupplicantP2pIfaceCallbackImplSpy(String iface, WifiP2pMonitor monitor, + int serviceVersion) { + super(iface, monitor, serviceVersion); } } @@ -100,7 +112,11 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mMonitor = mock(WifiP2pMonitor.class); - mDut = new SupplicantP2pIfaceCallbackImplSpy(mIface, mMonitor); + initializeDut(DEFAULT_SERVICE_VERSION); + } + + private void initializeDut(int serviceVersion) { + mDut = new SupplicantP2pIfaceCallbackImplSpy(mIface, mMonitor, serviceVersion); } /** @@ -150,6 +166,79 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { anyString(), any(WifiP2pDevice.class)); } + private static OuiKeyedData generateHalOuiKeyedData(int oui) { + PersistableBundle bundle = new PersistableBundle(); + bundle.putString("stringKey", "stringValue"); + bundle.putInt("intKey", 789); + + OuiKeyedData data = new OuiKeyedData(); + data.oui = oui; + data.vendorData = bundle; + return data; + } + + private static OuiKeyedData[] generateHalOuiKeyedDataList(int size) { + OuiKeyedData[] dataList = new OuiKeyedData[size]; + for (int i = 0; i < size; i++) { + dataList[i] = generateHalOuiKeyedData(i + 1); + } + return dataList; + } + + /** + * Sunny day scenario for testOnDeviceFoundWithParams call. + */ + @Test + public void testOnDeviceFoundWithParams_success() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + initializeDut(3 /* serviceVersion */); + 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; + int fakeGroupCapabilities = 456; + OuiKeyedData[] halVendorData = generateHalOuiKeyedDataList(5); + + P2pDeviceFoundEventParams params = new P2pDeviceFoundEventParams(); + params.srcAddress = mDeviceAddress1Bytes; + params.p2pDeviceAddress = mDeviceAddress2Bytes; + params.primaryDeviceType = fakePrimaryDeviceTypeBytes; + params.deviceName = fakeDeviceName; + params.configMethods = fakeConfigMethods; + params.deviceCapabilities = fakeCapabilities; + params.groupCapabilities = fakeGroupCapabilities; + params.wfdDeviceInfo = mDeviceInfoBytes; + params.vendorData = halVendorData; + + doAnswer(new AnswerWithArguments() { + public void answer(String iface, WifiP2pDevice device) { + // NOTE: mDeviceAddress1Bytes seems to be ignored by + // legacy implementation of WifiP2pDevice. + assertEquals(iface, mIface); + assertEquals(device.deviceName, fakeDeviceName); + assertEquals(device.primaryDeviceType, fakePrimaryDeviceTypeString); + assertEquals(device.deviceCapability, fakeCapabilities); + assertEquals(device.groupCapability, fakeGroupCapabilities); + assertEquals(device.wpsConfigMethodsSupported, fakeConfigMethods); + assertEquals(device.deviceAddress, mDeviceAddress2String); + assertEquals(device.status, WifiP2pDevice.AVAILABLE); + assertEquals(device.getVendorData(), + HalAidlUtil.halToFrameworkOuiKeyedDataList(halVendorData)); + } + }).when(mMonitor).broadcastP2pDeviceFound( + anyString(), any(WifiP2pDevice.class)); + + mDut.onDeviceFoundWithParams(params); + + params.wfdDeviceInfo = null; + mDut.onDeviceFoundWithParams(params); + + // Make sure we issued a broadcast each time. + verify(mMonitor, times(2)).broadcastP2pDeviceFound( + anyString(), any(WifiP2pDevice.class)); + } + /** * Sunny day scenario for onDeviceFound call with sign bit set in bytes. */ @@ -340,6 +429,60 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { anyString(), any(WifiP2pDevice.class)); } + private static OuiKeyedData[] createTestVendorData() { + int oui = 0x0033aabb; + OuiKeyedData vendorDataElement = new OuiKeyedData(); + vendorDataElement.oui = oui; + vendorDataElement.vendorData = new PersistableBundle(); + return new OuiKeyedData[]{vendorDataElement}; + } + + /** + * Sunny day scenario for onGoNegotiationRequestWithParams call. + */ + @Test + public void testOnGoNegotiationRequestWithParams_success() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + initializeDut(3 /* serviceVersion */); + HashSet<Integer> setups = new HashSet<Integer>(); + + P2pGoNegotiationReqEventParams params = new P2pGoNegotiationReqEventParams(); + params.srcAddress = mDeviceAddress1Bytes; + params.passwordId = WpsDevPasswordId.USER_SPECIFIED; + params.vendorData = createTestVendorData(); + + doAnswer(new AnswerWithArguments() { + public void answer(String iface, WifiP2pConfig config) { + assertEquals(iface, mIface); + assertNotNull(config.wps); + setups.add(config.wps.setup); + assertEquals(config.deviceAddress, mDeviceAddress1String); + assertEquals(params.vendorData[0].oui, config.getVendorData().get(0).getOui()); + } + }).when(mMonitor).broadcastP2pGoNegotiationRequest( + anyString(), any(WifiP2pConfig.class)); + + mDut.onGoNegotiationRequestWithParams(params); + assertTrue(setups.contains(WpsInfo.DISPLAY)); + + params.passwordId = WpsDevPasswordId.PUSHBUTTON; + + mDut.onGoNegotiationRequestWithParams(params); + assertTrue(setups.contains(WpsInfo.PBC)); + + params.passwordId = WpsDevPasswordId.REGISTRAR_SPECIFIED; + + mDut.onGoNegotiationRequestWithParams(params); + assertTrue(setups.contains(WpsInfo.KEYPAD)); + + params.passwordId = 0xffff; + + // Invalid should default to PBC + setups.clear(); + mDut.onGoNegotiationRequestWithParams(params); + assertTrue(setups.contains(WpsInfo.PBC)); + } + /** * Sunny day scenario for onGroupStarted call. */ @@ -477,6 +620,59 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { } /** + * Sunny day scenario for onGroupStartedWithParams call when the parameters + * include vendor data. + */ + @Test + public void testOnGroupStartedWithParams_vendorData_success() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + initializeDut(3 /* serviceVersion */); + String fakeName = "group name"; + String fakePassphrase = "secret"; + byte[] fakeSsidBytesList = new byte[] {0x30, 0x31, 0x32, 0x33}; + String fakeSsidString = "0123"; + HashSet<String> passwords = new HashSet<String>(); + OuiKeyedData[] halVendorData = generateHalOuiKeyedDataList(5); + + P2pGroupStartedEventParams params = new P2pGroupStartedEventParams(); + params.groupInterfaceName = fakeName; + params.isGroupOwner = true; + params.ssid = fakeSsidBytesList; + params.frequencyMHz = 1; + params.psk = null; + params.passphrase = fakePassphrase; + params.isPersistent = true; + params.goDeviceAddress = mDeviceAddress1Bytes; + params.isP2pClientEapolIpAddressInfoPresent = true; + params.vendorData = halVendorData; + + doAnswer(new AnswerWithArguments() { + public void answer(String iface, WifiP2pGroup group) { + assertEquals(iface, mIface); + assertNotNull(group.getOwner()); + assertEquals(group.getOwner().deviceAddress, mDeviceAddress1String); + assertEquals(group.getNetworkId(), WifiP2pGroup.NETWORK_ID_PERSISTENT); + passwords.add(group.getPassphrase()); + assertEquals(group.getInterface(), fakeName); + assertEquals(group.getNetworkName(), fakeSsidString); + assertEquals(group.getVendorData(), + HalAidlUtil.halToFrameworkOuiKeyedDataList(halVendorData)); + } + }).when(mMonitor).broadcastP2pGroupStarted( + anyString(), any(WifiP2pGroup.class)); + + mDut.onGroupStartedWithParams(params); + assertTrue(passwords.contains(fakePassphrase)); + + params.passphrase = null; + mDut.onGroupStartedWithParams(params); + assertTrue(passwords.contains(null)); + + verify(mMonitor, times(2)).broadcastP2pGroupStarted( + anyString(), any(WifiP2pGroup.class)); + } + + /** * Failing scenarios for onGroupStartedWithParams call. */ @Test @@ -640,6 +836,35 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { assertEquals(WifiP2pProvDiscEvent.PBC_REQ, discEventCaptor.getValue().event); } + /** + * Test provision discovery event callback when the event contains vendor data. + */ + @Test + public void testOnProvisionDiscoveryCompletedEvent_vendorData() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + initializeDut(3 /* serviceVersion */); + OuiKeyedData[] halVendorData = generateHalOuiKeyedDataList(5); + List<android.net.wifi.OuiKeyedData> frameworkVendorData = + HalAidlUtil.halToFrameworkOuiKeyedDataList(halVendorData); + + P2pProvisionDiscoveryCompletedEventParams params = + new P2pProvisionDiscoveryCompletedEventParams(); + params.p2pDeviceAddress = DEVICE_ADDRESS; + params.isRequest = false; + params.status = P2pProvDiscStatusCode.SUCCESS; + params.configMethods = WpsConfigMethods.DISPLAY; + params.generatedPin = "12345678"; + params.vendorData = halVendorData; + + ArgumentCaptor<WifiP2pProvDiscEvent> discEventCaptor = + ArgumentCaptor.forClass(WifiP2pProvDiscEvent.class); + mDut.onProvisionDiscoveryCompletedEvent(params); + verify(mMonitor).broadcastP2pProvisionDiscoveryEnterPin( + anyString(), discEventCaptor.capture()); + assertEquals(WifiP2pProvDiscEvent.ENTER_PIN, discEventCaptor.getValue().event); + assertEquals(frameworkVendorData, discEventCaptor.getValue().getVendorData()); + } + private void verifyProvisionDiscoveryFailureEvent( int halStatus, int expectedStatus) throws Exception { byte[] p2pDeviceAddr = DEVICE_ADDRESS; @@ -726,6 +951,33 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { assertEquals(mDeviceAddress1String, p2pDeviceCaptor.getValue().deviceAddress); } + /** + * Test onPeerClientJoined + */ + @Test + public void testOnPeerClientJoined() { + assumeTrue(SdkLevel.isAtLeastV()); + initializeDut(3 /* serviceVersion */); + OuiKeyedData[] halVendorData = generateHalOuiKeyedDataList(5); + List<android.net.wifi.OuiKeyedData> frameworkVendorData = + HalAidlUtil.halToFrameworkOuiKeyedDataList(halVendorData); + + P2pPeerClientJoinedEventParams params = new P2pPeerClientJoinedEventParams(); + params.clientInterfaceAddress = mDeviceAddress1Bytes; + params.clientDeviceAddress = mDeviceAddress2Bytes; + params.vendorData = halVendorData; + params.clientIpAddress = 0xc831a8c0; + + ArgumentCaptor<WifiP2pDevice> p2pDeviceCaptor = + ArgumentCaptor.forClass(WifiP2pDevice.class); + mDut.onPeerClientJoined(params); + verify(mMonitor).broadcastP2pApStaConnected(eq(mIface), p2pDeviceCaptor.capture()); + assertEquals(mDeviceAddress2String, p2pDeviceCaptor.getValue().deviceAddress); + assertEquals(MacAddress.fromBytes(mDeviceAddress1Bytes), + p2pDeviceCaptor.getValue().getInterfaceMacAddress()); + assertEquals(frameworkVendorData, p2pDeviceCaptor.getValue().getVendorData()); + } + // TLVS hex data encoded as a hex string. // Taken directly from an observed supplicant service response event private static final String SERV_DISC_RESP_TLVS = "1d00010100076578616d706c650b5f6166706f766572" @@ -855,6 +1107,33 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { } /** + * Test testOnInvitationReceivedWithParams should trigger P2pInvitationReceived broadcast. + */ + @Test + public void testOnInvitationReceivedWithParams() { + assumeTrue(SdkLevel.isAtLeastV()); + initializeDut(3 /* serviceVersion */); + + P2pInvitationEventParams params = new P2pInvitationEventParams(); + params.srcAddress = mDeviceAddress1Bytes; + params.goDeviceAddress = mDeviceAddress2Bytes; + params.bssid = DEVICE_ADDRESS; + params.persistentNetworkId = TEST_NETWORK_ID; + params.operatingFrequencyMHz = TEST_GROUP_FREQUENCY; + params.vendorData = createTestVendorData(); + + mDut.onInvitationReceivedWithParams(params); + + ArgumentCaptor<WifiP2pGroup> groupCaptor = ArgumentCaptor.forClass(WifiP2pGroup.class); + verify(mMonitor).broadcastP2pInvitationReceived(eq(mIface), groupCaptor.capture()); + + WifiP2pGroup group = groupCaptor.getValue(); + assertEquals(TEST_NETWORK_ID, group.getNetworkId()); + assertEquals(mDeviceAddress2String, group.getOwner().deviceAddress); + assertEquals(params.vendorData[0].oui, group.getVendorData().get(0).getOui()); + } + + /** * Test onInvitationResult should trigger P2pInvitationResult broadcast. */ @Test @@ -877,6 +1156,32 @@ public class SupplicantP2pIfaceCallbackAidlImplTest extends WifiBaseTest { } /** + * Test onP2pApStaDisconnected callback + */ + @Test + public void testOnPeerClientDisconnected() { + assumeTrue(SdkLevel.isAtLeastV()); + initializeDut(3 /* serviceVersion */); + OuiKeyedData[] halVendorData = generateHalOuiKeyedDataList(5); + List<android.net.wifi.OuiKeyedData> frameworkVendorData = + HalAidlUtil.halToFrameworkOuiKeyedDataList(halVendorData); + + P2pPeerClientDisconnectedEventParams params = new P2pPeerClientDisconnectedEventParams(); + params.clientInterfaceAddress = mDeviceAddress1Bytes; + params.clientDeviceAddress = mDeviceAddress2Bytes; + params.vendorData = halVendorData; + + ArgumentCaptor<WifiP2pDevice> p2pDeviceCaptor = + ArgumentCaptor.forClass(WifiP2pDevice.class); + mDut.onPeerClientDisconnected(params); + verify(mMonitor).broadcastP2pApStaDisconnected(eq(mIface), p2pDeviceCaptor.capture()); + assertEquals(mDeviceAddress2String, p2pDeviceCaptor.getValue().deviceAddress); + assertEquals(MacAddress.fromBytes(mDeviceAddress1Bytes), + p2pDeviceCaptor.getValue().getInterfaceMacAddress()); + assertEquals(frameworkVendorData, p2pDeviceCaptor.getValue().getVendorData()); + } + + /** * Test the sunny case of onDeviceFoundWithVendorElements. */ @Test diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImplTest.java index 6de2b79486..9cb54e710f 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalAidlImplTest.java @@ -19,8 +19,10 @@ import static org.junit.Assert.assertArrayEquals; 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; +import static org.junit.Assume.assumeTrue; import static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; @@ -29,6 +31,7 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -49,27 +52,34 @@ import android.hardware.wifi.supplicant.ISupplicantP2pNetwork; import android.hardware.wifi.supplicant.IfaceInfo; import android.hardware.wifi.supplicant.MacAddress; import android.hardware.wifi.supplicant.MiracastMode; +import android.hardware.wifi.supplicant.P2pConnectInfo; +import android.hardware.wifi.supplicant.P2pExtListenInfo; import android.hardware.wifi.supplicant.P2pFrameTypeMask; import android.hardware.wifi.supplicant.SupplicantStatusCode; import android.hardware.wifi.supplicant.WpsProvisionMethod; import android.net.wifi.CoexUnsafeChannel; +import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; import android.os.IBinder; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.text.TextUtils; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.WifiBaseTest; import com.android.server.wifi.WifiInjector; +import com.android.server.wifi.WifiNative; import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.util.NativeUtil; @@ -100,7 +110,13 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { private @Mock WifiP2pMonitor mWifiMonitor; private @Mock WifiInjector mWifiInjector; private @Mock IBinder mServiceBinderMock; + private @Mock WifiSettingsConfigStore mWifiSettingsConfigStore; + private @Mock WifiNative.SupplicantDeathEventHandler mSupplicantHalDeathHandler; + private ArgumentCaptor<IBinder.DeathRecipient> mSupplicantDeathCaptor = + ArgumentCaptor.forClass(IBinder.DeathRecipient.class); + + final int mServiceVersion = 2; final String mIfaceName = "virtual_interface_name"; final String mSsid = "\"SSID\""; final byte[] mSsidBytes = {'S', 'S', 'I', 'D'}; @@ -164,6 +180,7 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mDut = new SupplicantP2pIfaceHalSpy(); + setCachedServiceVersion(mServiceVersion); } /** @@ -646,12 +663,13 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { } /** - * Sunny day scenario for connect() + * Sunny day scenario for connect() using the HAL method for AIDL <= 2. */ @Test - public void testConnect_success() throws Exception { + public void testConnect_V2_success() throws Exception { final String configPin = "12345"; final HashSet<Integer> methods = new HashSet<>(); + setCachedServiceVersion(2); doAnswer(new AnswerWithArguments() { public String answer(byte[] peer, int method, String pin, boolean joinExisting, @@ -700,6 +718,61 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { } /** + * Sunny day scenario for connect() using the HAL method for AIDL >= 3. + */ + @Test + public void testConnect_V3_success() throws Exception { + final String configPin = "12345"; + final HashSet<Integer> methods = new HashSet<>(); + setCachedServiceVersion(3); + + doAnswer(new AnswerWithArguments() { + public String answer(P2pConnectInfo info) throws RemoteException { + String pin = info.preSelectedPin; + int method = info.provisionMethod; + methods.add(method); + + if (method == WpsProvisionMethod.DISPLAY && TextUtils.isEmpty(pin)) { + // Return the configPin for DISPLAY method if the pin was not provided. + return configPin; + } else { + if (method != WpsProvisionMethod.PBC) { + // PIN is only required for PIN methods. + assertEquals(pin, configPin); + } + // For all the other cases, there is no generated pin. + return ""; + } + } + }).when(mISupplicantP2pIfaceMock).connectWithParams(any(P2pConnectInfo.class)); + + WifiP2pConfig config = createPlaceholderP2pConfig(mPeerMacAddress, WpsInfo.DISPLAY, ""); + + // Default value when service is not initialized. + assertNull(mDut.connect(config, false)); + + executeAndValidateInitializationSequence(false, false); + + assertEquals(configPin, mDut.connect(config, false)); + assertTrue(methods.contains(WpsProvisionMethod.DISPLAY)); + methods.clear(); + + config = createPlaceholderP2pConfig(mPeerMacAddress, WpsInfo.DISPLAY, configPin); + assertTrue(mDut.connect(config, false).isEmpty()); + assertTrue(methods.contains(WpsProvisionMethod.DISPLAY)); + methods.clear(); + + config = createPlaceholderP2pConfig(mPeerMacAddress, WpsInfo.PBC, ""); + assertTrue(mDut.connect(config, false).isEmpty()); + assertTrue(methods.contains(WpsProvisionMethod.PBC)); + methods.clear(); + + config = createPlaceholderP2pConfig(mPeerMacAddress, WpsInfo.KEYPAD, configPin); + assertTrue(mDut.connect(config, false).isEmpty()); + assertTrue(methods.contains(WpsProvisionMethod.KEYPAD)); + } + + /** * Test connect with invalid arguments. */ @Test @@ -746,6 +819,7 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { WifiP2pConfig config = createPlaceholderP2pConfig(mPeerMacAddress, WpsInfo.DISPLAY, configPin); + setCachedServiceVersion(2); executeAndValidateInitializationSequence(false, false); doThrow(new ServiceSpecificException(SupplicantStatusCode.FAILURE_UNKNOWN)) .when(mISupplicantP2pIfaceMock).connect(eq(mPeerMacAddressBytes), anyInt(), @@ -1401,6 +1475,13 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { assertFalse(mDut.isInitializationComplete()); } + private void setCachedServiceVersion(int version) { + when(mWifiSettingsConfigStore + .get(eq(WifiSettingsConfigStore.SUPPLICANT_HAL_AIDL_SERVICE_VERSION))) + .thenReturn(version); + when(mWifiInjector.getSettingsConfigStore()).thenReturn(mWifiSettingsConfigStore); + } + /** * Sunny day scenario for configureExtListen() */ @@ -1411,15 +1492,45 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { .configureExtListen(anyInt(), anyInt()); doNothing().when(mISupplicantP2pIfaceMock).configureExtListen(eq(123), eq(456)); doNothing().when(mISupplicantP2pIfaceMock).configureExtListen(eq(0), eq(0)); + setCachedServiceVersion(2); // Default value when service is not initialized. - assertFalse(mDut.configureExtListen(true, 123, 456)); + assertFalse(mDut.configureExtListen(true, 123, 456, null)); executeAndValidateInitializationSequence(false, false); - assertTrue(mDut.configureExtListen(true, 123, 456)); + assertTrue(mDut.configureExtListen(true, 123, 456, null)); // Turning listening off should reset intervals to 0s. - assertTrue(mDut.configureExtListen(false, 999, 999)); + assertTrue(mDut.configureExtListen(false, 999, 999, null)); + // Disable listening. + assertTrue(mDut.configureExtListen(false, -1, -1, null)); + } + + /** + * Sunny day scenario for configureExtListenWithParams() + */ + @Test + public void testConfigureExtListenWithParams_success() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + setCachedServiceVersion(3); // API requires HAL >= 3 + + OuiKeyedData vendorDataElement = + new OuiKeyedData.Builder(0x00aabbcc, new PersistableBundle()).build(); + List<OuiKeyedData> vendorData = Arrays.asList(vendorDataElement); + WifiP2pExtListenParams extListenParams = + new WifiP2pExtListenParams.Builder().setVendorData(vendorData).build(); + + // Default value when service is not initialized. + assertFalse(mDut.configureExtListen(true, 123, 456, extListenParams)); + + executeAndValidateInitializationSequence(false, false); + assertTrue(mDut.configureExtListen(true, 123, 456, extListenParams)); + // Disable listening. - assertTrue(mDut.configureExtListen(false, -1, -1)); + assertTrue(mDut.configureExtListen(false, -1, -1, extListenParams)); + + // Legacy HAL API should not get called. + verify(mISupplicantP2pIfaceMock, atLeastOnce()) + .configureExtListenWithParams(any(P2pExtListenInfo.class)); + verify(mISupplicantP2pIfaceMock, never()).configureExtListen(anyInt(), anyInt()); } /** @@ -1427,10 +1538,11 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { */ @Test public void testConfigureExtListen_invalidArguments() throws Exception { + setCachedServiceVersion(2); executeAndValidateInitializationSequence(false, false); doNothing().when(mISupplicantP2pIfaceMock).configureExtListen(anyInt(), anyInt()); - assertFalse(mDut.configureExtListen(true, -1, 1)); - assertFalse(mDut.configureExtListen(true, 1, -1)); + assertFalse(mDut.configureExtListen(true, -1, 1, null)); + assertFalse(mDut.configureExtListen(true, 1, -1, null)); } /** @@ -1438,10 +1550,11 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { */ @Test public void testConfigureExtListen_failure() throws Exception { + setCachedServiceVersion(2); executeAndValidateInitializationSequence(false, false); doThrow(new ServiceSpecificException(SupplicantStatusCode.FAILURE_UNKNOWN)) .when(mISupplicantP2pIfaceMock).configureExtListen(anyInt(), anyInt()); - assertFalse(mDut.configureExtListen(true, 1, 1)); + assertFalse(mDut.configureExtListen(true, 1, 1, null)); // Check that service is still alive. assertTrue(mDut.isInitializationComplete()); } @@ -1452,10 +1565,11 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { */ @Test public void testConfigureExtListen_exception() throws Exception { + setCachedServiceVersion(2); executeAndValidateInitializationSequence(false, false); doThrow(new RemoteException()).when(mISupplicantP2pIfaceMock) .configureExtListen(anyInt(), anyInt()); - assertFalse(mDut.configureExtListen(true, 1, 1)); + assertFalse(mDut.configureExtListen(true, 1, 1, null)); // Check service is dead. assertFalse(mDut.isInitializationComplete()); } @@ -2630,7 +2744,7 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { } assertTrue(mDut.initialize()); - verify(mServiceBinderMock).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); + verify(mServiceBinderMock).linkToDeath(mSupplicantDeathCaptor.capture(), anyInt()); assertTrue(mDut.isInitializationComplete()); // Now setup the iface. @@ -2679,4 +2793,47 @@ public class SupplicantP2pIfaceHalAidlImplTest extends WifiBaseTest { } return new TestP2pServiceInfo(services); } + + /** + * Tests the terminate function and ensures that its callback gets called. + */ + @Test + public void testTerminateAndDeadHandler() throws Exception { + executeAndValidateInitializationSequence(false, false); + mDut.terminate(); + verify(mISupplicantMock).terminate(); + // Trigger the supplicant died. + mSupplicantDeathCaptor.getValue().binderDied(); + // Check that terminate cleared all internal state. + assertFalse(mDut.isInitializationComplete()); + } + + /** + * Tests the handling of supplicant death notification. + */ + @Test + public void testSupplicantDeathCallback() throws Exception { + executeAndValidateInitializationSequence(false, false); + assertNotNull(mSupplicantDeathCaptor.getValue()); + assertTrue(mDut.isInitializationComplete()); + assertTrue(mDut.registerDeathHandler(mSupplicantHalDeathHandler)); + mSupplicantDeathCaptor.getValue().binderDied(); + assertFalse(mDut.isInitializationComplete()); + verify(mSupplicantHalDeathHandler).onDeath(); + } + + /** + * Tests the handling of supplicant death unregister. + */ + @Test + public void testSupplicantDeathCallbackUnregister() throws Exception { + executeAndValidateInitializationSequence(false, false); + assertNotNull(mSupplicantDeathCaptor.getValue()); + assertTrue(mDut.isInitializationComplete()); + assertTrue(mDut.registerDeathHandler(mSupplicantHalDeathHandler)); + assertTrue(mDut.deregisterDeathHandler()); + mSupplicantDeathCaptor.getValue().binderDied(); + assertFalse(mDut.isInitializationComplete()); + verify(mSupplicantHalDeathHandler, never()).onDeath(); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImplTest.java index 734255abbc..2520a7b01e 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalHidlImplTest.java @@ -1581,13 +1581,13 @@ public class SupplicantP2pIfaceHalHidlImplTest extends WifiBaseTest { when(mISupplicantP2pIfaceMock.configureExtListen(eq(0), eq(0))) .thenReturn(mStatusSuccess); // Default value when service is not initialized. - assertFalse(mDut.configureExtListen(true, 123, 456)); + assertFalse(mDut.configureExtListen(true, 123, 456, null)); executeAndValidateInitializationSequence(false, false, false); - assertTrue(mDut.configureExtListen(true, 123, 456)); + assertTrue(mDut.configureExtListen(true, 123, 456, null)); // Turning listening off should reset intervals to 0s. - assertTrue(mDut.configureExtListen(false, 999, 999)); + assertTrue(mDut.configureExtListen(false, 999, 999, null)); // Disable listening. - assertTrue(mDut.configureExtListen(false, -1, -1)); + assertTrue(mDut.configureExtListen(false, -1, -1, null)); } /** @@ -1598,8 +1598,8 @@ public class SupplicantP2pIfaceHalHidlImplTest extends WifiBaseTest { executeAndValidateInitializationSequence(false, false, false); when(mISupplicantP2pIfaceMock.configureExtListen(anyInt(), anyInt())) .thenReturn(mStatusFailure); - assertFalse(mDut.configureExtListen(true, -1, 1)); - assertFalse(mDut.configureExtListen(true, 1, -1)); + assertFalse(mDut.configureExtListen(true, -1, 1, null)); + assertFalse(mDut.configureExtListen(true, 1, -1, null)); } /** @@ -1610,7 +1610,7 @@ public class SupplicantP2pIfaceHalHidlImplTest extends WifiBaseTest { executeAndValidateInitializationSequence(false, false, false); when(mISupplicantP2pIfaceMock.configureExtListen(anyInt(), anyInt())) .thenReturn(mStatusFailure); - assertFalse(mDut.configureExtListen(true, 1, 1)); + assertFalse(mDut.configureExtListen(true, 1, 1, null)); // Check that service is still alive. assertTrue(mDut.isInitializationComplete()); } @@ -1623,7 +1623,7 @@ public class SupplicantP2pIfaceHalHidlImplTest extends WifiBaseTest { executeAndValidateInitializationSequence(false, false, false); when(mISupplicantP2pIfaceMock.configureExtListen(anyInt(), anyInt())) .thenThrow(mRemoteException); - assertFalse(mDut.configureExtListen(true, 1, 1)); + assertFalse(mDut.configureExtListen(true, 1, 1, null)); // Check service is dead. assertFalse(mDut.isInitializationComplete()); } diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java index 84d870a9c4..bf7194bec5 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java @@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -39,6 +40,7 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; import com.android.server.wifi.WifiBaseTest; import com.android.server.wifi.WifiGlobals; import com.android.server.wifi.WifiInjector; +import com.android.server.wifi.WifiNative; import org.junit.Before; import org.junit.Test; @@ -58,6 +60,7 @@ public class SupplicantP2pIfaceHalTest extends WifiBaseTest { private SupplicantP2pIfaceHalSpy mDut; private @Mock SupplicantP2pIfaceHalHidlImpl mP2pIfaceHalHidlMock; private @Mock SupplicantP2pIfaceHalAidlImpl mP2pIfaceHalAidlMock; + private @Mock WifiNative.SupplicantDeathEventHandler mSupplicantHalDeathHandler; private @Mock WifiP2pMonitor mMonitor; private @Mock WifiGlobals mWifiGlobals; private @Mock WifiInjector mWifiInjector; @@ -485,10 +488,11 @@ public class SupplicantP2pIfaceHalTest extends WifiBaseTest { initializeWithAidlImpl(true); int period = 2; int interval = 3; - when(mP2pIfaceHalAidlMock.configureExtListen(anyBoolean(), anyInt(), anyInt())) + when(mP2pIfaceHalAidlMock.configureExtListen(anyBoolean(), anyInt(), anyInt(), any())) .thenReturn(true); - assertTrue(mDut.configureExtListen(ENABLE, period, interval)); - verify(mP2pIfaceHalAidlMock).configureExtListen(eq(ENABLE), eq(period), eq(interval)); + assertTrue(mDut.configureExtListen(ENABLE, period, interval, null)); + verify(mP2pIfaceHalAidlMock).configureExtListen( + eq(ENABLE), eq(period), eq(interval), eq(null)); } /** @@ -807,4 +811,38 @@ public class SupplicantP2pIfaceHalTest extends WifiBaseTest { verify(mP2pIfaceHalAidlMock).configureEapolIpAddressAllocationParams(eq(0x0101A8C0), eq(0x00FFFFFF), eq(0x0501A8C0), eq(0x0801A8C0)); } + + /** + * Test that we can call terminate + */ + @Test + public void testTerminate() { + initializeWithAidlImpl(true); + doNothing().when(mP2pIfaceHalAidlMock).terminate(); + mDut.terminate(); + verify(mP2pIfaceHalAidlMock).terminate(); + } + + /** + * Test that we can call registerDeathHandler + */ + @Test + public void testRegisterDeathHandler() { + initializeWithAidlImpl(true); + when(mP2pIfaceHalAidlMock.registerDeathHandler( + any(WifiNative.SupplicantDeathEventHandler.class))).thenReturn(true); + assertTrue(mDut.registerDeathHandler(mSupplicantHalDeathHandler)); + verify(mP2pIfaceHalAidlMock).registerDeathHandler(eq(mSupplicantHalDeathHandler)); + } + + /** + * Test that we can call deregisterDeathHandler + */ + @Test + public void testDeregisterDeathHandler() { + initializeWithAidlImpl(true); + when(mP2pIfaceHalAidlMock.deregisterDeathHandler()).thenReturn(true); + assertTrue(mDut.deregisterDeathHandler()); + verify(mP2pIfaceHalAidlMock).deregisterDeathHandler(); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeInterfaceManagementTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeInterfaceManagementTest.java index cc2456f238..694c6901fa 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeInterfaceManagementTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeInterfaceManagementTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -34,18 +35,22 @@ import android.os.WorkSource; import androidx.test.filters.SmallTest; +import com.android.server.wifi.DeviceConfigFacade; import com.android.server.wifi.HalDeviceManager; import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener; import com.android.server.wifi.HalDeviceManager.ManagerStatusListener; import com.android.server.wifi.PropertyService; import com.android.server.wifi.WifiBaseTest; +import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiMetrics; import com.android.server.wifi.WifiNative; import com.android.server.wifi.WifiVendorHal; import com.android.server.wifi.hal.WifiHal; +import com.android.wifi.flags.FeatureFlags; import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -55,8 +60,7 @@ import org.mockito.MockitoAnnotations; */ @SmallTest public class WifiP2pNativeInterfaceManagementTest extends WifiBaseTest { - private static final String P2P_IFACE_NAME = "p2p0"; - private static final String P2P_INTERFACE_PROPERTY = "wifi.direct.interface"; + private static final String TEST_P2P_IFACE_NAME = "p2p0"; private static final WorkSource TEST_WS = new WorkSource(); @Mock private SupplicantP2pIfaceHal mSupplicantP2pIfaceHal; @@ -70,6 +74,11 @@ public class WifiP2pNativeInterfaceManagementTest extends WifiBaseTest { @Mock private WifiNl80211Manager mWifiNl80211Manager; @Mock private WifiNative mWifiNative; @Mock private WifiMetrics mWifiMetrics; + @Mock private WifiNative.Iface mMockP2pIface; + @Mock private WifiInjector mWifiInjector; + @Mock private DeviceConfigFacade mDeviceConfigFacade; + @Mock private FeatureFlags mFeatureFlags; + private WifiP2pNative mWifiP2pNative; private WifiStatus mWifiStatusSuccess; private ManagerStatusListener mManagerStatusListener; @@ -84,31 +93,60 @@ public class WifiP2pNativeInterfaceManagementTest extends WifiBaseTest { mWifiStatusSuccess.code = WifiStatusCode.SUCCESS; when(mHalDeviceManager.isSupported()).thenReturn(true); + mMockP2pIface.name = TEST_P2P_IFACE_NAME; + when(mWifiNative.createP2pIface(any(InterfaceDestroyedListener.class), + any(Handler.class), any(WorkSource.class))).thenReturn(mMockP2pIface); when(mHalDeviceManager.createP2pIface(any(InterfaceDestroyedListener.class), - any(Handler.class), any(WorkSource.class))).thenReturn(P2P_IFACE_NAME); + any(Handler.class), any(WorkSource.class))).thenReturn(TEST_P2P_IFACE_NAME); when(mSupplicantP2pIfaceHal.isInitializationStarted()).thenReturn(true); when(mSupplicantP2pIfaceHal.initialize()).thenReturn(true); when(mSupplicantP2pIfaceHal.isInitializationComplete()).thenReturn(true); - when(mSupplicantP2pIfaceHal.setupIface(P2P_IFACE_NAME)).thenReturn(true); - when(mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME)) - .thenReturn(P2P_IFACE_NAME); - + when(mSupplicantP2pIfaceHal.setupIface(TEST_P2P_IFACE_NAME)).thenReturn(true); + when(mSupplicantP2pIfaceHal.registerDeathHandler(any())).thenReturn(true); + when(mPropertyService.getString( + WifiP2pNative.P2P_INTERFACE_PROPERTY, WifiP2pNative.P2P_IFACE_NAME)) + .thenReturn(TEST_P2P_IFACE_NAME); + when(mWifiInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); + when(mDeviceConfigFacade.getFeatureFlags()).thenReturn(mFeatureFlags); + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(true); mWifiP2pNative = new WifiP2pNative(mWifiNl80211Manager, mWifiNative, mWifiMetrics, - mWifiVendorHal, mSupplicantP2pIfaceHal, mHalDeviceManager, mPropertyService); + mWifiVendorHal, mSupplicantP2pIfaceHal, mHalDeviceManager, mPropertyService, + mWifiInjector); + } + + /** + * Verifies the setup of a p2p interface. + */ + @Test + public void testSetUpInterfaceByHDM() throws Exception { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testSetUpInterface(false); } /** * Verifies the setup of a p2p interface. */ @Test - public void testSetUpInterface() throws Exception { - assertEquals(P2P_IFACE_NAME, + public void testSetUpInterfaceByWifiNative() throws Exception { + testSetUpInterface(true); + } + + private void testSetUpInterface(boolean isD2dAloneFeatureEnabled) throws Exception { + assertEquals(TEST_P2P_IFACE_NAME, mWifiP2pNative.setupInterface( mHalDeviceInterfaceDestroyedListener, mHandler, TEST_WS)); - - verify(mHalDeviceManager).createP2pIface(any(InterfaceDestroyedListener.class), - eq(mHandler), eq(TEST_WS)); - verify(mSupplicantP2pIfaceHal).setupIface(eq(P2P_IFACE_NAME)); + if (isD2dAloneFeatureEnabled) { + verify(mWifiNative).createP2pIface(any(InterfaceDestroyedListener.class), + eq(mHandler), eq(TEST_WS)); + verify(mHalDeviceManager, never()).createP2pIface(any(InterfaceDestroyedListener.class), + any(), any()); + } else { + verify(mHalDeviceManager).createP2pIface(any(InterfaceDestroyedListener.class), + eq(mHandler), eq(TEST_WS)); + verify(mWifiNative, never()).createP2pIface(any(InterfaceDestroyedListener.class), + any(), any()); + } + verify(mSupplicantP2pIfaceHal).setupIface(eq(TEST_P2P_IFACE_NAME)); } /** @@ -118,13 +156,22 @@ public class WifiP2pNativeInterfaceManagementTest extends WifiBaseTest { public void testSetUpInterfaceWithNoVendorHal() throws Exception { when(mHalDeviceManager.isSupported()).thenReturn(false); - assertEquals(P2P_IFACE_NAME, mWifiP2pNative.setupInterface( + assertEquals(TEST_P2P_IFACE_NAME, mWifiP2pNative.setupInterface( mHalDeviceInterfaceDestroyedListener, mHandler, TEST_WS)); verify(mHalDeviceManager, never()) .createP2pIface(any(InterfaceDestroyedListener.class), any(Handler.class), any(WorkSource.class)); - verify(mSupplicantP2pIfaceHal).setupIface(eq(P2P_IFACE_NAME)); + verify(mSupplicantP2pIfaceHal).setupIface(eq(TEST_P2P_IFACE_NAME)); + } + + /** + * Verifies the teardown of a p2p interface. + */ + @Test + public void testTeardownInterfaceWhenD2dWithoutSTADisabled() throws Exception { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testTeardownInterface(false); } /** @@ -132,29 +179,54 @@ public class WifiP2pNativeInterfaceManagementTest extends WifiBaseTest { */ @Test public void testTeardownInterface() throws Exception { - assertEquals(P2P_IFACE_NAME, + testTeardownInterface(true); + } + + private void testTeardownInterface(boolean isD2dAloneFeatureEnabled) throws Exception { + assertEquals(TEST_P2P_IFACE_NAME, mWifiP2pNative.setupInterface(mHalDeviceInterfaceDestroyedListener, mHandler, TEST_WS)); mWifiP2pNative.teardownInterface(); verify(mHalDeviceManager).removeP2pIface(anyString()); - verify(mSupplicantP2pIfaceHal).teardownIface(eq(P2P_IFACE_NAME)); + if (!isD2dAloneFeatureEnabled) { + verify(mSupplicantP2pIfaceHal).teardownIface(eq(TEST_P2P_IFACE_NAME)); + } } /** * Verifies the teardown of a p2p interface with no HAL (HIDL) support. */ @Test - public void testTeardownInterfaceWithNoVendorHal() throws Exception { - when(mHalDeviceManager.isSupported()).thenReturn(false); + public void testTeardownInterfaceWithNoVendorHalWhenD2dAloneFeatureEnabled() throws Exception { + testTeardownInterfaceWithNoVendorHal(true); + } + /** + * Verifies the teardown of a p2p interface with no HAL (HIDL) support. + */ + @Test + public void testTeardownInterfaceWithNoVendorHalD2dAloneFeatureDisabled() throws Exception { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testTeardownInterfaceWithNoVendorHal(false); + } - assertEquals(P2P_IFACE_NAME, mWifiP2pNative.setupInterface( + private void testTeardownInterfaceWithNoVendorHal(boolean isD2dAloneFeatureEnabled) + throws Exception { + when(mHalDeviceManager.isSupported()).thenReturn(false); + InOrder order = inOrder(mSupplicantP2pIfaceHal, mWifiNative); + assertEquals(TEST_P2P_IFACE_NAME, mWifiP2pNative.setupInterface( mHalDeviceInterfaceDestroyedListener, mHandler, TEST_WS)); mWifiP2pNative.teardownInterface(); verify(mHalDeviceManager, never()).removeIface(any(WifiHal.WifiInterface.class)); - verify(mSupplicantP2pIfaceHal).teardownIface(eq(P2P_IFACE_NAME)); + if (isD2dAloneFeatureEnabled) { + order.verify(mSupplicantP2pIfaceHal).deregisterDeathHandler(); + order.verify(mSupplicantP2pIfaceHal).teardownIface(eq(TEST_P2P_IFACE_NAME)); + order.verify(mWifiNative).teardownP2pIface(eq(mMockP2pIface.id)); + } else { + order.verify(mSupplicantP2pIfaceHal).teardownIface(eq(TEST_P2P_IFACE_NAME)); + } } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeTest.java index 153fb6ee2a..e70588f5bd 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeTest.java @@ -46,13 +46,16 @@ import android.os.WorkSource; import androidx.test.filters.SmallTest; import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.server.wifi.DeviceConfigFacade; import com.android.server.wifi.HalDeviceManager; import com.android.server.wifi.PropertyService; import com.android.server.wifi.WifiBaseTest; +import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiMetrics; import com.android.server.wifi.WifiNative; import com.android.server.wifi.WifiVendorHal; import com.android.server.wifi.hal.WifiHal; +import com.android.wifi.flags.FeatureFlags; import org.junit.After; import org.junit.Before; @@ -104,6 +107,10 @@ public class WifiP2pNativeTest extends WifiBaseTest { @Mock private Handler mHandlerMock; @Mock private WorkSource mWorkSourceMock; @Mock private IWifiP2pIface mIWifiP2pIfaceMock; + @Mock private WifiNative.Iface mMockP2pIface; + @Mock private WifiInjector mWifiInjector; + @Mock private DeviceConfigFacade mDeviceConfigFacade; + @Mock private FeatureFlags mFeatureFlags; private MockitoSession mSession; private WifiP2pNative mWifiP2pNative; @@ -131,10 +138,12 @@ public class WifiP2pNativeTest extends WifiBaseTest { .startMocking(); mWifiClientInterfaceNames.add("wlan0"); mWifiClientInterfaceNames.add("wlan1"); - + when(mWifiInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); + when(mDeviceConfigFacade.getFeatureFlags()).thenReturn(mFeatureFlags); + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(true); mWifiP2pNative = new WifiP2pNative(mWifiCondManager, mWifiNative, mWifiMetrics, mWifiVendorHalMock, mSupplicantP2pIfaceHalMock, mHalDeviceManagerMock, - mPropertyServiceMock); + mPropertyServiceMock, mWifiInjector); when(mWifiNative.getClientInterfaceNames()).thenReturn(mWifiClientInterfaceNames); @@ -149,7 +158,9 @@ public class WifiP2pNativeTest extends WifiBaseTest { // setup default mock behaviors when(mHalDeviceManagerMock.isSupported()).thenReturn(true); - + mMockP2pIface.name = TEST_IFACE; + when(mWifiNative.createP2pIface(any(HalDeviceManager.InterfaceDestroyedListener.class), + any(Handler.class), any(WorkSource.class))).thenReturn(mMockP2pIface); doAnswer(new AnswerWithArguments() { public boolean answer(WifiP2pGroupList groupList) { for (WifiP2pGroup g : mWifiP2pGroupList.getGroupList()) { @@ -178,16 +189,34 @@ public class WifiP2pNativeTest extends WifiBaseTest { } /** - * Verifies that setupInterface returns correct values when successfully creating P2P Iface. + * Verifies that setupInterface by calling HalDeviceManager returns correct values + * when successfully creating P2P Iface. (Old design, feature is disabled) */ @Test - public void testSetupInterfaceSuccessInCreatingP2pIface() { - when(mHalDeviceManagerMock.createP2pIface( - any(HalDeviceManager.InterfaceDestroyedListener.class), - eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + public void testSetupInterfaceByHDMSuccessInCreatingP2pIface() { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testSetupInterfaceSuccessInCreatingP2pIface(false); + } + + /** + * Verifies that setupInterface by WifiNative returns correct values + * when successfully creating P2P Iface. (The default behavior) + */ + @Test + public void testSetupInterfaceByWifiNativeSuccessInCreatingP2pIface() { + testSetupInterfaceSuccessInCreatingP2pIface(true); + } + + private void testSetupInterfaceSuccessInCreatingP2pIface(boolean isD2dAloneFeatureEnabled) { + if (!isD2dAloneFeatureEnabled) { + when(mHalDeviceManagerMock.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + } when(mSupplicantP2pIfaceHalMock.initialize()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.isInitializationComplete()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.setupIface(eq(TEST_IFACE))).thenReturn(true); + when(mSupplicantP2pIfaceHalMock.registerDeathHandler(any())).thenReturn(true); assertEquals( mWifiP2pNative.setupInterface( @@ -205,6 +234,7 @@ public class WifiP2pNativeTest extends WifiBaseTest { when(mSupplicantP2pIfaceHalMock.initialize()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.isInitializationComplete()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.setupIface(eq(TEST_IFACE))).thenReturn(true); + when(mSupplicantP2pIfaceHalMock.registerDeathHandler(any())).thenReturn(true); assertEquals( mWifiP2pNative.setupInterface( @@ -213,13 +243,34 @@ public class WifiP2pNativeTest extends WifiBaseTest { } /** - * Verifies that setupInterface returns correct values when failing in creating P2P Iface. + * Verifies that setupInterface returns correct values when failing in creating P2P Iface + * by HDM. */ @Test - public void testSetupInterfaceFailureInCreatingP2pIface() { - when(mHalDeviceManagerMock.createP2pIface( - any(HalDeviceManager.InterfaceDestroyedListener.class), - eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(null); + public void testSetupInterfaceFailureInCreatingP2pIfaceByHDM() { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testSetupInterfaceFailureInCreatingP2pIface(false); + } + + /** + * Verifies that setupInterface returns correct values when failing in creating P2P Iface + * by WifiNative. + */ + @Test + public void testSetupInterfaceFailureInCreatingP2pIfaceByWifiNative() { + testSetupInterfaceFailureInCreatingP2pIface(true); + } + + private void testSetupInterfaceFailureInCreatingP2pIface(boolean isD2dAloneFeatureEnabled) { + if (isD2dAloneFeatureEnabled) { + when(mWifiNative.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(null); + } else { + when(mHalDeviceManagerMock.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(null); + } when(mHalDeviceManagerMock.isItPossibleToCreateIface( eq(HalDeviceManager.HDM_CREATE_IFACE_P2P), eq(mWorkSourceMock))).thenReturn(true); @@ -236,10 +287,31 @@ public class WifiP2pNativeTest extends WifiBaseTest { * HalDevMgr not possibly creating it. */ @Test - public void testSetupInterfaceFailureInCreatingP2pIfaceWhenHalDevMgrNotPossiblyCreate() { - when(mHalDeviceManagerMock.createP2pIface( - any(HalDeviceManager.InterfaceDestroyedListener.class), - eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(null); + public void testSetupInterfaceFailureInHDMCreatingP2pIfaceWhenHalDevMgrNotPossiblyCreate() { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testSetupInterfaceFailureInCreatingP2pIfaceAndHalDevMgrNotPossiblyCreate(false); + } + + /** + * Verifies that Wi-Fi metrics do correct action when setting up p2p interface failed and + * HalDevMgr not possibly creating it. + */ + @Test + public void testSetupInterfaceFailureInCreatingP2pByWifiNativeAndHalDevMgrNotPossiblyCreate() { + testSetupInterfaceFailureInCreatingP2pIfaceAndHalDevMgrNotPossiblyCreate(true); + } + + private void testSetupInterfaceFailureInCreatingP2pIfaceAndHalDevMgrNotPossiblyCreate( + boolean isD2dAloneFeatureEnabled) { + if (isD2dAloneFeatureEnabled) { + when(mWifiNative.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(null); + } else { + when(mHalDeviceManagerMock.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(null); + } when(mHalDeviceManagerMock.isItPossibleToCreateIface( eq(HalDeviceManager.HDM_CREATE_IFACE_P2P), eq(mWorkSourceMock))).thenReturn(false); @@ -252,19 +324,34 @@ public class WifiP2pNativeTest extends WifiBaseTest { * initialization fails. */ @Test - public void testSetupInterfaceFailureInSupplicantConnectionInitialization() { - when(mHalDeviceManagerMock.createP2pIface( - any(HalDeviceManager.InterfaceDestroyedListener.class), - eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + public void testSetupInterfaceByHDMAndFailureInSupplicantConnectionInitialization() { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testSetupInterfaceFailureInSupplicantConnectionInitialization(false); + } + + /** + * Verifies that setupInterface returns correct values when supplicant connection + * initialization fails. + */ + @Test + public void testSetupInterfaceByWifiNativeAndFailureInSupplicantConnectionInitialization() { + testSetupInterfaceFailureInSupplicantConnectionInitialization(true); + } + + private void testSetupInterfaceFailureInSupplicantConnectionInitialization( + boolean isD2dAloneFeatureEnabled) { + if (!isD2dAloneFeatureEnabled) { + when(mHalDeviceManagerMock.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + } when(mSupplicantP2pIfaceHalMock.isInitializationStarted()).thenReturn(false); when(mSupplicantP2pIfaceHalMock.initialize()).thenReturn(false); - - mWifiP2pNative.setupInterface(mDestroyedListenerMock, mHandlerMock, mWorkSourceMock); - verify(mWifiMetrics).incrementNumSetupP2pInterfaceFailureDueToSupplicant(); assertEquals( mWifiP2pNative.setupInterface( mDestroyedListenerMock, mHandlerMock, mWorkSourceMock), null); + verify(mWifiMetrics).incrementNumSetupP2pInterfaceFailureDueToSupplicant(); } /** @@ -272,20 +359,36 @@ public class WifiP2pNativeTest extends WifiBaseTest { * initialization never completes. */ @Test - public void testSetupInterfaceFailureInSupplicantConnectionInitNotCompleted() { - when(mHalDeviceManagerMock.createP2pIface( - any(HalDeviceManager.InterfaceDestroyedListener.class), - eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + public void testSetupInterfaceByHDMAndFailureInSupplicantConnectionInitNotCompleted() { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testSetupInterfaceFailureInSupplicantConnectionInitNotCompleted(false); + } + + /** + * Verifies that setupInterface returns correct values when supplicant connection + * initialization never completes. + */ + @Test + public void testSetupInterfaceByWifiNativeAndFailureInSupplicantConnectionInitNotCompleted() { + testSetupInterfaceFailureInSupplicantConnectionInitNotCompleted(true); + } + + private void testSetupInterfaceFailureInSupplicantConnectionInitNotCompleted( + boolean isD2dAloneFeatureEnabled) { + if (!isD2dAloneFeatureEnabled) { + when(mHalDeviceManagerMock.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + } when(mSupplicantP2pIfaceHalMock.setupIface(eq(TEST_IFACE))).thenReturn(true); when(mSupplicantP2pIfaceHalMock.initialize()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.isInitializationComplete()).thenReturn(false); - mWifiP2pNative.setupInterface(mDestroyedListenerMock, mHandlerMock, mWorkSourceMock); - verify(mWifiMetrics).incrementNumSetupP2pInterfaceFailureDueToSupplicant(); assertEquals( mWifiP2pNative.setupInterface( mDestroyedListenerMock, mHandlerMock, mWorkSourceMock), null); + verify(mWifiMetrics).incrementNumSetupP2pInterfaceFailureDueToSupplicant(); } /** @@ -293,20 +396,52 @@ public class WifiP2pNativeTest extends WifiBaseTest { * for supplicant. */ @Test - public void testSetupInterfaceFailureInSettingUpP2pIfaceInSupplicant() { - when(mHalDeviceManagerMock.createP2pIface( - any(HalDeviceManager.InterfaceDestroyedListener.class), - eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + public void testSetupInterfaceByHDMAndFailureInSettingUpP2pIfaceInSupplicant() { + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(false); + testSetupInterfaceFailureInSettingUpP2pIfaceInSupplicant(false); + } + + /** + * Verifies that setupInterface returns correct values when failing in setting up P2P Iface + * for supplicant. + */ + @Test + public void testSetupInterfaceByWifiNativeAndFailureInSettingUpP2pIfaceInSupplicant() { + testSetupInterfaceFailureInSettingUpP2pIfaceInSupplicant(true); + } + private void testSetupInterfaceFailureInSettingUpP2pIfaceInSupplicant( + boolean isD2dAloneFeatureEnabled) { + if (!isD2dAloneFeatureEnabled) { + when(mHalDeviceManagerMock.createP2pIface( + any(HalDeviceManager.InterfaceDestroyedListener.class), + eq(mHandlerMock), eq(mWorkSourceMock))).thenReturn(TEST_IFACE); + } when(mSupplicantP2pIfaceHalMock.initialize()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.isInitializationComplete()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.setupIface(eq(TEST_IFACE))).thenReturn(false); - mWifiP2pNative.setupInterface(mDestroyedListenerMock, mHandlerMock, mWorkSourceMock); + assertEquals( + mWifiP2pNative.setupInterface( + mDestroyedListenerMock, mHandlerMock, mWorkSourceMock), + null); verify(mWifiMetrics).incrementNumSetupP2pInterfaceFailureDueToSupplicant(); + } + + /** + * Verifies that setupInterface returns correct values when failing in setting up + * P2P supplicant handler. + */ + @Test + public void testSetupInterfaceFailureInSettingUpP2pIfaceInSupplicantRegisterDeathHandler() { + when(mSupplicantP2pIfaceHalMock.initialize()).thenReturn(true); + when(mSupplicantP2pIfaceHalMock.isInitializationComplete()).thenReturn(true); + when(mSupplicantP2pIfaceHalMock.setupIface(eq(TEST_IFACE))).thenReturn(true); + when(mSupplicantP2pIfaceHalMock.registerDeathHandler(any())).thenReturn(false); assertEquals( mWifiP2pNative.setupInterface( mDestroyedListenerMock, mHandlerMock, mWorkSourceMock), null); + verify(mWifiMetrics).incrementNumSetupP2pInterfaceFailureDueToSupplicant(); } /** @@ -613,10 +748,11 @@ public class WifiP2pNativeTest extends WifiBaseTest { */ @Test public void testP2pExtListen() { - when(mSupplicantP2pIfaceHalMock.configureExtListen(anyBoolean(), anyInt(), anyInt())) + when(mSupplicantP2pIfaceHalMock.configureExtListen(anyBoolean(), anyInt(), anyInt(), any())) .thenReturn(true); - assertTrue(mWifiP2pNative.p2pExtListen(true, 10000, 20000)); - verify(mSupplicantP2pIfaceHalMock).configureExtListen(eq(true), eq(10000), eq(20000)); + assertTrue(mWifiP2pNative.p2pExtListen(true, 10000, 20000, null)); + verify(mSupplicantP2pIfaceHalMock).configureExtListen( + eq(true), eq(10000), eq(20000), eq(null)); } /** @@ -1013,6 +1149,7 @@ public class WifiP2pNativeTest extends WifiBaseTest { when(mSupplicantP2pIfaceHalMock.initialize()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.isInitializationComplete()).thenReturn(true); when(mSupplicantP2pIfaceHalMock.setupIface(any())).thenReturn(true); + when(mSupplicantP2pIfaceHalMock.registerDeathHandler(any())).thenReturn(true); mWifiP2pNative.setupInterface(mDestroyedListenerMock, mHandlerMock, mWorkSourceMock); } @@ -1055,4 +1192,15 @@ public class WifiP2pNativeTest extends WifiBaseTest { verify(mSupplicantP2pIfaceHalMock).configureEapolIpAddressAllocationParams(eq(0x0101A8C0), eq(0x00FFFFFF), eq(0x0501A8C0), eq(0x0801A8C0)); } + + @Test + public void testStopP2pSupplicantIfNecessary() throws Exception { + when(mSupplicantP2pIfaceHalMock.isInitializationStarted()).thenReturn(false); + mWifiP2pNative.stopP2pSupplicantIfNecessary(); + verify(mSupplicantP2pIfaceHalMock, never()).terminate(); + + when(mSupplicantP2pIfaceHalMock.isInitializationStarted()).thenReturn(true); + mWifiP2pNative.stopP2pSupplicantIfNecessary(); + verify(mSupplicantP2pIfaceHalMock).terminate(); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java index 546da0c60f..4589a287dd 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java @@ -24,6 +24,7 @@ import static android.net.wifi.WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL; +import static com.android.server.wifi.WifiSettingsConfigStore.D2D_ALLOWED_WHEN_INFRA_STA_DISABLED; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_DEVICE_ADDRESS; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_DEVICE_NAME; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_PENDING_FACTORY_RESET; @@ -78,21 +79,26 @@ import android.content.res.Resources; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.InetAddresses; +import android.net.LinkAddress; import android.net.MacAddress; import android.net.NetworkInfo; import android.net.NetworkStack; +import android.net.TetheredClient; import android.net.TetheringInterface; import android.net.TetheringManager; import android.net.wifi.CoexUnsafeChannel; +import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; import android.net.wifi.WpsInfo; +import android.net.wifi.p2p.IWifiP2pListener; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pDeviceList; +import android.net.wifi.p2p.WifiP2pExtListenParams; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pGroupList; import android.net.wifi.p2p.WifiP2pInfo; @@ -106,9 +112,12 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.Message; import android.os.Messenger; +import android.os.PersistableBundle; import android.os.Process; +import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; @@ -116,6 +125,7 @@ import android.os.test.TestLooper; import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; +import android.util.LocalLog; import android.view.Display; import android.view.LayoutInflater; import android.view.View; @@ -151,6 +161,7 @@ import com.android.server.wifi.util.StringUtil; import com.android.server.wifi.util.WaitingState; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; +import com.android.wifi.flags.FeatureFlags; import com.android.wifi.resources.R; import org.junit.After; @@ -169,9 +180,11 @@ import java.net.InetAddress; import java.net.NetworkInterface; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -182,11 +195,14 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { private static final String TAG = "WifiP2pServiceImplTest"; private static final String IFACE_NAME_P2P = "mockP2p0"; private static final String P2P_GO_IP = "192.168.49.1"; + private static final String P2P_PEER_IP = "192.168.49.50"; private static final long STATE_CHANGE_WAITING_TIME = 1000; private static final String thisDeviceMac = "11:22:33:44:55:66"; + private static final String PEER_INTERFACE_ADDRESS = "aa:bb:cc:dd:aa:bb"; private static final String thisDeviceName = "thisDeviceName"; private static final String ANONYMIZED_DEVICE_ADDRESS = "02:00:00:00:00:00"; private static final String TEST_PACKAGE_NAME = "com.p2p.test"; + private static final String TEST_NETWORK_NAME = "DIRECT-xy-NEW"; private static final String TEST_ANDROID_ID = "314Deadbeef"; private static final String[] TEST_REQUIRED_PERMISSIONS_T = new String[] { @@ -234,6 +250,11 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { private ArgumentCaptor<TetheringManager.TetheringEventCallback> mTetheringEventCallbackCaptor = ArgumentCaptor.forClass(TetheringManager.TetheringEventCallback.class); private TetheringManager.TetheringEventCallback mTetheringEventCallback; + private Bundle mExtras = new Bundle(); + private IWifiP2pListener mP2pListener = mock(IWifiP2pListener.class); + private ArgumentCaptor<WifiSettingsConfigStore.OnSettingsChangedListener> + mD2DAllowedSettingsCallbackCaptor = + ArgumentCaptor.forClass(WifiSettingsConfigStore.OnSettingsChangedListener.class); @Mock Bundle mBundle; @Mock Context mContext; @@ -277,6 +298,12 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { @Mock TetheringManager mTetheringManager; @Mock WifiDiagnostics mWifiDiagnostics; @Mock WifiP2pConnection mWifiP2pConnection; + @Mock Collection<TetheredClient> mClients; + @Mock TetheredClient mTetheredClient; + @Mock TetheredClient.AddressInfo mAddressInfo; + @Mock List<TetheredClient.AddressInfo> mAddresses; + @Mock LocalLog mLocalLog; + @Mock FeatureFlags mFeatureFlags; private void generatorTestData() { mTestWifiP2pGroup = new WifiP2pGroup(); @@ -306,7 +333,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { // for general group started event mTestWifiP2pNewPersistentGoGroup = new WifiP2pGroup(); mTestWifiP2pNewPersistentGoGroup.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); - mTestWifiP2pNewPersistentGoGroup.setNetworkName("DIRECT-xy-NEW"); + mTestWifiP2pNewPersistentGoGroup.setNetworkName(TEST_NETWORK_NAME); mTestWifiP2pNewPersistentGoGroup.setOwner(new WifiP2pDevice(thisDeviceMac)); mTestWifiP2pNewPersistentGoGroup.setIsGroupOwner(true); mTestWifiP2pNewPersistentGoGroup.setInterface(IFACE_NAME_P2P); @@ -407,6 +434,14 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { } } + private void simulateOnClientsChanged() throws Exception { + List<TetheredClient> clients = new ArrayList<>(1); + clients.add(mTetheredClient); + mClients = clients; + mTetheringEventCallback.onClientsChanged(mClients); + mLooper.dispatchAll(); + } + /** * Mock send WifiP2pManager.UPDATE_CHANNEL_INFO * @@ -665,6 +700,32 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { } /** + * Send WifiP2pMonitor.AP_STA_CONNECTED_EVENT. + * + * @param device Peer device information. + */ + private void sendApStaConnectedEvent(WifiP2pDevice device) throws Exception { + Message msg = Message.obtain(); + msg.what = WifiP2pMonitor.AP_STA_CONNECTED_EVENT; + msg.obj = device; + mP2pStateMachineMessenger.send(Message.obtain(msg)); + mLooper.dispatchAll(); + } + + /** + * Send WifiP2pMonitor.AP_STA_DISCONNECTED_EVENT. + * + * @param device Peer device information. + */ + private void sendApStaDisConnectedEvent(WifiP2pDevice device) throws Exception { + Message msg = Message.obtain(); + msg.what = WifiP2pMonitor.AP_STA_DISCONNECTED_EVENT; + msg.obj = device; + mP2pStateMachineMessenger.send(Message.obtain(msg)); + mLooper.dispatchAll(); + } + + /** * Mock send WifiP2pManager.SET_CHANNEL * * @param replyMessenger for checking replied message. @@ -1217,7 +1278,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { /** * Check the broadcast of WIFI_P2P_THIS_DEVICE_CHANGED_ACTION is sent as expected. */ - private void checkSendThisDeviceChangedBroadcast() { + private void checkSendThisDeviceChangedBroadcast() throws RemoteException { ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); String[] permission_gold; if (mWifiPermissionsUtil.isLocationModeEnabled()) { @@ -1259,6 +1320,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { } verifyDeviceChangedBroadcastIntent(intentCaptor.getValue()); } + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener, atLeastOnce()).onDeviceConfigurationChanged(any()); + } } /** @@ -1340,6 +1404,8 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { when(mWifiSettingsConfigStore.get(eq(WIFI_P2P_DEVICE_ADDRESS))).thenReturn(thisDeviceMac); when(mWifiSettingsConfigStore.get(eq(WIFI_P2P_DEVICE_NAME))).thenReturn(thisDeviceName); when(mWifiSettingsConfigStore.get(eq(WIFI_P2P_PENDING_FACTORY_RESET))).thenReturn(false); + when(mWifiSettingsConfigStore.get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED))) + .thenReturn(false); when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); if (supported) { when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_WIFI_DIRECT))) @@ -1362,6 +1428,8 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { .config_p2pWaitForPeerInviteOnInviteStatusInfoUnavailable)).thenReturn(false); when(mResources.getBoolean(R.bool .config_wifiP2pGoIpAddressAllocationInEapolFrames)).thenReturn(false); + when(mResources.getInteger(R.integer.config_wifiConfigurationWifiRunnerThresholdInMs)) + .thenReturn(4000); when(mResources.getConfiguration()).thenReturn(mConfiguration); when(mWifiInjector.getFrameworkFacade()).thenReturn(mFrameworkFacade); when(mWifiInjector.getUserManager()).thenReturn(mUserManager); @@ -1443,9 +1511,12 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { when(mCoexManager.getCoexRestrictions()).thenReturn(0); when(mCoexManager.getCoexUnsafeChannels()).thenReturn(Collections.emptyList()); when(mWifiInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); + when(mDeviceConfigFacade.getFeatureFlags()).thenReturn(mFeatureFlags); when(mWifiInjector.getWifiDiagnostics()).thenReturn(mWifiDiagnostics); + when(mWifiInjector.getWifiHandlerLocalLog()).thenReturn(mLocalLog); when(mDeviceConfigFacade.isP2pFailureBugreportEnabled()).thenReturn(false); when(mContext.getSystemService(TetheringManager.class)).thenReturn(mTetheringManager); + when(mP2pListener.asBinder()).thenReturn(mock(IBinder.class)); mWifiP2pServiceImpl = new WifiP2pServiceImpl(mContext, mWifiInjector); if (supported) { @@ -1468,6 +1539,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { } mWifiStateChangedReceiver = mBcastRxCaptor.getAllValues().get(0); mLocationModeReceiver = mBcastRxCaptor.getAllValues().get(1); + verify(mWifiSettingsConfigStore).registerChangeListener( + eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED), + mD2DAllowedSettingsCallbackCaptor.capture(), any()); } verify(mWifiPermissionsUtil, never()).isLocationModeEnabled(); @@ -1503,6 +1577,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { mClient2 = new Binder(); when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext); mWifiP2pServiceImpl.handleBootCompleted(); + if (SdkLevel.isAtLeastT()) { + mWifiP2pServiceImpl.registerWifiP2pListener(mP2pListener, TEST_PACKAGE_NAME, mExtras); + } } @After @@ -1555,7 +1632,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { forceP2pEnabled(mClient1); WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); - group.setNetworkName("DIRECT-xy-NEW"); + group.setNetworkName(TEST_NETWORK_NAME); group.setOwner(new WifiP2pDevice("thisDeviceMac")); group.setIsGroupOwner(true); group.setInterface(IFACE_NAME_P2P); @@ -1709,6 +1786,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { inOrder.verify(mContext).sendStickyBroadcastAsUser(argThat( new WifiP2pServiceImplTest.P2pStateChangedIntentMatcher( WifiP2pManager.WIFI_P2P_STATE_ENABLED)), any()); + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener).onP2pStateChanged(eq(WifiP2pManager.WIFI_P2P_STATE_ENABLED)); + } // disabled broadcast sent when user restriction is set simulateUserRestrictionChange(true); @@ -1716,6 +1796,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { inOrder.verify(mContext).sendStickyBroadcastAsUser(argThat( new WifiP2pServiceImplTest.P2pStateChangedIntentMatcher( WifiP2pManager.WIFI_P2P_STATE_DISABLED)), any()); + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener).onP2pStateChanged(eq(WifiP2pManager.WIFI_P2P_STATE_DISABLED)); + } // no disabled broadcast sent when Wi-Fi is disabled since broadcast already sent simulateWifiStateChange(false); @@ -2184,6 +2267,10 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { assertTrue(mClientHandler.hasMessages(WifiP2pManager.DISCOVER_PEERS_SUCCEEDED)); verify(mLastCallerInfoManager).put(eq(WifiManager.API_P2P_DISCOVER_PEERS), anyInt(), anyInt(), anyInt(), anyString(), eq(true)); + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener).onDiscoveryStateChanged( + eq(WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED)); + } } /** @@ -2696,7 +2783,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { // p2pFlush should be invoked once in forceP2pEnabled. verify(mWifiNative).p2pFlush(); verify(mWifiNative, never()).p2pStopFind(); - verify(mWifiNative, never()).p2pExtListen(anyBoolean(), anyInt(), anyInt()); + verify(mWifiNative, never()).p2pExtListen(anyBoolean(), anyInt(), anyInt(), eq(null)); } /** @@ -2705,14 +2792,14 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { @Test public void testStartListenFailureWhenNativeCallFailure() throws Exception { setTargetSdkGreaterThanT(); - when(mWifiNative.p2pExtListen(eq(true), anyInt(), anyInt())).thenReturn(false); + when(mWifiNative.p2pExtListen(eq(true), anyInt(), anyInt(), any())).thenReturn(false); forceP2pEnabled(mClient1); sendSimpleMsg(mClientMessenger, WifiP2pManager.START_LISTEN); // p2pFlush should be invoked once in forceP2pEnabled. verify(mWifiNative).p2pFlush(); verify(mWifiNative).p2pStopFind(); verify(mWifiNative).p2pExtListen(eq(true), eq(P2P_EXT_LISTEN_PERIOD_MS), - eq(P2P_EXT_LISTEN_INTERVAL_MS)); + eq(P2P_EXT_LISTEN_INTERVAL_MS), eq(null)); assertTrue(mClientHandler.hasMessages(WifiP2pManager.START_LISTEN_FAILED)); if (SdkLevel.isAtLeastT()) { verify(mWifiPermissionsUtil, atLeastOnce()).checkNearbyDevicesPermission( @@ -2731,14 +2818,14 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { @Test public void testStartListenSuccess() throws Exception { setTargetSdkGreaterThanT(); - when(mWifiNative.p2pExtListen(eq(true), anyInt(), anyInt())).thenReturn(true); + when(mWifiNative.p2pExtListen(eq(true), anyInt(), anyInt(), any())).thenReturn(true); forceP2pEnabled(mClient1); sendSimpleMsg(mClientMessenger, WifiP2pManager.START_LISTEN); // p2pFlush should be invoked once in forceP2pEnabled. verify(mWifiNative).p2pFlush(); verify(mWifiNative).p2pStopFind(); verify(mWifiNative).p2pExtListen(eq(true), eq(P2P_EXT_LISTEN_PERIOD_MS), - eq(P2P_EXT_LISTEN_INTERVAL_MS)); + eq(P2P_EXT_LISTEN_INTERVAL_MS), eq(null)); assertTrue(mClientHandler.hasMessages(WifiP2pManager.START_LISTEN_SUCCEEDED)); if (SdkLevel.isAtLeastT()) { verify(mWifiPermissionsUtil, atLeastOnce()).checkNearbyDevicesPermission( @@ -2749,6 +2836,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { verify(mWifiPermissionsUtil).checkCanAccessWifiDirect(eq(TEST_PACKAGE_NAME), eq("testFeature"), anyInt(), eq(true)); } + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener).onListenStateChanged(eq(WifiP2pManager.WIFI_P2P_LISTEN_STARTED)); + } } /** @@ -2757,14 +2847,14 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { @Test public void testStartListenSuccessWithGroup() throws Exception { setTargetSdkGreaterThanT(); - when(mWifiNative.p2pExtListen(eq(true), anyInt(), anyInt())).thenReturn(true); + when(mWifiNative.p2pExtListen(eq(true), anyInt(), anyInt(), any())).thenReturn(true); mockEnterGroupCreatedState(); sendSimpleMsg(mClientMessenger, WifiP2pManager.START_LISTEN); // p2pFlush should be invoked once in forceP2pEnabled. verify(mWifiNative).p2pFlush(); verify(mWifiNative, times(2)).p2pStopFind(); verify(mWifiNative).p2pExtListen(eq(true), eq(P2P_EXT_LISTEN_PERIOD_MS), - eq(P2P_EXT_LISTEN_INTERVAL_MS)); + eq(P2P_EXT_LISTEN_INTERVAL_MS), eq(null)); assertTrue(mClientHandler.hasMessages(WifiP2pManager.START_LISTEN_SUCCEEDED)); if (SdkLevel.isAtLeastT()) { verify(mWifiPermissionsUtil, atLeastOnce()).checkNearbyDevicesPermission( @@ -2779,6 +2869,47 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { anyInt(), anyInt(), anyString(), eq(true)); } + /** + * Verify that a caller with proper permission can send WifiP2pManager.START_LISTEN + * with additional parameters. + */ + @Test + public void testStartListenSuccessWithExtListenParams() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + setTargetSdkGreaterThanT(); + when(mWifiNative.p2pExtListen(eq(true), anyInt(), anyInt(), any())).thenReturn(true); + forceP2pEnabled(mClient1); + + OuiKeyedData vendorDataElement = + new OuiKeyedData.Builder(0x00aabbcc, new PersistableBundle()).build(); + List<OuiKeyedData> vendorData = Arrays.asList(vendorDataElement); + WifiP2pExtListenParams extListenParams = + new WifiP2pExtListenParams.Builder().setVendorData(vendorData).build(); + + Message msg = Message.obtain(); + msg.what = WifiP2pManager.START_LISTEN; + msg.arg1 = WifiP2pManager.WIFI_P2P_EXT_LISTEN_WITH_PARAMS; + msg.replyTo = mClientMessenger; + msg.obj = new AttributionSource(1000, TEST_PACKAGE_NAME, null); + + Bundle extras = new Bundle(); + extras.putParcelable(WifiP2pManager.EXTRA_PARAM_KEY_EXT_LISTEN_PARAMS, extListenParams); + msg.getData().putBundle(WifiP2pManager.EXTRA_PARAM_KEY_BUNDLE, extras); + mP2pStateMachineMessenger.send(Message.obtain(msg)); + mLooper.dispatchAll(); + + // p2pFlush should be invoked once during forceP2pEnabled. + verify(mWifiNative).p2pFlush(); + verify(mWifiNative).p2pStopFind(); + verify(mWifiNative).p2pExtListen(eq(true), eq(P2P_EXT_LISTEN_PERIOD_MS), + eq(P2P_EXT_LISTEN_INTERVAL_MS), any(WifiP2pExtListenParams.class)); + assertTrue(mClientHandler.hasMessages(WifiP2pManager.START_LISTEN_SUCCEEDED)); + verify(mWifiPermissionsUtil, atLeastOnce()).checkNearbyDevicesPermission( + any(), eq(true), any()); + verify(mWifiPermissionsUtil, never()).checkCanAccessWifiDirect( + any(), any(), anyInt(), anyBoolean()); + } + @Test public void testStartListenAndSetChannelFailureWithDefaultStateHandling() throws Exception { setTargetSdkGreaterThanT(); @@ -2802,11 +2933,11 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { */ @Test public void testStopListenFailureWhenNativeCallFailure() throws Exception { - when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt())).thenReturn(false); + when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt(), any())).thenReturn(false); forceP2pEnabled(mClient1); sendSimpleMsg(mClientMessenger, WifiP2pManager.STOP_LISTEN); verify(mWifiNative).p2pStopFind(); - verify(mWifiNative).p2pExtListen(eq(false), anyInt(), anyInt()); + verify(mWifiNative).p2pExtListen(eq(false), anyInt(), anyInt(), eq(null)); assertTrue(mClientHandler.hasMessages(WifiP2pManager.STOP_LISTEN_FAILED)); } @@ -2815,11 +2946,11 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { */ @Test public void testStopListenSuccess() throws Exception { - when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt())).thenReturn(true); + when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt(), any())).thenReturn(true); forceP2pEnabled(mClient1); sendSimpleMsg(mClientMessenger, WifiP2pManager.STOP_LISTEN); verify(mWifiNative).p2pStopFind(); - verify(mWifiNative).p2pExtListen(eq(false), anyInt(), anyInt()); + verify(mWifiNative).p2pExtListen(eq(false), anyInt(), anyInt(), eq(null)); assertTrue(mClientHandler.hasMessages(WifiP2pManager.STOP_LISTEN_SUCCEEDED)); verify(mLastCallerInfoManager).put(eq(WifiManager.API_P2P_STOP_LISTENING), anyInt(), anyInt(), anyInt(), anyString(), eq(true)); @@ -3311,7 +3442,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); - group.setNetworkName("DIRECT-xy-NEW"); + group.setNetworkName(TEST_NETWORK_NAME); group.setOwner(new WifiP2pDevice("thisDeviceMac")); group.setIsGroupOwner(true); group.setInterface(IFACE_NAME_P2P); @@ -3321,6 +3452,144 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { eq(P2pConnectionEvent.CLF_NONE)); } + @Test + public void testOnClientsChangedOnApStaConnection() throws Exception { + when(mTetheredClient.getTetheringType()).thenReturn(TetheringManager.TETHERING_WIFI_P2P); + when(mTetheredClient.getAddresses()).thenReturn(mAddresses); + when(mAddresses.size()).thenReturn(1); + when(mAddresses.get(0)).thenReturn(mAddressInfo); + when(mTetheredClient.getMacAddress()) + .thenReturn(MacAddress.fromString(PEER_INTERFACE_ADDRESS)); + when(mAddressInfo.getAddress()).thenReturn(new LinkAddress(P2P_PEER_IP + "/" + "24")); + + forceP2pEnabled(mClient1); + + // Update the P2P peer list. + WifiP2pDeviceList peers; + WifiP2pDevice dev; + mockPeersList(); + sendRequestPeersMsg(mClientMessenger); + verify(mClientHandler, times(1)).sendMessage(mMessageCaptor.capture()); + + // Start the P2P GO. + WifiP2pGroup group = new WifiP2pGroup(); + group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); + group.setNetworkName("DIRECT-xy-NEW"); + group.setOwner(new WifiP2pDevice("thisDeviceMac")); + group.setIsGroupOwner(true); + group.setInterface(IFACE_NAME_P2P); + sendGroupStartedMsg(group); + simulateTetherReady(); + + // Trigger AP_STA_CONNECTED event & validate the results. + WifiP2pDevice connectedClientDevice = new WifiP2pDevice(mTestWifiP2pDevice); + connectedClientDevice.setInterfaceMacAddress(MacAddress.fromString(PEER_INTERFACE_ADDRESS)); + sendApStaConnectedEvent(connectedClientDevice); + simulateOnClientsChanged(); + // Verify that the connected client is added to the p2p group client list. + sendRequestGroupInfoMsg(mClientMessenger); + verify(mClientHandler, times(2)).sendMessage(mMessageCaptor.capture()); + assertEquals(WifiP2pManager.RESPONSE_GROUP_INFO, mMessageCaptor.getValue().what); + WifiP2pGroup wifiP2pGroup = (WifiP2pGroup) mMessageCaptor.getValue().obj; + assertEquals(1, wifiP2pGroup.getClientList().size()); + WifiP2pDevice client = wifiP2pGroup.getClientList().iterator().next(); + assertNotNull(client); + assertEquals(mTestWifiP2pDevice.deviceAddress, client.deviceAddress); + assertEquals(MacAddress.fromString(PEER_INTERFACE_ADDRESS), + client.getInterfaceMacAddress()); + if (SdkLevel.isAtLeastV()) { + assertEquals(InetAddresses.parseNumericAddress(P2P_PEER_IP), client.getIpAddress()); + } + + // Verify that the interface MAC address and IP address is not updated in the P2P peer list. + sendRequestPeersMsg(mClientMessenger); + verify(mClientHandler, times(3)).sendMessage(mMessageCaptor.capture()); + peers = (WifiP2pDeviceList) mMessageCaptor.getValue().obj; + assertEquals(WifiP2pManager.RESPONSE_PEERS, mMessageCaptor.getValue().what); + dev = peers.get(mTestWifiP2pDevice.deviceAddress); + assertNotNull(dev); + assertNull(dev.getInterfaceMacAddress()); + if (SdkLevel.isAtLeastV()) { + assertNull(dev.getIpAddress()); + } + + } + + @Test + public void testApStaConnectedDisconnectedEventWithEapolIPAddress() throws Exception { + forceP2pEnabled(mClient1); + + WifiP2pDeviceList peers; + WifiP2pDevice dev; + WifiP2pGroup wifiP2pGroup; + + // Update the P2P Peer list. + mockPeersList(); + sendRequestPeersMsg(mClientMessenger); + verify(mClientHandler, times(1)).sendMessage(mMessageCaptor.capture()); + + // Start the P2P GO. + WifiP2pGroup group = new WifiP2pGroup(); + group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); + group.setNetworkName("DIRECT-xy-NEW"); + group.setOwner(new WifiP2pDevice("thisDeviceMac")); + group.setIsGroupOwner(true); + group.setInterface(IFACE_NAME_P2P); + sendGroupStartedMsg(group); + simulateTetherReady(); + + // Trigger AP_STA_CONNECTED event & validate the results. + WifiP2pDevice connectedClientDevice = new WifiP2pDevice(mTestWifiP2pDevice); + connectedClientDevice.setInterfaceMacAddress(MacAddress.fromString(PEER_INTERFACE_ADDRESS)); + connectedClientDevice.setIpAddress(InetAddresses.parseNumericAddress(P2P_PEER_IP)); + sendApStaConnectedEvent(connectedClientDevice); + // Verify that the connected client is added to the p2p group client list. + sendRequestGroupInfoMsg(mClientMessenger); + verify(mClientHandler, times(2)).sendMessage(mMessageCaptor.capture()); + assertEquals(WifiP2pManager.RESPONSE_GROUP_INFO, mMessageCaptor.getValue().what); + wifiP2pGroup = (WifiP2pGroup) mMessageCaptor.getValue().obj; + assertEquals(1, wifiP2pGroup.getClientList().size()); + WifiP2pDevice client = wifiP2pGroup.getClientList().iterator().next(); + assertNotNull(client); + assertEquals(mTestWifiP2pDevice.deviceAddress, client.deviceAddress); + assertEquals(MacAddress.fromString(PEER_INTERFACE_ADDRESS), + client.getInterfaceMacAddress()); + if (SdkLevel.isAtLeastV()) { + assertEquals(InetAddresses.parseNumericAddress(P2P_PEER_IP), client.getIpAddress()); + } + + // Verify that the interface MAC address and IP address is not set in the P2P peer list. + sendRequestPeersMsg(mClientMessenger); + verify(mClientHandler, times(3)).sendMessage(mMessageCaptor.capture()); + peers = (WifiP2pDeviceList) mMessageCaptor.getValue().obj; + assertEquals(WifiP2pManager.RESPONSE_PEERS, mMessageCaptor.getValue().what); + dev = peers.get(mTestWifiP2pDevice.deviceAddress); + assertNotNull(dev); + assertNull(dev.getInterfaceMacAddress()); + if (SdkLevel.isAtLeastV()) { + assertNull(dev.getIpAddress()); + } + + // Trigger AP_STA_DISCONNECTED event & validate the results. + sendApStaDisConnectedEvent(connectedClientDevice); + // Verify that the client is removed from the P2P group client list. + sendRequestGroupInfoMsg(mClientMessenger); + verify(mClientHandler, times(4)).sendMessage(mMessageCaptor.capture()); + assertEquals(WifiP2pManager.RESPONSE_GROUP_INFO, mMessageCaptor.getValue().what); + wifiP2pGroup = (WifiP2pGroup) mMessageCaptor.getValue().obj; + assertNotNull(wifiP2pGroup); + assertEquals(0, wifiP2pGroup.getClientList().size()); + + // Verify that the P2P device is not removed from the P2P peer list. + sendRequestPeersMsg(mClientMessenger); + verify(mClientHandler, times(5)).sendMessage(mMessageCaptor.capture()); + peers = (WifiP2pDeviceList) mMessageCaptor.getValue().obj; + assertEquals(WifiP2pManager.RESPONSE_PEERS, mMessageCaptor.getValue().what); + dev = peers.get(mTestWifiP2pDevice.deviceAddress); + assertNotNull(dev); + assertEquals(mTestWifiP2pDevice.deviceAddress, dev.deviceAddress); + } + /** * Verify the connection event ends due to timeout. */ @@ -3479,7 +3748,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { WifiP2pServiceImpl.P2pStatus.NO_COMMON_CHANNEL); WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); - group.setNetworkName("DIRECT-xy-NEW"); + group.setNetworkName(TEST_NETWORK_NAME); group.setOwner(new WifiP2pDevice("thisDeviceMac")); group.setIsGroupOwner(true); group.setInterface(IFACE_NAME_P2P); @@ -4069,7 +4338,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { */ @Test public void testStopListenSuccessWhenNativeCallSucceedInCreatingGroup() throws Exception { - when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt())).thenReturn(true); + when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt(), any())).thenReturn(true); // Move to group creating state testConnectWithConfigValidAsGroupSuccess(); sendSimpleMsg(mClientMessenger, WifiP2pManager.STOP_LISTEN); @@ -4084,7 +4353,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { */ @Test public void testStopListenFailureWhenNativeCallFailInCreatingGroup() throws Exception { - when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt())).thenReturn(false); + when(mWifiNative.p2pExtListen(eq(false), anyInt(), anyInt(), any())).thenReturn(false); // Move to group creating state testConnectWithConfigValidAsGroupSuccess(); sendSimpleMsg(mClientMessenger, WifiP2pManager.STOP_LISTEN); @@ -5080,6 +5349,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { when(mWifiNative.p2pListNetworks(any())).thenReturn(true); sendSimpleMsg(mClientMessenger, WifiP2pManager.FACTORY_RESET); checkSendP2pPersistentGroupsChangedBroadcast(); + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener, atLeastOnce()).onPersistentGroupsChanged(any()); + } verify(mWifiInjector).getUserManager(); verify(mPackageManager).getNameForUid(anyInt()); verify(mWifiPermissionsUtil).checkNetworkSettingsPermission(anyInt()); @@ -5492,13 +5764,13 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { when(mWifiPermissionsUtil.checkCanAccessWifiDirect(eq(TEST_PACKAGE_NAME), eq("testFeature"), anyInt(), anyBoolean())).thenReturn(true); - when(mWifiNative.p2pExtListen(anyBoolean(), anyInt(), anyInt())).thenReturn(true); + when(mWifiNative.p2pExtListen(anyBoolean(), anyInt(), anyInt(), any())).thenReturn(true); sendSimpleMsg(mClientMessenger, WifiP2pManager.START_LISTEN); verify(mWifiNative).p2pStopFind(); sendSimpleMsg(mClientMessenger, WifiP2pManager.GET_LISTEN_STATE); sendSimpleMsg(mClientMessenger, WifiP2pManager.STOP_LISTEN); - verify(mWifiNative, times(2)).p2pExtListen(anyBoolean(), anyInt(), anyInt()); + verify(mWifiNative, times(2)).p2pExtListen(anyBoolean(), anyInt(), anyInt(), eq(null)); sendSimpleMsg(mClientMessenger, WifiP2pManager.GET_LISTEN_STATE); verify(mClientHandler, times(5)).sendMessage(mMessageCaptor.capture()); @@ -6233,7 +6505,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); - group.setNetworkName("DIRECT-xy-NEW"); + group.setNetworkName(TEST_NETWORK_NAME); group.setOwner(new WifiP2pDevice("thisDeviceMac")); group.setIsGroupOwner(true); group.setInterface(IFACE_NAME_P2P); @@ -6416,7 +6688,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { forceP2pEnabled(mClient1); WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); - group.setNetworkName("DIRECT-xy-NEW"); + group.setNetworkName(TEST_NETWORK_NAME); group.setOwner(new WifiP2pDevice("thisDeviceMac")); group.setIsGroupOwner(true); group.setInterface(IFACE_NAME_P2P); @@ -7013,6 +7285,27 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { WpsInfo.PBC, WifiP2pManager.CONNECTION_REQUEST_ACCEPT); } + /** Verify the failure scenario for setConnectionRequestResult without a saved peer config. */ + @Test + public void testSetConnectionRequestResultFailureWithoutSavedPeerConfig() throws Exception { + assumeTrue(SdkLevel.isAtLeastS()); + when(mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(anyInt())) + .thenReturn(true); + when(mWifiPermissionsUtil.checkNearbyDevicesPermission(any(), anyBoolean(), any())) + .thenReturn(true); + Binder binder = new Binder(); + mockEnterGroupCreatedState(); + sendSetConnectionRequestResultMsg( + mClientMessenger, + MacAddress.fromString(mTestWifiP2pDevice.deviceAddress), + WifiP2pManager.CONNECTION_REQUEST_ACCEPT, + binder); + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mClientHandler).sendMessage(messageCaptor.capture()); + List<Message> messages = messageCaptor.getAllValues(); + assertEquals(WifiP2pManager.SET_CONNECTION_REQUEST_RESULT_FAILED, messages.get(0).what); + } + /** * Verify that deferring pin to the framework works normally. */ @@ -7173,7 +7466,10 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { WifiP2pMonitor.PROV_DISC_STATUS_REJECTED, pdEvent); verify(mWifiNative).p2pCancelConnect(); - + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener).onGroupCreationFailed( + eq(WifiP2pManager.GROUP_CREATION_FAILURE_REASON_PROVISION_DISCOVERY_FAILED)); + } } /** @@ -7204,6 +7500,9 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { sendSimpleMsg(null, WifiP2pServiceImpl.PEER_CONNECTION_USER_REJECT); verify(mWifiNative).p2pReject(eq(mTestWifiP2pDevice.deviceAddress)); + if (SdkLevel.isAtLeastT()) { + verify(mP2pListener).onGroupNegotiationRejectedByUser(); + } } /** @@ -7431,7 +7730,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { forceP2pEnabled(mClient1); WifiP2pGroup group = new WifiP2pGroup(); group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); - group.setNetworkName("DIRECT-xy-NEW"); + group.setNetworkName(TEST_NETWORK_NAME); group.setOwner(new WifiP2pDevice("thisDeviceMac")); group.setIsGroupOwner(true); group.setInterface(IFACE_NAME_P2P); @@ -7458,7 +7757,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { @Test public void testGroupStartedTetheringDirectCallback() throws Exception { - when(mWifiNative.p2pExtListen(anyBoolean(), anyInt(), anyInt())).thenReturn(true); + when(mWifiNative.p2pExtListen(anyBoolean(), anyInt(), anyInt(), any())).thenReturn(true); assumeTrue(SdkLevel.isAtLeastS()); forceP2pEnabled(mClient1); verify(mTetheringManager).registerTetheringEventCallback(any(), any()); @@ -7476,7 +7775,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { simulateTetherReady(); verify(mWifiP2pMetrics).startGroupEvent(group); verify(mWifiNative).p2pStopFind(); - verify(mWifiNative).p2pExtListen(eq(false), anyInt(), anyInt()); + verify(mWifiNative).p2pExtListen(eq(false), anyInt(), anyInt(), eq(null)); sendGroupRemovedMsg(); //force to back disabled state @@ -7554,7 +7853,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { @Test public void testSetListenOnInviteStatusCodeInfoUnavailable() throws Exception { forceP2pEnabled(mClient1); - when(mWifiNative.p2pExtListen(anyBoolean(), anyInt(), anyInt())).thenReturn(true); + when(mWifiNative.p2pExtListen(anyBoolean(), anyInt(), anyInt(), any())).thenReturn(true); when(mWifiNative.getGroupCapability(any())).thenReturn(0); when(mWifiNative.p2pReinvoke(anyInt(), any())).thenReturn(true); when(mWifiNative.p2pGetSsid(any())).thenReturn(null); @@ -7572,7 +7871,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { verify(mWifiNative, times(2)).p2pStopFind(); verify(mWifiNative).p2pExtListen(eq(true), eq(P2P_EXT_LISTEN_PERIOD_MS), - eq(P2P_EXT_LISTEN_INTERVAL_MS)); + eq(P2P_EXT_LISTEN_INTERVAL_MS), eq(null)); } /** @@ -7630,4 +7929,227 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { verify(mWifiNative, never()).configureEapolIpAddressAllocationParams(anyInt(), anyInt(), anyInt(), anyInt()); } + + @Test + public void testSendP2pConnectionChangedBroadcast() throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); + ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); + ArgumentCaptor<String[]> permissionCaptor = ArgumentCaptor.forClass(String[].class); + String[] receiverPermissions; + int flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT; + + // mock p2p enabled + forceP2pEnabled(mClient1); + if (!SdkLevel.isAtLeastU()) { + receiverPermissions = new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_WIFI_STATE}; + verify(mContext).sendBroadcastWithMultiplePermissions(argThat((Intent intent) -> { + WifiP2pInfo p2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); + WifiP2pGroup p2pGroup = intent.getParcelableExtra( + WifiP2pManager.EXTRA_WIFI_P2P_GROUP); + assert p2pInfo != null; + return intent.getAction().equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION) + && intent.getFlags() == Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + && Objects.isNull(intent.getPackage()) + && !p2pInfo.groupFormed && Objects.isNull(p2pGroup); + }), permissionCaptor.capture()); + assertEquals(receiverPermissions, permissionCaptor.getValue()); + } else { + receiverPermissions = new String[]{NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}; + flags |= Intent.FLAG_RECEIVER_FOREGROUND; + verify(mContext).sendBroadcastWithMultiplePermissions(intentCaptor.capture(), + permissionCaptor.capture()); + Intent intent = intentCaptor.getValue(); + assertEquals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION, intent.getAction()); + assertEquals(flags, intent.getFlags()); + WifiP2pInfo p2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); + WifiP2pGroup p2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP); + assert p2pInfo != null; + assertFalse(p2pInfo.groupFormed); + assertFalse(p2pInfo.isGroupOwner); + assertNull(p2pGroup); + assertEquals(receiverPermissions, permissionCaptor.getValue()); + } + + // mock group started + WifiP2pGroup group = new WifiP2pGroup(); + group.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); + group.setNetworkName("DIRECT-xy-NEW"); + group.setOwner(new WifiP2pDevice("thisDeviceMac")); + group.setIsGroupOwner(true); + group.setInterface(IFACE_NAME_P2P); + sendGroupStartedMsg(group); + simulateTetherReady(); + + // reassign captor again, otherwise captor.getAllValues() will include previous values + intentCaptor = ArgumentCaptor.forClass(Intent.class); + permissionCaptor = ArgumentCaptor.forClass(String[].class); + if (!SdkLevel.isAtLeastU()) { + // there are other broadcasts from sendThisDeviceChangedBroadcast() called by + // updateThisDevice() + verify(mContext, times(6)).sendBroadcastWithMultiplePermissions(intentCaptor.capture(), + permissionCaptor.capture()); + } else { + verify(mContext, times(3)).sendBroadcastWithMultiplePermissions(intentCaptor.capture(), + permissionCaptor.capture()); + } + ArrayList<Intent> intentArrayList = new ArrayList<>(); + ArrayList<String[]> permissionArrayList = new ArrayList<>(); + for (int i = 0; i < intentCaptor.getAllValues().size(); i++) { + Intent intent = intentCaptor.getAllValues().get(i); + if (intent.getAction().equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { + intentArrayList.add(intent); + permissionArrayList.add(permissionCaptor.getAllValues().get(i)); + } + } + assertEquals(3, intentArrayList.size()); + /* Total three WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION broadcasts are as follows. + * ---------------------------------------------------------------------------------------- + * State p2pInfo.groupFormed p2pGroup intent.permission intent.flag intent.package + * ---------------------------------------------------------------------------------------- + * PreU: + * P2pEnabledState :false null RECEIVER_PERMISSIONS_FOR_BROADCAST(location ON) + * Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + * null + * GroupCreatingState :false p2pGroup.isGo RECEIVER_PERMISSIONS_FOR_BROADCAST(location ON) + * Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + * null + * GroupNegotiationState:true p2pGroup.isGo android.Manifest.permission.TETHER_PRIVILEGED + * Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + * com.android.networkstack.tethering + * + * PostU: + * P2pEnabledState : false null android.permission.MAINLINE_NETWORK_STACK + * Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT|Intent.FLAG_RECEIVER_FOREGROUND + * null + * GroupCreatingState : false p2pGroup.isGo android.permission.MAINLINE_NETWORK_STACK + * Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT|Intent.FLAG_RECEIVER_FOREGROUND + * null + * GroupNegotiationState: true p2pGroup.isGo android.permission.MAINLINE_NETWORK_STACK + * Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT|Intent.FLAG_RECEIVER_FOREGROUND + * com.android.networkstack.tethering + */ + Intent intent = intentArrayList.get(1); + assertEquals(flags, intent.getFlags()); + assertNull(intent.getPackage()); + WifiP2pInfo p2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); + assert p2pInfo != null; + assertFalse(p2pInfo.groupFormed); + WifiP2pGroup p2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP); + assert p2pGroup != null; + assertTrue(p2pGroup.isGroupOwner()); + assertEquals(receiverPermissions, permissionArrayList.get(1)); + + intent = intentArrayList.get(2); + assertEquals(flags, intent.getFlags()); + assertNotNull(intent.getPackage()); + p2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); + assert p2pInfo != null; + assertTrue(p2pInfo.groupFormed); + p2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP); + assert p2pGroup != null; + assertTrue(p2pGroup.isGroupOwner()); + if (!SdkLevel.isAtLeastU()) { + receiverPermissions = new String[]{android.Manifest.permission.TETHER_PRIVILEGED}; + } + assertEquals(receiverPermissions, permissionArrayList.get(2)); + } + + /** + * Verify that p2p doesn't disable when wifi disabled and D2d is allowed when + * infra sta is disabled. + */ + @Test + public void testP2pDoesInitWhenClientConnectWithWifiDisabledAndD2DAllowed() + throws Exception { + when(mWifiSettingsConfigStore.get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED))) + .thenReturn(true); + when(mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()).thenReturn(true); + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(true); + simulateWifiStateChange(false); + checkIsP2pInitWhenClientConnected(true, mClient1, + new WorkSource(mClient1.getCallingUid(), TEST_PACKAGE_NAME)); + } + + @Test + public void testWifiP2pListener() throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + forceP2pEnabled(mClient1); + when(mWifiNative.p2pGroupAdd(any(), eq(false))).thenReturn(true); + WifiP2pGroup p2pGroup = new WifiP2pGroup(); + p2pGroup.setNetworkId(WifiP2pGroup.NETWORK_ID_PERSISTENT); + p2pGroup.setNetworkName(TEST_NETWORK_NAME); + p2pGroup.setOwner(new WifiP2pDevice("thisDeviceMac")); + p2pGroup.setIsGroupOwner(true); + p2pGroup.setInterface(IFACE_NAME_P2P); + + sendCreateGroupMsgWithConfigValidAsGroup(mClientMessenger); + sendGroupStartedMsg(p2pGroup); + simulateTetherReady(); + verify(mP2pListener).onGroupCreating(); + ArgumentCaptor<WifiP2pInfo> p2pInfoCaptor = ArgumentCaptor.forClass(WifiP2pInfo.class); + ArgumentCaptor<WifiP2pGroup> p2pGroupCaptor = ArgumentCaptor.forClass(WifiP2pGroup.class); + verify(mP2pListener).onGroupCreated(p2pInfoCaptor.capture(), p2pGroupCaptor.capture()); + assertEquals(TEST_NETWORK_NAME, p2pGroupCaptor.getValue().getNetworkName()); + assertTrue(p2pGroupCaptor.getValue().isClientListEmpty()); + assertTrue(p2pInfoCaptor.getValue().groupFormed); + + WifiP2pDevice peerClientDevice = new WifiP2pDevice(); + peerClientDevice.deviceName = "peerClientDeviceName"; + peerClientDevice.deviceAddress = "11:22:33:aa:bb:cc"; + peerClientDevice.setInterfaceMacAddress(MacAddress.fromString(PEER_INTERFACE_ADDRESS)); + sendSimpleMsg(null, WifiP2pMonitor.AP_STA_CONNECTED_EVENT, peerClientDevice); + verify(mP2pListener).onPeerClientJoined(p2pInfoCaptor.capture(), + p2pGroupCaptor.capture()); + assertFalse(p2pGroupCaptor.getValue().isClientListEmpty()); + assertTrue(p2pInfoCaptor.getValue().groupFormed); + + sendSimpleMsg(null, WifiP2pMonitor.AP_STA_DISCONNECTED_EVENT, peerClientDevice); + verify(mP2pListener).onPeerClientDisconnected(p2pInfoCaptor.capture(), + p2pGroupCaptor.capture()); + assertTrue(p2pGroupCaptor.getValue().isClientListEmpty()); + assertTrue(p2pInfoCaptor.getValue().groupFormed); + verify(mP2pListener, atLeastOnce()).onPeerListChanged(any()); + + sendSimpleMsg(null, WifiP2pMonitor.P2P_FREQUENCY_CHANGED_EVENT, TEST_GROUP_FREQUENCY); + verify(mP2pListener).onFrequencyChanged(p2pInfoCaptor.capture(), + p2pGroupCaptor.capture()); + assertEquals(TEST_GROUP_FREQUENCY, p2pGroupCaptor.getValue().getFrequency()); + + sendGroupRemovedMsg(); + mockEnterDisabledState(); + mLooper.dispatchAll(); + verify(mP2pListener).onGroupRemoved(); + + mWifiP2pServiceImpl.unregisterWifiP2pListener(mP2pListener); + doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceNearbyDevicesPermission( + any(), anyBoolean(), any()); + assertThrows(SecurityException.class, + () -> mWifiP2pServiceImpl.registerWifiP2pListener(mP2pListener, TEST_PACKAGE_NAME, + mExtras)); + } + + /** + * Verify that p2p disable when the D2d allowed value changes to false + */ + @Test + public void testP2pChangeToDisableWhenD2DAllowedToFalse() + throws Exception { + when(mWifiSettingsConfigStore.get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED))) + .thenReturn(true); + when(mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()).thenReturn(true); + when(mFeatureFlags.d2dWhenInfraStaOff()).thenReturn(true); + simulateWifiStateChange(false); + checkIsP2pInitWhenClientConnected(true, mClient1, + new WorkSource(mClient1.getCallingUid(), TEST_PACKAGE_NAME)); + when(mWifiSettingsConfigStore.get(eq(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED))) + .thenReturn(false); + mD2DAllowedSettingsCallbackCaptor.getValue().onSettingsChanged( + D2D_ALLOWED_WHEN_INFRA_STA_DISABLED, false); + mLooper.dispatchAll(); + // P2P is really disabled when wifi is off. + verify(mWifiNative).teardownInterface(); + verify(mWifiMonitor).stopMonitoring(anyString()); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/rtt/RttMetricsTest.java b/service/tests/wifitests/src/com/android/server/wifi/rtt/RttMetricsTest.java index 7cb196d20f..3488351c9c 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/rtt/RttMetricsTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/rtt/RttMetricsTest.java @@ -599,13 +599,19 @@ public class RttMetricsTest extends WifiBaseTest { for (int i = 0; i < countAp; ++i) { placeholderMacBase[0]++; - builder.addResponder(new ResponderConfig(MacAddress.fromBytes(placeholderMacBase), - ResponderConfig.RESPONDER_AP, true, 0, 0, 0, 0, 0)); + builder.addResponder(new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromBytes(placeholderMacBase)) + .setResponderType(ResponderConfig.RESPONDER_AP) + .set80211mcSupported(true) + .build()); } for (int i = 0; i < countAware; ++i) { placeholderMacBase[0]++; - builder.addResponder(new ResponderConfig(MacAddress.fromBytes(placeholderMacBase), - ResponderConfig.RESPONDER_AWARE, true, 0, 0, 0, 0, 0)); + builder.addResponder(new ResponderConfig.Builder() + .setMacAddress(MacAddress.fromBytes(placeholderMacBase)) + .setResponderType(ResponderConfig.RESPONDER_AWARE) + .set80211mcSupported(true) + .build()); } return builder.build(); @@ -618,8 +624,14 @@ public class RttMetricsTest extends WifiBaseTest { for (ResponderConfig peer : request.mRttPeers) { - RangingResult rttResult = new RangingResult(status, peer.macAddress, - (int) (distance * 1000), 0, 0, 8, 8, null, null, null, 0, true); + RangingResult rttResult = new RangingResult.Builder() + .setStatus(status) + .setMacAddress(peer.getMacAddress()) + .setDistanceMm((int) (distance * 1000)) + .setNumAttemptedMeasurements(8) + .setNumSuccessfulMeasurements(8) + .set80211mcMeasurement(true) + .build(); distance += incrDistanceM; rangingResults.add(rttResult); } diff --git a/service/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java index 7c779ddc5f..c96116914d 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java @@ -315,7 +315,8 @@ public class RttServiceImplTest extends WifiBaseTest { for (int i = 0; i < numIter; ++i) { // even: MC, non-MC, Aware, odd: MC only if (i % 2 == 0) { - requests[i] = RttTestUtils.getDummyRangingRequestMcOnly((byte) i); + requests[i] = RttTestUtils.getDummyRangingRequestMcOnly((byte) i, + RangingRequest.getDefaultRttBurstSize()); } else { requests[i] = RttTestUtils.getDummyRangingRequest((byte) i); } @@ -423,21 +424,9 @@ public class RttServiceImplTest extends WifiBaseTest { RttTestUtils.getDummyRangingResults(mRequestCaptor.getValue()); results.first.remove(results.first.size() - 1); RangingResult removed = results.second.remove(results.second.size() - 1); - results.second.add( - new RangingResult( - RangingResult.STATUS_FAIL, - removed.getPeerHandle(), - 0, - 0, - 0, - 0, - 0, - null, - null, - null, - 0, - RangingResult.UNSPECIFIED, - RangingResult.UNSPECIFIED)); + results.second.add(new RangingResult.Builder() + .setPeerHandle(removed.getPeerHandle()) + .build()); clock.time += MEASUREMENT_DURATION; mRangingResultsCbCaptor.getValue() .onRangingResults(mIntCaptor.getValue(), results.first); @@ -899,16 +888,14 @@ public class RttServiceImplTest extends WifiBaseTest { RttTestUtils.getDummyRangingResults(request); results.first.remove(1); // remove a direct AWARE request RangingResult removed = results.second.remove(1); - results.second.add( - new RangingResult(RangingResult.STATUS_FAIL, removed.getMacAddress(), 0, 0, 0, 0, 0, - null, null, null, 0, false, RangingResult.UNSPECIFIED, - RangingResult.UNSPECIFIED)); + results.second.add(new RangingResult.Builder() + .setMacAddress(removed.getMacAddress()) + .build()); results.first.remove(0); // remove an AP request removed = results.second.remove(0); - results.second.add( - new RangingResult(RangingResult.STATUS_FAIL, removed.getMacAddress(), 0, 0, 0, 0, 0, - null, null, null, 0, false, RangingResult.UNSPECIFIED, - RangingResult.UNSPECIFIED)); + results.second.add(new RangingResult.Builder() + .setMacAddress(removed.getMacAddress()) + .build()); // (1) request ranging operation mDut.startRanging(mockIbinder, mPackageName, mFeatureId, null, request, @@ -949,10 +936,9 @@ public class RttServiceImplTest extends WifiBaseTest { RttTestUtils.getDummyRangingResults(request); List<RangingResult> allFailResults = new ArrayList<>(); for (RangingResult result : results.second) { - allFailResults.add( - new RangingResult(RangingResult.STATUS_FAIL, result.getMacAddress(), 0, 0, 0, 0, - 0, null, null, null, 0, false, RangingResult.UNSPECIFIED, - RangingResult.UNSPECIFIED)); + allFailResults.add(new RangingResult.Builder() + .setMacAddress(result.getMacAddress()) + .build()); } // (1) request ranging operation diff --git a/service/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java b/service/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java index 3af1324bab..2ddeeeb03e 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java +++ b/service/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java @@ -77,10 +77,9 @@ public class RttTestUtils { } /** - * Returns a placeholder ranging request with 2 requests: - * - First: 802.11mc capable + * Returns a placeholder ranging request with 11mc request with a specified burst size. */ - public static RangingRequest getDummyRangingRequestMcOnly(byte lastMacByte) { + public static RangingRequest getDummyRangingRequestMcOnly(byte lastMacByte, int rttBurstSize) { RangingRequest.Builder builder = new RangingRequest.Builder(); ScanResult scan1 = new ScanResult(); @@ -89,6 +88,7 @@ public class RttTestUtils { scan1.channelWidth = ScanResult.CHANNEL_WIDTH_40MHZ; builder.addAccessPoint(scan1); + builder.setRttBurstSize(rttBurstSize); return builder.build(); } @@ -127,49 +127,78 @@ public class RttTestUtils { if (request != null) { for (ResponderConfig peer : request.mRttPeers) { - RangingResult rangingResult; - halResults.add(new RangingResult(RangingResult.STATUS_SUCCESS, - peer.macAddress, rangeCmBase, rangeStdDevCmBase, rssiBase, - 8, 5, null, null, null, rangeTimestampBase, true, 5180, - ScanResult.CHANNEL_WIDTH_40MHZ)); + halResults.add(new RangingResult.Builder() + .setStatus(RangingResult.STATUS_SUCCESS) + .setMacAddress(peer.getMacAddress()) + .setDistanceMm(rangeCmBase) + .setDistanceStdDevMm(rangeStdDevCmBase) + .setRssi(rssiBase) + .setNumAttemptedMeasurements(8) + .setNumSuccessfulMeasurements(5) + .setRangingTimestampMillis(rangeTimestampBase) + .set80211mcMeasurement(true) + .setMeasurementChannelFrequencyMHz(5180) + .setMeasurementBandwidth(ScanResult.CHANNEL_WIDTH_40MHZ) + .build()); + RangingResult.Builder builder = new RangingResult.Builder() + .setStatus(RangingResult.STATUS_SUCCESS) + .setDistanceMm(rangeCmBase++) + .setDistanceStdDevMm(rangeStdDevCmBase++) + .setRssi(rssiBase++) + .setNumAttemptedMeasurements(8) + .setNumSuccessfulMeasurements(5) + .setRangingTimestampMillis(rangeTimestampBase++) + .set80211mcMeasurement(true) + .setMeasurementChannelFrequencyMHz(5180) + .setMeasurementBandwidth(ScanResult.CHANNEL_WIDTH_40MHZ); if (peer.peerHandle == null) { - rangingResult = new RangingResult(RangingResult.STATUS_SUCCESS, - peer.macAddress, rangeCmBase++, rangeStdDevCmBase++, rssiBase++, - 8, 5, null, null, null, rangeTimestampBase++, true, 5180, - ScanResult.CHANNEL_WIDTH_40MHZ); + builder.setMacAddress(peer.getMacAddress()); } else { - rangingResult = - new RangingResult( - RangingResult.STATUS_SUCCESS, - peer.peerHandle, - rangeCmBase++, - rangeStdDevCmBase++, - rssiBase++, - 8, - 5, - null, - null, - null, - rangeTimestampBase++, - 5180, - ScanResult.CHANNEL_WIDTH_40MHZ); + builder.setPeerHandle(peer.peerHandle); } + RangingResult rangingResult = builder.build(); results.add(rangingResult); - } } else { - results.add(new RangingResult(RangingResult.STATUS_SUCCESS, - MacAddress.fromString("10:01:02:03:04:05"), rangeCmBase++, - rangeStdDevCmBase++, rssiBase++, 8, 4, null, null, - null, rangeTimestampBase++, true, 5180, ScanResult.CHANNEL_WIDTH_40MHZ)); - results.add(new RangingResult(RangingResult.STATUS_SUCCESS, - MacAddress.fromString("1A:0B:0C:0D:0E:0F"), rangeCmBase++, - rangeStdDevCmBase++, rssiBase++, 9, 3, null, null, - null, rangeTimestampBase++, true, 5180, ScanResult.CHANNEL_WIDTH_40MHZ)); - results.add(new RangingResult(RangingResult.STATUS_SUCCESS, - MacAddress.fromString("08:09:08:07:06:05"), rangeCmBase++, - rangeStdDevCmBase++, rssiBase++, 10, 2, null, null, - null, rangeTimestampBase++, true, 5180, ScanResult.CHANNEL_WIDTH_40MHZ)); + results.add(new RangingResult.Builder() + .setStatus(RangingResult.STATUS_SUCCESS) + .setMacAddress(MacAddress.fromString("10:01:02:03:04:05")) + .setDistanceMm(rangeCmBase++) + .setDistanceStdDevMm(rangeStdDevCmBase++) + .setRssi(rssiBase++) + .setNumAttemptedMeasurements(8) + .setNumSuccessfulMeasurements(4) + .setRangingTimestampMillis(rangeTimestampBase++) + .set80211mcMeasurement(true) + .setMeasurementChannelFrequencyMHz(5180) + .setMeasurementBandwidth(ScanResult.CHANNEL_WIDTH_40MHZ) + .build()); + results.add(new RangingResult.Builder() + .setStatus(RangingResult.STATUS_SUCCESS) + .setMacAddress(MacAddress.fromString("1A:0B:0C:0D:0E:0F")) + .setDistanceMm(rangeCmBase++) + .setDistanceStdDevMm(rangeStdDevCmBase++) + .setRssi(rssiBase++) + .setNumAttemptedMeasurements(9) + .setNumSuccessfulMeasurements(3) + .setRangingTimestampMillis(rangeTimestampBase++) + .set80211mcMeasurement(true) + .setMeasurementChannelFrequencyMHz(5180) + .setMeasurementBandwidth(ScanResult.CHANNEL_WIDTH_40MHZ) + .build()); + results.add(new RangingResult.Builder() + .setStatus(RangingResult.STATUS_SUCCESS) + .setMacAddress(MacAddress.fromString("08:09:08:07:06:05")) + .setDistanceMm(rangeCmBase++) + .setDistanceStdDevMm(rangeStdDevCmBase++) + .setRssi(rssiBase++) + .setNumAttemptedMeasurements(10) + .setNumSuccessfulMeasurements(2) + .setRangingTimestampMillis(rangeTimestampBase++) + .set80211mcMeasurement(true) + .setMeasurementChannelFrequencyMHz(5180) + .setMeasurementBandwidth(ScanResult.CHANNEL_WIDTH_40MHZ) + .build()); halResults.addAll(results); } diff --git a/service/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java b/service/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java index 456d2fe971..b8f3a6bd46 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java @@ -97,6 +97,7 @@ import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.MockResources; import com.android.server.wifi.ScanResults; import com.android.server.wifi.WifiBaseTest; +import com.android.server.wifi.WifiGlobals; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiLocalServices; import com.android.server.wifi.WifiMetrics; @@ -163,6 +164,7 @@ public class WifiScanningServiceTest extends WifiBaseTest { @Mock WifiManager mWifiManager; @Mock LastCallerInfoManager mLastCallerInfoManager; @Mock DeviceConfigFacade mDeviceConfigFacade; + @Mock WifiGlobals mWifiGlobals; PresetKnownBandsChannelHelper mChannelHelper0; PresetKnownBandsChannelHelper mChannelHelper1; TestLooper mLooper; @@ -193,7 +195,8 @@ public class WifiScanningServiceTest extends WifiBaseTest { mSwPnoMobilityIterations); mResources.setInteger(R.integer.config_wifiSwPnoFastTimerIterations, mSwPnoFastIterations); mResources.setInteger(R.integer.config_wifiSwPnoSlowTimerIterations, mSwPnoSlowIterations); - mResources.setBoolean(R.bool.config_wifiSwPnoEnabled, true); + when(mWifiInjector.getWifiGlobals()).thenReturn(mWifiGlobals); + when(mWifiGlobals.isSwPnoEnabled()).thenReturn(true); when(mContext.getResources()).thenReturn(mResources); when(mWifiInjector.getWifiPermissionsUtil()) diff --git a/service/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java index 40f1c5364e..e0d780ee14 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java @@ -839,7 +839,7 @@ public class ApConfigUtilTest extends WifiBaseTest { when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ)) .thenReturn(ALLOWED_5G_FREQS); // ch# 149, 153 mCapability = ApConfigUtil.updateSoftApCapabilityWithAvailableChannelList(mCapability, - mContext, mWifiNative); + mContext, mWifiNative, null); assertEquals(SoftApManager.START_RESULT_SUCCESS, ApConfigUtil.updateApChannelConfig(mWifiNative, mCoexManager, mResources, TEST_COUNTRY_CODE, configBuilder, configBuilder.build(), diff --git a/service/tests/wifitests/src/com/android/server/wifi/util/HalAidlUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/util/HalAidlUtilTest.java index 7703e0af99..102ef51d8a 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/util/HalAidlUtilTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/util/HalAidlUtilTest.java @@ -21,6 +21,7 @@ import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; +import android.hardware.wifi.common.OuiKeyedData; import android.net.wifi.util.PersistableBundleUtils; import android.os.PersistableBundle; @@ -56,6 +57,13 @@ public class HalAidlUtilTest { oui, createTestPersistableBundle()).build(); } + private static OuiKeyedData createHalOuiKeyedData(int oui) { + OuiKeyedData data = new OuiKeyedData(); + data.oui = oui; + data.vendorData = createTestPersistableBundle(); + return data; + } + private static boolean frameworkAndHalOuiKeyedDataEqual( android.net.wifi.OuiKeyedData frameworkData, android.hardware.wifi.common.OuiKeyedData halData) { @@ -97,4 +105,39 @@ public class HalAidlUtilTest { HalAidlUtil.frameworkToHalOuiKeyedDataList(frameworkList); assertEquals(0, halList.length); } + + /** + * Test the conversion of a valid HAL OuiKeyedData list to its framework equivalent. + */ + @Test + public void testConvertOuiKeyedDataToFramework() { + OuiKeyedData[] halList = new OuiKeyedData[TEST_VENDOR_DATA_LIST_SIZE]; + for (int i = 0; i < TEST_VENDOR_DATA_LIST_SIZE; i++) { + halList[i] = createHalOuiKeyedData(i + 1); + } + + List<android.net.wifi.OuiKeyedData> frameworkList = + HalAidlUtil.halToFrameworkOuiKeyedDataList(halList); + assertEquals(frameworkList.size(), halList.length); + for (int i = 0; i < TEST_VENDOR_DATA_LIST_SIZE; i++) { + assertTrue(frameworkAndHalOuiKeyedDataEqual(frameworkList.get(i), halList[i])); + } + } + + /** + * Test the conversion of an invalid OuiKeyedData list. Invalid entries should be ignored. + */ + @Test + public void testConvertOuiKeyedDataToFramework_invalid() { + OuiKeyedData[] halList = new OuiKeyedData[TEST_VENDOR_DATA_LIST_SIZE]; + for (int i = 0; i < TEST_VENDOR_DATA_LIST_SIZE; i++) { + // Fill list with entries that have an invalid OUI. + halList[i] = createHalOuiKeyedData(0); + } + + // No entries should appear in the converted list. + List<android.net.wifi.OuiKeyedData> frameworkList = + HalAidlUtil.halToFrameworkOuiKeyedDataList(halList); + assertEquals(0, frameworkList.size()); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java index f595de37f6..0d5e495193 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue; import android.net.MacAddress; import android.net.wifi.ScanResult; import android.net.wifi.ScanResult.InformationElement; +import android.util.SparseIntArray; import androidx.test.filters.SmallTest; @@ -462,33 +463,38 @@ public class InformationElementUtilTest extends WifiBaseTest { } private void verifyCapabilityStringFromIes( - InformationElement[] ies, int beaconCap, boolean isOweSupported, - String capsStr) { + InformationElement[] ies, + int beaconCap, + boolean isOweSupported, + String capsStr, + SparseIntArray unknownAkmMap) { InformationElementUtil.Capabilities capabilities = new InformationElementUtil.Capabilities(); - capabilities.from(ies, beaconCap, isOweSupported, 2400); + capabilities.from(ies, beaconCap, isOweSupported, 2400, unknownAkmMap); String result = capabilities.generateCapabilitiesString(); assertEquals(capsStr, result); } private void verifyCapabilityStringFromIe( - InformationElement ie, int beaconCap, boolean isOweSupported, - String capsStr) { + InformationElement ie, + int beaconCap, + boolean isOweSupported, + String capsStr, + SparseIntArray unknownAkmMap) { InformationElement[] ies = new InformationElement[] { ie }; - verifyCapabilityStringFromIes(new InformationElement[] { ie }, - beaconCap, isOweSupported, capsStr); - + verifyCapabilityStringFromIes( + new InformationElement[] {ie}, beaconCap, isOweSupported, capsStr, unknownAkmMap); } private void verifyCapabilityStringFromIeWithoutOweSupported( InformationElement ie, String capsStr) { - verifyCapabilityStringFromIe(ie, 0x1 << 4, false, capsStr); + verifyCapabilityStringFromIe(ie, 0x1 << 4, false, capsStr, null); } private void verifyCapabilityStringFromIeWithOweSupported( - InformationElement ie, String capsStr) { - verifyCapabilityStringFromIe(ie, 0x1 << 4, true, capsStr); + InformationElement ie, String capsStr, SparseIntArray unknownAkmMap) { + verifyCapabilityStringFromIe(ie, 0x1 << 4, true, capsStr, unknownAkmMap); } /** @@ -791,10 +797,12 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0xF2, (byte) 0x02, (byte) 0x00, (byte) 0x00 }; InformationElement[] ies = new InformationElement[] { ieWpa, ieRsn }; - verifyCapabilityStringFromIes(ies, + verifyCapabilityStringFromIes( + ies, 0x1 << 4, false, - "[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][RSN-PSK-CCMP+TKIP]"); + "[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][RSN-PSK-CCMP+TKIP]", + null); } /** @@ -822,8 +830,8 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x08, // Padding (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIeWithOweSupported(ieRsn, - "[WPA2-PSK-CCMP][RSN-PSK+SAE-CCMP]"); + verifyCapabilityStringFromIeWithOweSupported( + ieRsn, "[WPA2-PSK-CCMP][RSN-PSK+SAE-CCMP]", null); } /** @@ -851,8 +859,7 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x09, // Padding (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIeWithOweSupported(ieRsn, - "[RSN-SAE+FT/SAE-CCMP]"); + verifyCapabilityStringFromIeWithOweSupported(ieRsn, "[RSN-SAE+FT/SAE-CCMP]", null); } /** @@ -880,8 +887,7 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x18, // Padding (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIeWithOweSupported(ieRsn, - "[RSN-SAE+SAE_EXT_KEY-CCMP]"); + verifyCapabilityStringFromIeWithOweSupported(ieRsn, "[RSN-SAE+SAE_EXT_KEY-CCMP]", null); } /** @@ -910,8 +916,8 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x19, // Padding (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIeWithOweSupported(ieRsn, - "[RSN-SAE_EXT_KEY+FT/SAE_EXT_KEY-CCMP]"); + verifyCapabilityStringFromIeWithOweSupported( + ieRsn, "[RSN-SAE_EXT_KEY+FT/SAE_EXT_KEY-CCMP]", null); } /** @@ -937,8 +943,7 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x12, // Padding (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIeWithOweSupported(ieRsn, - "[RSN-OWE-CCMP]"); + verifyCapabilityStringFromIeWithOweSupported(ieRsn, "[RSN-OWE-CCMP]", null); } /** @@ -954,8 +959,7 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x50, (byte) 0x6F, (byte) 0x9A, (byte) 0x1C, // OWE IE contains BSSID, SSID and channel of other BSS, but we don't parse it. (byte) 0x00, (byte) 0x000, (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIe(ieOwe, 0x1 << 0, true, - "[RSN-OWE_TRANSITION-CCMP][ESS]"); + verifyCapabilityStringFromIe(ieOwe, 0x1 << 0, true, "[RSN-OWE_TRANSITION-CCMP][ESS]", null); } /** @@ -971,8 +975,7 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x50, (byte) 0x6F, (byte) 0x9A, (byte) 0x1C, // OWE IE contains BSSID, SSID and channel of other BSS, but we don't parse it. (byte) 0x00, (byte) 0x000, (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIe(ieOwe, 0x1 << 0, false, - "[ESS]"); + verifyCapabilityStringFromIe(ieOwe, 0x1 << 0, false, "[ESS]", null); } /** @@ -1035,9 +1038,11 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x0E, // RSN capabilities (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIeWithOweSupported(ieRsn, + verifyCapabilityStringFromIeWithOweSupported( + ieRsn, "[WPA2-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA256-CCMP]" - + "[RSN-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA256-CCMP]"); + + "[RSN-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA256-CCMP]", + null); } /** @@ -1068,9 +1073,60 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x0F, // RSN capabilities (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIeWithOweSupported(ieRsn, + verifyCapabilityStringFromIeWithOweSupported( + ieRsn, "[WPA2-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA384-CCMP]" - + "[RSN-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA384-CCMP]"); + + "[RSN-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA384-CCMP]", + null); + } + + /** + * Test Capabilities.generateCapabilitiesString() with RSN IE, CCMP and unknown AKM suite + * selector. Expect the function to return a capability string with the mapped AKM scheme. + */ + @Test + public void buildCapabilities_rsnIeUnknownAkmMapping() { + // unknown AKM (0x00, 0x40, 0x96, 0x00) -> known AKM (0x00, 0x0F, 0xAC, 0x18) - SAE_EXT_KEY + SparseIntArray unknownAkmMap = + new SparseIntArray() { + { + put(0x00964000, 0x12); + } + }; + InformationElement ieRsn = new InformationElement(); + ieRsn.id = InformationElement.EID_RSN; + ieRsn.bytes = + new byte[] { + // RSNE Version (0x0001) + (byte) 0x01, + (byte) 0x00, + // Group cipher suite: CCMP + (byte) 0x00, + (byte) 0x0F, + (byte) 0xAC, + (byte) 0x04, + // Number of cipher suites (1) + (byte) 0x01, + (byte) 0x00, + // Cipher suite: CCMP + (byte) 0x00, + (byte) 0x0F, + (byte) 0xAC, + (byte) 0x04, + // Number of AKMs (1) + (byte) 0x01, + (byte) 0x00, + // unknown AKM (0x00, 0x40, 0x96, 0x00) + (byte) 0x00, + (byte) 0x40, + (byte) 0x96, + (byte) 0x00, + // RSN capabilities + (byte) 0x00, + (byte) 0x00 + }; + verifyCapabilityStringFromIeWithOweSupported( + ieRsn, "[RSN-SAE_EXT_KEY-CCMP]", unknownAkmMap); } /** @@ -1092,10 +1148,7 @@ public class InformationElementUtilTest extends WifiBaseTest { (byte) 0xF2, (byte) 0x02, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x50 }; InformationElement[] ies = new InformationElement[] { ieWpa, ieRsn }; - verifyCapabilityStringFromIes(ies, - 0x1 << 4, - false, - "[WPA][RSN]"); + verifyCapabilityStringFromIes(ies, 0x1 << 4, false, "[WPA][RSN]", null); } /** @@ -1119,10 +1172,7 @@ public class InformationElementUtilTest extends WifiBaseTest { ieWps.bytes = new byte[] { (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x04 }; InformationElement[] ies = new InformationElement[] { ieWpa, ieWps }; - verifyCapabilityStringFromIes(ies, - 0x1 << 4, - false, - "[WPA-PSK-CCMP+TKIP][WPS]"); + verifyCapabilityStringFromIes(ies, 0x1 << 4, false, "[WPA-PSK-CCMP+TKIP][WPS]", null); } /** @@ -1156,7 +1206,7 @@ public class InformationElementUtilTest extends WifiBaseTest { ie.bytes = new byte[] { (byte) 0x00, (byte) 0x04, (byte) 0x0E, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIe(ie, 0, false, ""); + verifyCapabilityStringFromIe(ie, 0, false, "", null); } /** @@ -1172,7 +1222,7 @@ public class InformationElementUtilTest extends WifiBaseTest { ie.bytes = new byte[] { (byte) 0x00, (byte) 0x04, (byte) 0x0E, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIe(ie, 0x1 << 0, false, "[ESS]"); + verifyCapabilityStringFromIe(ie, 0x1 << 0, false, "[ESS]", null); } /** @@ -1189,7 +1239,7 @@ public class InformationElementUtilTest extends WifiBaseTest { ie.bytes = new byte[] { (byte) 0x00, (byte) 0x04, (byte) 0x0E, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; - verifyCapabilityStringFromIe(ie, 0, false, ""); + verifyCapabilityStringFromIe(ie, 0, false, "", null); } /** @@ -1203,7 +1253,7 @@ public class InformationElementUtilTest extends WifiBaseTest { InformationElementUtil.Capabilities capabilities = new InformationElementUtil.Capabilities(); - capabilities.from(new InformationElement[0], beaconCap, false, 2400); + capabilities.from(new InformationElement[0], beaconCap, false, 2400, null); String result = capabilities.generateCapabilitiesString(); assertEquals("[IBSS]", result); @@ -1220,7 +1270,7 @@ public class InformationElementUtilTest extends WifiBaseTest { InformationElementUtil.Capabilities capabilities = new InformationElementUtil.Capabilities(); - capabilities.from(new InformationElement[0], beaconCap, false, 58320); + capabilities.from(new InformationElement[0], beaconCap, false, 58320, null); String result = capabilities.generateCapabilitiesString(); assertEquals("[IBSS]", result); @@ -1237,7 +1287,7 @@ public class InformationElementUtilTest extends WifiBaseTest { InformationElementUtil.Capabilities capabilities = new InformationElementUtil.Capabilities(); - capabilities.from(new InformationElement[0], beaconCap, false, 58320); + capabilities.from(new InformationElement[0], beaconCap, false, 58320, null); String result = capabilities.generateCapabilitiesString(); assertEquals("[ESS]", result); @@ -1259,8 +1309,8 @@ public class InformationElementUtilTest extends WifiBaseTest { extendedCap.from(ie); assertFalse(extendedCap.isStrictUtf8()); assertFalse(extendedCap.is80211McRTTResponder()); - assertFalse(extendedCap.isTriggerBasedRangingRespSupported()); - assertFalse(extendedCap.isNonTriggerBasedRangingRespSupported()); + assertFalse(extendedCap.is80211azTbResponder()); + assertFalse(extendedCap.is80211azNtbResponder()); assertFalse(extendedCap.isTwtRequesterSupported()); assertFalse(extendedCap.isTwtResponderSupported()); assertFalse(extendedCap.isFilsCapable()); @@ -1318,8 +1368,8 @@ public class InformationElementUtilTest extends WifiBaseTest { InformationElementUtil.ExtendedCapabilities extendedCap = new InformationElementUtil.ExtendedCapabilities(); extendedCap.from(ie); - assertTrue(extendedCap.isTriggerBasedRangingRespSupported()); - assertTrue(extendedCap.isNonTriggerBasedRangingRespSupported()); + assertTrue(extendedCap.is80211azTbResponder()); + assertTrue(extendedCap.is80211azNtbResponder()); assertTrue(extendedCap.isTwtRequesterSupported()); assertTrue(extendedCap.isTwtResponderSupported()); assertTrue(extendedCap.isFilsCapable()); @@ -2519,11 +2569,10 @@ public class InformationElementUtilTest extends WifiBaseTest { } /** - * Verify that the expected EHT Operation information element is parsed and - * DisabledSubchannelBitmap is present. + * Verify that the expected EHT Operation information element is parsed correctly. */ @Test - public void testEhtOperationElementWithDisabledSubchannelBitmapPresent() throws Exception { + public void testEhtOperationElement() throws Exception { InformationElement ie = new InformationElement(); ie.id = InformationElement.EID_EXTENSION_PRESENT; ie.idExt = InformationElement.EID_EXT_EHT_OPERATION; @@ -2549,8 +2598,28 @@ public class InformationElementUtilTest extends WifiBaseTest { ehtOperation.from(ie); assertTrue(ehtOperation.isPresent()); + assertTrue(ehtOperation.isEhtOperationInfoPresent()); assertTrue(ehtOperation.isDisabledSubchannelBitmapPresent()); assertArrayEquals(new byte[]{(byte) 0x3, (byte) 0x0}, ehtOperation.getDisabledSubchannelBitmap()); + assertEquals(ScanResult.CHANNEL_WIDTH_160MHZ, ehtOperation.getChannelWidth()); + assertEquals(5250, ehtOperation.getCenterFreq0(ScanResult.WIFI_BAND_5_GHZ)); + assertEquals(5250, ehtOperation.getCenterFreq0(ScanResult.WIFI_BAND_5_GHZ)); + + ie.bytes = new byte[]{(byte) 0x01, //EHT Operation Param + (byte) 0x44, (byte) 0x44, (byte) 0x44, (byte) 0x44, //EHT-MCS + (byte) 0x04, (byte) 0x2f, (byte) 0x1f}; //EHT Operation Info: Control, CCFS0, CCFS1 + + ehtOperation.from(ie); + + assertTrue(ehtOperation.isPresent()); + assertTrue(ehtOperation.isEhtOperationInfoPresent()); + assertFalse(ehtOperation.isDisabledSubchannelBitmapPresent()); + assertEquals(ScanResult.CHANNEL_WIDTH_320MHZ, ehtOperation.getChannelWidth()); + // Center frequency of channel index 47 (0x2F), 160 Mhz + assertEquals(6185, ehtOperation.getCenterFreq0(ScanResult.WIFI_BAND_6_GHZ)); + // Center frequency of channel index 31 (0x1F), 320 Mhz + assertEquals(6105, ehtOperation.getCenterFreq1(ScanResult.WIFI_BAND_6_GHZ)); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java index efdc2d5c9f..a53ace0010 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java @@ -770,8 +770,8 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, TEST_FEATURE_ID, mUid); // verify that checking FINE for legacy apps! - verify(mMockAppOps).noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), anyInt(), anyString(), - any(), any()); + verify(mMockAppOps).noteOpNoThrow(eq(AppOpsManager.OPSTR_FINE_LOCATION), anyInt(), + anyString(), any(), any()); } /** @@ -793,7 +793,8 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { codeUnderTest.enableVerboseLogging(true); codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, TEST_FEATURE_ID, mUid); verify(mMockAppOps) - .noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), anyInt(), anyString(), any(), any()); + .noteOpNoThrow(eq(AppOpsManager.OPSTR_FINE_LOCATION), anyInt(), anyString(), + any(), any()); } /** @@ -821,7 +822,7 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { } catch (SecurityException e) { // empty } - verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString()); + verify(mMockAppOps, never()).noteOpNoThrow(anyInt(), anyInt(), anyString()); } /** @@ -869,52 +870,6 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { } /** - * Verifies the helper method exposed for checking SYSTERM_ALERT_WINDOW permission. - */ - @Test - public void testCheckSystemAlertWindowPermissionWithModeDefaultAppOps() throws Exception { - setupMocks(); - WifiPermissionsUtil wifiPermissionsUtil = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockUserManager, mWifiInjector); - wifiPermissionsUtil.enableVerboseLogging(true); - - when(mMockAppOps.noteOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, MANAGED_PROFILE_UID, - TEST_PACKAGE_NAME, null, null)) - .thenReturn(AppOpsManager.MODE_DEFAULT); - when(mMockPermissionsWrapper.getUidPermission( - Manifest.permission.SYSTEM_ALERT_WINDOW, MANAGED_PROFILE_UID)) - .thenReturn(PackageManager.PERMISSION_DENIED); - assertFalse(wifiPermissionsUtil.checkSystemAlertWindowPermission( - MANAGED_PROFILE_UID, TEST_PACKAGE_NAME)); - - when(mMockAppOps.noteOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, MANAGED_PROFILE_UID, - TEST_PACKAGE_NAME, null, null)) - .thenReturn(AppOpsManager.MODE_DEFAULT); - when(mMockPermissionsWrapper.getUidPermission( - Manifest.permission.SYSTEM_ALERT_WINDOW, MANAGED_PROFILE_UID)) - .thenReturn(PackageManager.PERMISSION_GRANTED); - assertTrue(wifiPermissionsUtil.checkSystemAlertWindowPermission( - MANAGED_PROFILE_UID, TEST_PACKAGE_NAME)); - } - - /** - * Verifies the helper method exposed for checking SYSTERM_ALERT_WINDOW permission. - */ - @Test - public void testCheckSystemAlertWindowPermissionWithModeAllowedAppOps() throws Exception { - setupMocks(); - WifiPermissionsUtil wifiPermissionsUtil = new WifiPermissionsUtil(mMockPermissionsWrapper, - mMockContext, mMockUserManager, mWifiInjector); - wifiPermissionsUtil.enableVerboseLogging(true); - - when(mMockAppOps.noteOp( - AppOpsManager.OP_SYSTEM_ALERT_WINDOW, MANAGED_PROFILE_UID, TEST_PACKAGE_NAME)) - .thenReturn(AppOpsManager.MODE_ALLOWED); - assertTrue(wifiPermissionsUtil.checkSystemAlertWindowPermission( - MANAGED_PROFILE_UID, TEST_PACKAGE_NAME)); - } - - /** * Verifies the helper method exposed for checking if the app is a DeviceOwner. */ @Test @@ -1186,8 +1141,8 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { verify(mMockAppOps, never()) .unsafeCheckOp(AppOpsManager.OPSTR_FINE_LOCATION, mUid, TEST_PACKAGE_NAME); - verify(mMockAppOps).noteOp(AppOpsManager.OPSTR_FINE_LOCATION, mUid, TEST_PACKAGE_NAME, - TEST_FEATURE_ID, null); + verify(mMockAppOps).noteOpNoThrow(AppOpsManager.OPSTR_FINE_LOCATION, mUid, + TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); } /** @@ -1315,7 +1270,7 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { verify(mMockAppOps).unsafeCheckOp(AppOpsManager.OPSTR_FINE_LOCATION, mUid, TEST_PACKAGE_NAME); - verify(mMockAppOps, never()).noteOp( + verify(mMockAppOps, never()).noteOpNoThrow( AppOpsManager.OPSTR_FINE_LOCATION, mUid, TEST_PACKAGE_NAME, null, null); } @@ -1491,8 +1446,8 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { codeUnderTest.enableVerboseLogging(true); codeUnderTest.enforceCanAccessScanResultsForWifiScanner(TEST_PACKAGE_NAME, TEST_FEATURE_ID, mUid, IGNORE_LOCATION_SETTINGS, DONT_HIDE_FROM_APP_OPS); - verify(mMockAppOps).noteOp(AppOpsManager.OPSTR_FINE_LOCATION, mUid, TEST_PACKAGE_NAME, - TEST_FEATURE_ID, null); + verify(mMockAppOps).noteOpNoThrow(AppOpsManager.OPSTR_FINE_LOCATION, mUid, + TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); } /** @@ -1785,12 +1740,12 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { eq(GET_PERMISSIONS | MATCH_UNINSTALLED_PACKAGES))).thenReturn( mPackagePermissionInfo); when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr); - when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PACKAGE_NAME, + when(mMockAppOps.noteOpNoThrow(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null)).thenReturn(mWifiScanAllowApps); - when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid), + when(mMockAppOps.noteOpNoThrow(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), nullable(String.class))) .thenReturn(mAllowCoarseLocationApps); - when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid), + when(mMockAppOps.noteOpNoThrow(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), nullable(String.class))) .thenReturn(mAllowFineLocationApps); when(mMockAppOps.unsafeCheckOp(AppOpsManager.OPSTR_FINE_LOCATION, mUid, TEST_PACKAGE_NAME)) @@ -1875,8 +1830,8 @@ public class WifiPermissionsUtilTest extends WifiBaseTest { codeUnderTest.enableVerboseLogging(true); codeUnderTest.enforceCoarseLocationPermission(TEST_PACKAGE_NAME, TEST_FEATURE_ID, mUid); // verify that checking Coarse for apps! - verify(mMockAppOps).noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), anyInt(), anyString(), - any(), any()); + verify(mMockAppOps).noteOpNoThrow(eq(AppOpsManager.OPSTR_COARSE_LOCATION), anyInt(), + anyString(), any(), any()); } @Test diff --git a/service/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java index 79d9cce0b8..389686ee77 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java @@ -16,8 +16,15 @@ package com.android.server.wifi.util; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; +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.net.IpConfiguration; import android.net.MacAddress; @@ -32,6 +39,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.MacAddressUtils; +import com.android.server.wifi.OuiKeyedDataUtil; import com.android.server.wifi.WifiBaseTest; import com.android.server.wifi.WifiConfigurationTestUtil; import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil; @@ -143,7 +151,9 @@ public class XmlUtilTest extends WifiBaseTest { throws IOException, XmlPullParserException { mWifiConfigStoreEncryptionUtil = mock(WifiConfigStoreEncryptionUtil.class); WifiConfiguration wepNetwork = WifiConfigurationTestUtil.createWepNetwork(); + wepNetwork.wepKeys = WifiConfigurationTestUtil.TEST_WEP_KEYS_WITH_NULL; for (int i = 0; i < wepNetwork.wepKeys.length; i++) { + if (wepNetwork.wepKeys[i] == null) continue; EncryptedData encryptedData = new EncryptedData(new byte[]{(byte) i}, new byte[]{(byte) i}); when(mWifiConfigStoreEncryptionUtil.encrypt(wepNetwork.wepKeys[i].getBytes())) @@ -163,7 +173,9 @@ public class XmlUtilTest extends WifiBaseTest { throws IOException, XmlPullParserException { mWifiConfigStoreEncryptionUtil = mock(WifiConfigStoreEncryptionUtil.class); WifiConfiguration wepNetwork = WifiConfigurationTestUtil.createWepNetwork(); + wepNetwork.wepKeys = WifiConfigurationTestUtil.TEST_WEP_KEYS_WITH_NULL; for (int i = 0; i < wepNetwork.wepKeys.length; i++) { + if (wepNetwork.wepKeys[i] == null) continue; when(mWifiConfigStoreEncryptionUtil.encrypt(wepNetwork.wepKeys[i].getBytes())) .thenReturn(null); } @@ -630,6 +642,73 @@ public class XmlUtilTest extends WifiBaseTest { retrieved.second.macRandomizationSetting); } + /** + * Verify serializing/deserializing DHCP hostname setting. + * @throws Exception + */ + @Test + public void testSendDhcpHostnameEnabledSerializeDeserialize() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); + config.setSendDhcpHostnameEnabled(true); + serializeDeserializeWifiConfiguration(config); + } + + /** + * Verify that deserializing an XML without SEND_DHCP_HOSTNAME will automatically set the value + * to true for secure networks. + * @throws IOException + * @throws XmlPullParserException + */ + @Test + public void testSendDhcpHostnameEnabledUpgradeToTrueForSecure() + throws IOException, XmlPullParserException { + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, mXmlDocHeader); + XmlUtil.writeNextSectionStart(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS_LIST); + XmlUtil.writeNextSectionStart(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS); + XmlUtil.writeNextValue(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE, + WifiConfiguration.SECURITY_TYPE_PSK); + XmlUtil.writeNextValue(out, WifiConfigurationXmlUtil.XML_TAG_IS_ENABLED, true); + XmlUtil.writeNextSectionEnd(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS); + XmlUtil.writeNextSectionEnd(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS_LIST); + XmlUtil.writeDocumentEnd(out, mXmlDocHeader); + + Pair<String, WifiConfiguration> retrieved = + deserializeWifiConfiguration(outputStream.toByteArray(), false); + + assertTrue(retrieved.second.isSendDhcpHostnameEnabled()); + } + + /** + * Verify that deserializing an XML without SEND_DHCP_HOSTNAME will automatically set the value + * to true for secure networks. + * @throws IOException + * @throws XmlPullParserException + */ + @Test + public void testSendDhcpHostnameEnabledUpgradeToFalseForOpen() + throws IOException, XmlPullParserException { + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, mXmlDocHeader); + XmlUtil.writeNextSectionStart(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS_LIST); + XmlUtil.writeNextSectionStart(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS); + XmlUtil.writeNextValue(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE, + WifiConfiguration.SECURITY_TYPE_OPEN); + XmlUtil.writeNextValue(out, WifiConfigurationXmlUtil.XML_TAG_IS_ENABLED, true); + XmlUtil.writeNextSectionEnd(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS); + XmlUtil.writeNextSectionEnd(out, WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS_LIST); + XmlUtil.writeDocumentEnd(out, mXmlDocHeader); + + Pair<String, WifiConfiguration> retrieved = + deserializeWifiConfiguration(outputStream.toByteArray(), false); + + assertFalse(retrieved.second.isSendDhcpHostnameEnabled()); + } + private WifiEnterpriseConfig makeTestWifiEnterpriseConfig() { final WifiEnterpriseConfig config = new WifiEnterpriseConfig(); config.setFieldValue(WifiEnterpriseConfig.IDENTITY_KEY, TEST_IDENTITY); @@ -892,4 +971,16 @@ public class XmlUtilTest extends WifiBaseTest { throws IOException, XmlPullParserException { testConfigStoreWithEncryptedPreSharedKey(true, true); } + + /** + * Verify that the vendor data field is serialized and deserialized correctly + * when provided. + */ + @Test + public void testWifiConfigurationWithVendorData() throws Exception { + assumeTrue(SdkLevel.isAtLeastV()); + WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); + config.setVendorData(OuiKeyedDataUtil.createTestOuiKeyedDataList(10)); + serializeDeserializeWifiConfiguration(config); + } } diff --git a/wifi_upload_hook.py b/wifi_upload_hook.py index 55fa267c15..ff063f5b02 100755 --- a/wifi_upload_hook.py +++ b/wifi_upload_hook.py @@ -28,13 +28,26 @@ STYLES_FILE = BASE_DIR + "values/styles.xml" DRAWABLE_DIR = BASE_DIR + "drawable/" LAYOUT_DIR = BASE_DIR + "layout/" -def is_commit_msg_valid(commit_msg): +BASE_WIFI_SERVICE_DIR = "service/java/com/android/server/wifi/" +XML_UTIL_FILE = BASE_WIFI_SERVICE_DIR + "util/XmlUtil.java" +CLOUD_BACKUP_RESTORE_FILE = BASE_WIFI_SERVICE_DIR + "WifiBackupRestore.java" +CLOUD_BACKUP_PARSER_FILE = BASE_WIFI_SERVICE_DIR + "WifiBackupDataV1Parser.java" + +def is_commit_msg_valid(commit_msg, checkResource, checkXmlTag): + isValid = True for line in commit_msg.splitlines(): line = line.strip().lower() - if line.startswith('updated-overlayable'): - return True - - return False + if checkResource: + if line.startswith('updated-overlayable'): + isValid = True + checkResource = False + if checkXmlTag: + isValid = False + if line.startswith('reviewed-cloud-b&r'): + isValid = True + checkXmlTag = False + + return isValid def is_in_aosp(): branches = subprocess.check_output(['git', 'branch', '-vv']).splitlines() @@ -61,6 +74,16 @@ def get_changed_resource_file(commit_files): return commit_file return None +def get_changed_xml_related_file(commit_files): + for commit_file in commit_files: + if commit_file == XML_UTIL_FILE: + return commit_file + if commit_file == CLOUD_BACKUP_RESTORE_FILE: + return commit_file + if commit_file == CLOUD_BACKUP_PARSER_FILE: + return commit_file + return None + def is_commit_msg_has_translation_bug_id(commit_msg): for line in commit_msg.splitlines(): line = line.strip().lower() @@ -68,51 +91,75 @@ def is_commit_msg_has_translation_bug_id(commit_msg): return True return False +def is_xml_tag_in_commits(): + cmd_run = subprocess.Popen('git show | grep -iE "XML_TAG"', + shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + out, err = cmd_run.communicate() + for line in out.splitlines(): + if line.startswith(b'+') or line.startswith(b'-'): + print('This commit has xml tag changed: "{changed_line}".'.format(changed_line=line.decode("utf-8"))) + print() + return True + return False def main(): - parser = ArgumentParser(description='Check if the overlayable file has been updated') + parser = ArgumentParser(description='Check if the dependency file has been updated') parser.add_argument('commit_msg', type=str, help='commit message') parser.add_argument('commit_files', type=str, nargs='*', help='files changed in the commit') args = parser.parse_args() commit_msg = args.commit_msg commit_files = args.commit_files - if is_in_aosp(): return 0 - changed_file = get_changed_resource_file(commit_files) - - if not changed_file: - return 0 - if changed_file == STRING_FILE: - if not is_commit_msg_has_translation_bug_id(commit_msg): - print('This commit has changed: "{changed_file}".'.format(changed_file=changed_file)) + changed_resource_file = get_changed_resource_file(commit_files) + + if changed_resource_file: + if changed_resource_file == STRING_FILE: + if not is_commit_msg_has_translation_bug_id(commit_msg): + print('This commit has changed: "{changed_file}".'.format(changed_resource_file=changed_resource_file)) + print() + print('Please add the following line to your commit message') + print() + print('Bug: 294871353') + print() + return 1 + + if not is_commit_msg_valid(commit_msg, True, False): + print('This commit has changed: "{changed_file}".'.format(changed_file=changed_resource_file)) + print() + print('If this change added/changed/removed overlayable resources used by the Wifi Module, ') + print('please update the "{overlay_file}".'.format(overlay_file=OVERLAY_FILE)) + print('and acknowledge you have done so by adding this line to your commit message:') + print() + print('Updated-Overlayable: TRUE') print() - print('Please add the following line to your commit message') + print('Otherwise, please explain why the Overlayable does not need to be updated:') print() - print('Bug: 294871353') + print('Updated-Overlayable: Not applicable - changing default value') + print() + return 1 + changed_xml_related_file = get_changed_xml_related_file(commit_files) + if changed_xml_related_file and is_xml_tag_in_commits(): + if not is_commit_msg_valid(commit_msg, False, True): + print('This commit has changed: "{changed_file}".'.format(changed_file=changed_xml_related_file)) + print() + print('If this change added/changed/removed xml resources used by the Wifi Module, ') + print('please review if it may break/miss the cloud B&R , check "{b_r_file}".'.format(b_r_file=CLOUD_BACKUP_PARSER_FILE)) + print('and acknowledge you have done so by adding this line to your commit message:') + print() + print('Reviewed-Cloud-B&R: TRUE') + print() + print('Otherwise, please explain why the cloud B&R does not need to be updated:') + print() + print('Reviewed-Cloud-B&R: Not applicable - not xml format change') print() return 1 - if is_commit_msg_valid(commit_msg): - return 0 - - print('This commit has changed: "{changed_file}".'.format(changed_file=changed_file)) - print() - print('If this change added/changed/removed overlayable resources used by the Wifi Module, ') - print('please update the "{overlay_file}".'.format(overlay_file=OVERLAY_FILE)) - print('and acknowledge you have done so by adding this line to your commit message:') - print() - print('Updated-Overlayable: TRUE') - print() - print('Otherwise, please explain why the Overlayable does not need to be updated:') - print() - print('Updated-Overlayable: Not applicable - changing default value') - print() - return 1 - + return 0 if __name__ == '__main__': exit_code = main() - sys.exit(exit_code)
\ No newline at end of file + sys.exit(exit_code) |