summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--framework/aidl-export/android/net/wifi/BlockingOption.aidl19
-rw-r--r--framework/api/current.txt15
-rw-r--r--framework/java/android/net/wifi/BlockingOption.java159
-rw-r--r--framework/java/android/net/wifi/IWifiManager.aidl3
-rw-r--r--framework/java/android/net/wifi/WifiManager.java21
-rw-r--r--framework/tests/src/android/net/wifi/BlockingOptionTest.java70
-rw-r--r--framework/tests/src/android/net/wifi/WifiManagerTest.java9
-rw-r--r--service/java/com/android/server/wifi/ClientMode.java6
-rw-r--r--service/java/com/android/server/wifi/ClientModeDefaults.java4
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java37
-rw-r--r--service/java/com/android/server/wifi/ConcreteClientModeManager.java6
-rw-r--r--service/java/com/android/server/wifi/WifiBlocklistMonitor.java8
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java1
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java26
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java13
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java13
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java11
17 files changed, 418 insertions, 3 deletions
diff --git a/framework/aidl-export/android/net/wifi/BlockingOption.aidl b/framework/aidl-export/android/net/wifi/BlockingOption.aidl
new file mode 100644
index 0000000000..47d4627114
--- /dev/null
+++ b/framework/aidl-export/android/net/wifi/BlockingOption.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 BlockingOption;
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 451f907e19..41062f1c6b 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -1,6 +1,20 @@
// Signature format: 2.0
package android.net.wifi {
+ @FlaggedApi("com.android.wifi.flags.bssid_blocklist_for_suggestion") public final class BlockingOption implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getBlockingTimeSeconds();
+ method public boolean isBlockingBssidOnly();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.BlockingOption> CREATOR;
+ }
+
+ @FlaggedApi("com.android.wifi.flags.bssid_blocklist_for_suggestion") public static final class BlockingOption.Builder {
+ ctor public BlockingOption.Builder(@IntRange(from=1, to=86400) int);
+ method @NonNull public android.net.wifi.BlockingOption build();
+ method @NonNull public android.net.wifi.BlockingOption.Builder setBlockingBssidOnly(boolean);
+ }
+
public abstract class EasyConnectStatusCallback {
field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
@@ -465,6 +479,7 @@ package android.net.wifi {
method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, String);
method @Deprecated public android.net.wifi.WifiManager.WifiLock createWifiLock(String);
method @Deprecated public boolean disableNetwork(int);
+ method @FlaggedApi("com.android.wifi.flags.bssid_blocklist_for_suggestion") @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public void disallowCurrentSuggestedNetwork(@NonNull android.net.wifi.BlockingOption);
method @Deprecated public boolean disconnect();
method @Deprecated public boolean enableNetwork(int, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_MANAGED_PROVISIONING, android.Manifest.permission.NETWORK_CARRIER_PROVISIONING}, conditional=true) public void flushPasspointAnqpCache();
diff --git a/framework/java/android/net/wifi/BlockingOption.java b/framework/java/android/net/wifi/BlockingOption.java
new file mode 100644
index 0000000000..ee152d4398
--- /dev/null
+++ b/framework/java/android/net/wifi/BlockingOption.java
@@ -0,0 +1,159 @@
+/*
+ * 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.IntRange;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import com.android.wifi.flags.Flags;
+
+import java.util.Objects;
+
+/**
+ * Options for blocking a network through
+ * {@link WifiManager#disallowCurrentSuggestedNetwork(BlockingOption)}
+ */
+@FlaggedApi(Flags.FLAG_BSSID_BLOCKLIST_FOR_SUGGESTION)
+public final class BlockingOption implements Parcelable {
+ private final int mDisableTime;
+ private final boolean mBSSIDOnly;
+
+ /**
+ * @hide
+ */
+ public BlockingOption(int disableTime, boolean bssidOnly) {
+ mDisableTime = disableTime;
+ mBSSIDOnly = bssidOnly;
+ }
+
+ /**
+ * @hide
+ */
+ public BlockingOption(Parcel in) {
+ mDisableTime = in.readInt();
+ mBSSIDOnly = in.readBoolean();
+ }
+
+ /**
+ * Get the blocking time which is set by {@link Builder#Builder(int)}
+ * @return Blocking time in seconds
+ */
+ public int getBlockingTimeSeconds() {
+ return mDisableTime;
+ }
+
+ /**
+ * Return whether or not a single BSSID is being blocked, which is set by
+ * {@link Builder#setBlockingBssidOnly(boolean)}
+ * @return True for blocking single BSSID, false otherwise.
+ */
+ public boolean isBlockingBssidOnly() {
+ return mBSSIDOnly;
+ }
+
+ /**
+ * Builder used to create {@link BlockingOption} objects.
+ */
+ @FlaggedApi(Flags.FLAG_BSSID_BLOCKLIST_FOR_SUGGESTION)
+ public static final class Builder {
+ private int mDisableTime;
+ private boolean mBSSIDOnly;
+
+ /**
+ * Create a {@link Builder} with blocking time for the network
+ *
+ * @param blockingTimeSec Time period to block the network in seconds
+ * @throws IllegalArgumentException if input is invalid.
+ */
+ public Builder(@IntRange(from = 1, to = 86400) int blockingTimeSec) {
+ if (blockingTimeSec < 1 || blockingTimeSec > 86400) {
+ throw new IllegalArgumentException("blockingTimeSec should between 1 to 86400");
+ }
+ mDisableTime = blockingTimeSec;
+ mBSSIDOnly = false;
+ }
+
+ /**
+ * Set to configure blocking the whole network or a single BSSID. By default, the whole
+ * network will be blocked.
+ * @param bssidOnly True for a single BSSID, otherwise the whole network will be blocked
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ @NonNull public Builder setBlockingBssidOnly(boolean bssidOnly) {
+ mBSSIDOnly = bssidOnly;
+ return this;
+ }
+
+ /**
+ * Create a BlockingOption object for use in
+ * {@link WifiManager#disallowCurrentSuggestedNetwork(BlockingOption)}.
+ */
+ @NonNull public BlockingOption build() {
+ return new BlockingOption(mDisableTime, mBSSIDOnly);
+ }
+ }
+
+ @NonNull
+ public static final Creator<BlockingOption> CREATOR = new Creator<BlockingOption>() {
+ @Override
+ public BlockingOption createFromParcel(Parcel in) {
+ return new BlockingOption(in);
+ }
+
+ @Override
+ public BlockingOption[] newArray(int size) {
+ return new BlockingOption[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mDisableTime);
+ dest.writeBoolean(mBSSIDOnly);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof BlockingOption lhs)) {
+ return false;
+ }
+ return mBSSIDOnly == lhs.mBSSIDOnly && mDisableTime == lhs.mDisableTime;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mBSSIDOnly, mDisableTime);
+ }
+
+ @Override
+ public String toString() {
+ return "BlockingOption[ "
+ + "DisableTime=" + mDisableTime
+ + ", BSSIDOnly=" + mBSSIDOnly;
+ }
+}
diff --git a/framework/java/android/net/wifi/IWifiManager.aidl b/framework/java/android/net/wifi/IWifiManager.aidl
index e5f89d6a15..18576c894e 100644
--- a/framework/java/android/net/wifi/IWifiManager.aidl
+++ b/framework/java/android/net/wifi/IWifiManager.aidl
@@ -20,6 +20,7 @@ import android.net.DhcpInfo;
import android.net.DhcpOption;
import android.net.Network;
import android.net.TetheringManager.TetheringRequest;
+import android.net.wifi.BlockingOption;
import android.net.wifi.CoexUnsafeChannel;
import android.net.wifi.IActionListener;
import android.net.wifi.IBooleanListener;
@@ -550,6 +551,8 @@ interface IWifiManager {
void getAutojoinDisallowedSecurityTypes(in IIntegerListener listener, in Bundle extras);
+ void disallowCurrentSuggestedNetwork(in BlockingOption option, String packageName);
+
void storeCapturedData(int triggerType, boolean isFullCapture, long triggerStartTimeMillis,
long triggerStopTimeMillis, in IIntegerListener listener);
}
diff --git a/framework/java/android/net/wifi/WifiManager.java b/framework/java/android/net/wifi/WifiManager.java
index 7f4030c906..ce7a3f0807 100644
--- a/framework/java/android/net/wifi/WifiManager.java
+++ b/framework/java/android/net/wifi/WifiManager.java
@@ -13220,4 +13220,25 @@ public class WifiManager {
}
return features;
}
+
+ /**
+ * When the device is connected to a network suggested by calling app
+ * {@link #addNetworkSuggestions(List)}, this API provide a way to avoid the current connection
+ * without {@link #removeNetworkSuggestions(List)}. The disallowed network will be disconnected
+ * or roam to other networks.
+ * App can only use this API to control the current connected network
+ * which was suggested by this app.
+ *
+ * @param blockingOption Option to change for the network blocking {@link BlockingOption}
+ */
+ @FlaggedApi(Flags.FLAG_BSSID_BLOCKLIST_FOR_SUGGESTION)
+ @RequiresPermission(CHANGE_WIFI_STATE)
+ public void disallowCurrentSuggestedNetwork(@NonNull BlockingOption blockingOption) {
+ Objects.requireNonNull(blockingOption, "blockingOption cannot be null");
+ try {
+ mService.disallowCurrentSuggestedNetwork(blockingOption, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/framework/tests/src/android/net/wifi/BlockingOptionTest.java b/framework/tests/src/android/net/wifi/BlockingOptionTest.java
new file mode 100644
index 0000000000..99f0e54f51
--- /dev/null
+++ b/framework/tests/src/android/net/wifi/BlockingOptionTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@SmallTest
+public class BlockingOptionTest {
+
+ @Test
+ public void testBuilderWithValidInput() {
+ BlockingOption option = new BlockingOption.Builder(100)
+ .setBlockingBssidOnly(true)
+ .build();
+ assertEquals(100, option.getBlockingTimeSeconds());
+ assertTrue(option.isBlockingBssidOnly());
+ }
+
+ @Test
+ public void testBuilderWithInValidInput() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ new BlockingOption.Builder(0)
+ .setBlockingBssidOnly(true)
+ .build();
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ new BlockingOption.Builder(1000000)
+ .setBlockingBssidOnly(true)
+ .build();
+ });
+ }
+
+ @Test
+ public void testParcel() {
+ BlockingOption option = new BlockingOption.Builder(100)
+ .setBlockingBssidOnly(true)
+ .build();
+ Parcel parcelW = Parcel.obtain();
+ option.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ BlockingOption parcelOption = BlockingOption.CREATOR.createFromParcel(parcelR);
+ assertEquals(option, parcelOption);
+ }
+}
diff --git a/framework/tests/src/android/net/wifi/WifiManagerTest.java b/framework/tests/src/android/net/wifi/WifiManagerTest.java
index b752f9f6e4..a029be2267 100644
--- a/framework/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/framework/tests/src/android/net/wifi/WifiManagerTest.java
@@ -4560,4 +4560,13 @@ public class WifiManagerTest {
public void testRemoveWifiStateChangedListenerWithNullListener() throws Exception {
mWifiManager.removeWifiStateChangedListener(null);
}
+
+ @Test
+ public void testDisallowCurrentSuggestedNetwork() throws RemoteException {
+ assertThrows(NullPointerException.class,
+ () -> mWifiManager.disallowCurrentSuggestedNetwork(null));
+ BlockingOption option = new BlockingOption.Builder(100).build();
+ mWifiManager.disallowCurrentSuggestedNetwork(option);
+ verify(mWifiService).disallowCurrentSuggestedNetwork(eq(option), eq(TEST_PACKAGE_NAME));
+ }
}
diff --git a/service/java/com/android/server/wifi/ClientMode.java b/service/java/com/android/server/wifi/ClientMode.java
index 7d3308469c..d5c7c82e8a 100644
--- a/service/java/com/android/server/wifi/ClientMode.java
+++ b/service/java/com/android/server/wifi/ClientMode.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.net.DhcpResultsParcelable;
import android.net.MacAddress;
import android.net.Network;
+import android.net.wifi.BlockingOption;
import android.net.wifi.IWifiConnectedNetworkScorer;
import android.net.wifi.WifiAnnotations;
import android.net.wifi.WifiConfiguration;
@@ -370,4 +371,9 @@ public interface ClientMode {
* Notify changes in PowerManager#isDeviceIdleMode
*/
void onIdleModeChanged(boolean isIdle);
+
+ /**
+ * Block current connect network and add to blocklist
+ */
+ void blockNetwork(BlockingOption option);
}
diff --git a/service/java/com/android/server/wifi/ClientModeDefaults.java b/service/java/com/android/server/wifi/ClientModeDefaults.java
index f526f2dc6a..6a9d1ae409 100644
--- a/service/java/com/android/server/wifi/ClientModeDefaults.java
+++ b/service/java/com/android/server/wifi/ClientModeDefaults.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.net.DhcpResultsParcelable;
import android.net.MacAddress;
import android.net.Network;
+import android.net.wifi.BlockingOption;
import android.net.wifi.IWifiConnectedNetworkScorer;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
@@ -284,4 +285,7 @@ public interface ClientModeDefaults extends ClientMode {
@Override
default void onIdleModeChanged(boolean isIdle) { }
+
+ @Override
+ default void blockNetwork(BlockingOption option) { }
}
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 4bc7c04c47..ba671d0218 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -33,6 +33,8 @@ import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY;
import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SCAN_ONLY;
import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
+import static com.android.server.wifi.WifiBlocklistMonitor.REASON_APP_DISALLOW;
+import static com.android.server.wifi.WifiConfigManager.LINK_CONFIGURATION_BSSID_MATCH_LENGTH;
import static com.android.server.wifi.WifiSettingsConfigStore.SECONDARY_WIFI_STA_FACTORY_MAC_ADDRESS;
import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STA_FACTORY_MAC_ADDRESS;
import static com.android.server.wifi.proto.WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__ROLE__ROLE_CLIENT_LOCAL_ONLY;
@@ -85,6 +87,7 @@ import android.net.shared.ProvisioningConfiguration;
import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
import android.net.vcn.VcnManager;
import android.net.vcn.VcnNetworkPolicyResult;
+import android.net.wifi.BlockingOption;
import android.net.wifi.IWifiConnectedNetworkScorer;
import android.net.wifi.MloLink;
import android.net.wifi.ScanResult;
@@ -8897,4 +8900,38 @@ public class ClientModeImpl extends StateMachine implements ClientMode {
mWifiInjector.getActiveModeWarden().updateCurrentConnectionInfo();
}
}
+
+ @Override
+ public void blockNetwork(BlockingOption option) {
+ if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
+ Log.e(TAG, "Calling blockNetwork when disconnected");
+ return;
+ }
+ WifiConfiguration configuration = mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
+ if (configuration == null) {
+ Log.e(TAG, "No available config for networkId: " + mLastNetworkId);
+ return;
+ }
+ if (mLastBssid == null) {
+ Log.e(TAG, "No available BSSID for networkId: " + mLastNetworkId);
+ return;
+ }
+ if (option.isBlockingBssidOnly()) {
+ mWifiBlocklistMonitor.blockBssidForDurationMs(mLastBssid,
+ mWifiConfigManager.getConfiguredNetwork(mLastNetworkId),
+ option.getBlockingTimeSeconds() * 1000L, REASON_APP_DISALLOW, 0);
+ } else {
+ ScanDetailCache scanDetailCache = mWifiConfigManager
+ .getScanDetailCacheForNetwork(mLastNetworkId);
+ for (String bssid : scanDetailCache.keySet()) {
+ if (bssid.regionMatches(true, 0, mLastBssid, 0,
+ LINK_CONFIGURATION_BSSID_MATCH_LENGTH)) {
+ mWifiBlocklistMonitor.blockBssidForDurationMs(bssid,
+ mWifiConfigManager.getConfiguredNetwork(mLastNetworkId),
+ option.getBlockingTimeSeconds() * 1000L, REASON_APP_DISALLOW, 0);
+ }
+ }
+ }
+ mWifiBlocklistMonitor.updateAndGetBssidBlocklistForSsids(Set.of(configuration.SSID));
+ }
}
diff --git a/service/java/com/android/server/wifi/ConcreteClientModeManager.java b/service/java/com/android/server/wifi/ConcreteClientModeManager.java
index a7c67031f1..36a43a5526 100644
--- a/service/java/com/android/server/wifi/ConcreteClientModeManager.java
+++ b/service/java/com/android/server/wifi/ConcreteClientModeManager.java
@@ -30,6 +30,7 @@ import android.net.MacAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.wifi.BlockingOption;
import android.net.wifi.IWifiConnectedNetworkScorer;
import android.net.wifi.WifiAnnotations;
import android.net.wifi.WifiConfiguration;
@@ -1725,4 +1726,9 @@ public class ConcreteClientModeManager implements ClientModeManager {
public void onIdleModeChanged(boolean isIdle) {
getClientMode().onIdleModeChanged(isIdle);
}
+
+ @Override
+ public void blockNetwork(BlockingOption option) {
+ getClientMode().blockNetwork(option);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiBlocklistMonitor.java b/service/java/com/android/server/wifi/WifiBlocklistMonitor.java
index 179f7f32c0..4e3a0ce3c8 100644
--- a/service/java/com/android/server/wifi/WifiBlocklistMonitor.java
+++ b/service/java/com/android/server/wifi/WifiBlocklistMonitor.java
@@ -89,8 +89,9 @@ public class WifiBlocklistMonitor {
public static final int REASON_NONLOCAL_DISCONNECT_CONNECTING = 12;
// Connection attempt aborted by the watchdog because the AP didn't respond.
public static final int REASON_FAILURE_NO_RESPONSE = 13;
+ public static final int REASON_APP_DISALLOW = 14;
// Constant being used to keep track of how many failure reasons there are.
- public static final int NUMBER_REASON_CODES = 14;
+ public static final int NUMBER_REASON_CODES = 15;
public static final int INVALID_REASON = -1;
@IntDef(prefix = { "REASON_" }, value = {
@@ -107,7 +108,8 @@ public class WifiBlocklistMonitor {
REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT,
REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE,
REASON_NONLOCAL_DISCONNECT_CONNECTING,
- REASON_FAILURE_NO_RESPONSE
+ REASON_FAILURE_NO_RESPONSE,
+ REASON_APP_DISALLOW
})
@Retention(RetentionPolicy.SOURCE)
public @interface FailureReason {}
@@ -186,6 +188,8 @@ public class WifiBlocklistMonitor {
"REASON_NONLOCAL_DISCONNECT_CONNECTING", true, false));
result.put(REASON_FAILURE_NO_RESPONSE, new BssidDisableReason(
"REASON_FAILURE_NO_RESPONSE", true, true));
+ result.put(REASON_APP_DISALLOW, new BssidDisableReason(
+ "REASON_APP_DISALLOW", false, false));
return result;
}
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index b08fbc27cd..b476fe0294 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -229,7 +229,6 @@ public class WifiConfigManager {
* Link networks only if the bssid in scan results for the networks match in the first
* 16 ASCII chars in the bssid string. For example = "af:de:56;34:15:7"
*/
- @VisibleForTesting
public static final int LINK_CONFIGURATION_BSSID_MATCH_LENGTH = 16;
/**
* Log tag for this class.
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 19a6c4a6c4..7b3c7c75e6 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -103,6 +103,7 @@ import android.net.Uri;
import android.net.ip.IpClientUtil;
import android.net.thread.ThreadNetworkController;
import android.net.thread.ThreadNetworkManager;
+import android.net.wifi.BlockingOption;
import android.net.wifi.CoexUnsafeChannel;
import android.net.wifi.IActionListener;
import android.net.wifi.IBooleanListener;
@@ -9137,4 +9138,29 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}, TAG + "#getAutojoinDisallowedSecurityTypes");
}
+
+ @Override
+ public void disallowCurrentSuggestedNetwork(@NonNull BlockingOption option,
+ @NonNull String packageName) {
+ Objects.requireNonNull(option, "blockingOption cannot be null");
+ int callingUid = Binder.getCallingUid();
+ mWifiPermissionsUtil.checkPackage(callingUid, packageName);
+ if (enforceChangePermission(packageName) != MODE_ALLOWED) {
+ throw new SecurityException("Caller does not hold CHANGE_WIFI_STATE permission");
+ }
+ if (mVerboseLoggingEnabled) {
+ mLog.info("disallowCurrentSuggestedNetwork: Uid=% Package Name=%").c(
+ callingUid).c(option.toString()).flush();
+ }
+ if (mActiveModeWarden.getWifiState() != WIFI_STATE_ENABLED) {
+ return;
+ }
+ WifiInfo info = mActiveModeWarden.getConnectionInfo();
+ if (!packageName.equals(info.getRequestingPackageName())) {
+ return;
+ }
+ mWifiThreadRunner.post(
+ () -> mActiveModeWarden.getPrimaryClientModeManager().blockNetwork(option),
+ "disallowCurrentSuggestedNetwork");
+ }
}
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 0b98979e64..8b705f0991 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -44,6 +44,7 @@ import static com.android.server.wifi.ClientModeImpl.CMD_PRE_DHCP_ACTION;
import static com.android.server.wifi.ClientModeImpl.CMD_PRE_DHCP_ACTION_COMPLETE;
import static com.android.server.wifi.ClientModeImpl.CMD_UNWANTED_NETWORK;
import static com.android.server.wifi.ClientModeImpl.WIFI_WORK_SOURCE;
+import static com.android.server.wifi.WifiBlocklistMonitor.REASON_APP_DISALLOW;
import static com.android.server.wifi.WifiSettingsConfigStore.SECONDARY_WIFI_STA_FACTORY_MAC_ADDRESS;
import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STA_FACTORY_MAC_ADDRESS;
import static com.android.server.wifi.TestUtil.createCapabilityBitset;
@@ -124,6 +125,7 @@ import android.net.networkstack.aidl.ip.ReachabilityLossInfoParcelable;
import android.net.networkstack.aidl.ip.ReachabilityLossReason;
import android.net.vcn.VcnManager;
import android.net.vcn.VcnNetworkPolicyResult;
+import android.net.wifi.BlockingOption;
import android.net.wifi.IActionListener;
import android.net.wifi.MloLink;
import android.net.wifi.ScanResult;
@@ -11278,4 +11280,15 @@ public class ClientModeImplTest extends WifiBaseTest {
verify(mWifiGlobals, never()).enableWpa3SaeH2eSupport();
}
}
+
+ @Test
+ public void testBlockNetwork() throws Exception {
+ connect();
+ BlockingOption option = new BlockingOption.Builder(100)
+ .setBlockingBssidOnly(true).build();
+ mCmi.blockNetwork(option);
+ verify(mWifiBlocklistMonitor).blockBssidForDurationMs(eq(TEST_BSSID_STR), any(),
+ eq(100 * 1000L), eq(REASON_APP_DISALLOW), eq(0));
+ verify(mWifiBlocklistMonitor).updateAndGetBssidBlocklistForSsids(any());
+ }
}
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 2c240530c0..522967a856 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -149,6 +149,7 @@ import android.net.Network;
import android.net.NetworkStack;
import android.net.TetheringManager;
import android.net.Uri;
+import android.net.wifi.BlockingOption;
import android.net.wifi.CoexUnsafeChannel;
import android.net.wifi.IActionListener;
import android.net.wifi.IBooleanListener;
@@ -13121,6 +13122,18 @@ public class WifiServiceImplTest extends WifiBaseTest {
customConfig, mExtras, false);
}
+ @Test
+ public void testDisallowCurrentSuggestedNetwork() {
+ BlockingOption blockingOption = new BlockingOption.Builder(100).build();
+ WifiInfo info = new WifiInfo();
+ info.setRequestingPackageName(TEST_PACKAGE_NAME);
+ when(mActiveModeWarden.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+ when(mActiveModeWarden.getConnectionInfo()).thenReturn(info);
+ mWifiServiceImpl.disallowCurrentSuggestedNetwork(blockingOption, TEST_PACKAGE_NAME);
+ mLooper.dispatchAll();
+ verify(mClientModeManager).blockNetwork(eq(blockingOption));
+ }
+
/**
* Test add and remove listener will go to ActiveModeWarden.
*/
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 809fa1a915..681db5b3d2 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
@@ -88,6 +88,8 @@ import android.os.test.TestLooper;
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.modules.utils.build.SdkLevel;
import com.android.server.wifi.Clock;
import com.android.server.wifi.DeviceConfigFacade;
@@ -117,6 +119,7 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import org.mockito.quality.Strictness;
import java.nio.ByteOrder;
import java.util.ArrayList;
@@ -172,6 +175,7 @@ public class WifiAwareDataPathStateManagerTest extends WifiBaseTest {
public ErrorCollector collector = new ErrorCollector();
private MockResources mResources;
private Bundle mExtras = new Bundle();
+ private StaticMockitoSession mSession;
/**
* Initialize mocks.
@@ -179,6 +183,12 @@ public class WifiAwareDataPathStateManagerTest extends WifiBaseTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mSession = ExtendedMockito.mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .mockStatic(WifiInjector.class)
+ .startMocking();
+
+ when(WifiInjector.getInstance()).thenReturn(mWifiInjector);
mAlarmManager = new TestAlarmManager();
when(mMockContext.getSystemService(Context.ALARM_SERVICE))
@@ -244,6 +254,7 @@ public class WifiAwareDataPathStateManagerTest extends WifiBaseTest {
@After
public void tearDown() throws Exception {
mMockNative.validateUniqueTransactionIds();
+ mSession.finishMocking();
}
/**