diff options
-rw-r--r-- | framework/aidl-export/android/net/wifi/BlockingOption.aidl | 19 | ||||
-rw-r--r-- | framework/api/current.txt | 15 | ||||
-rw-r--r-- | framework/java/android/net/wifi/BlockingOption.java | 152 | ||||
-rw-r--r-- | framework/java/android/net/wifi/IWifiManager.aidl | 3 | ||||
-rw-r--r-- | framework/java/android/net/wifi/WifiManager.java | 21 | ||||
-rw-r--r-- | framework/tests/src/android/net/wifi/BlockingOptionTest.java | 70 | ||||
-rw-r--r-- | framework/tests/src/android/net/wifi/WifiManagerTest.java | 9 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiServiceImpl.java | 11 |
8 files changed, 300 insertions, 0 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 a4982793a5..48588b5333 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..f4a92a7d32 --- /dev/null +++ b/framework/java/android/net/wifi/BlockingOption.java @@ -0,0 +1,152 @@ +/* + * 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); + } +} 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/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index 19a6c4a6c4..cc995f3403 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,14 @@ public class WifiServiceImpl extends IWifiManager.Stub { } }, TAG + "#getAutojoinDisallowedSecurityTypes"); } + + @Override + public void disallowCurrentSuggestedNetwork(BlockingOption option, String packageName) { + int callingUid = Binder.getCallingUid(); + mWifiPermissionsUtil.checkPackage(callingUid, packageName); + if (enforceChangePermission(packageName) != MODE_ALLOWED) { + throw new SecurityException("Caller does not hold CHANGE_WIFI_STATE permission"); + } + // TODO: function implementation + } } |