From eb95d64df8438897ed335d6c76d3fd6902a0e1a2 Mon Sep 17 00:00:00 2001 From: Kai Shi Date: Tue, 16 Jul 2019 14:19:13 -0700 Subject: WiFi: add ADB shell commands to force soft AP channel frequency and country code Bug: 136501595 Test: Manual test with Flame. Change-Id: I6d38a40db0261d0d1fa445b0bf307fc8b8d45149 --- .../java/com/android/server/wifi/HostapdHal.java | 29 ++++++- .../com/android/server/wifi/WifiCountryCode.java | 35 ++++++++ .../java/com/android/server/wifi/WifiInjector.java | 4 + .../com/android/server/wifi/WifiShellCommand.java | 92 ++++++++++++++++++++++ .../com/android/server/wifi/util/ApConfigUtil.java | 2 +- 5 files changed, 160 insertions(+), 2 deletions(-) (limited to 'service') diff --git a/service/java/com/android/server/wifi/HostapdHal.java b/service/java/com/android/server/wifi/HostapdHal.java index ee96fb269..5ac173447 100644 --- a/service/java/com/android/server/wifi/HostapdHal.java +++ b/service/java/com/android/server/wifi/HostapdHal.java @@ -33,6 +33,7 @@ import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wifi.WifiNative.HostapdDeathEventHandler; +import com.android.server.wifi.util.ApConfigUtil; import com.android.server.wifi.util.NativeUtil; import java.util.ArrayList; @@ -64,6 +65,8 @@ public class HostapdHal { private final boolean mEnableIeee80211AC; private final List mAcsChannelRanges; + private boolean mForceApChannel = false; + private int mForcedApChannel; // Hostapd HAL interface objects private IServiceManager mIServiceManager = null; @@ -300,6 +303,22 @@ public class HostapdHal { return true; } + /** + * Enable force-soft-AP-channel mode which takes effect when soft AP starts next time + * @param forcedApChannel The forced IEEE channel number + */ + void enableForceSoftApChannel(int forcedApChannel) { + mForceApChannel = true; + mForcedApChannel = forcedApChannel; + } + + /** + * Disable force-soft-AP-channel mode which take effect when soft AP starts next time + */ + void disableForceSoftApChannel() { + mForceApChannel = false; + } + /** * Add and start a new access point. * @@ -322,7 +341,15 @@ public class HostapdHal { Log.e(TAG, "Unrecognized apBand " + config.apBand); return false; } - if (mEnableAcs) { + if (mForceApChannel) { + ifaceParams.channelParams.enableAcs = false; + ifaceParams.channelParams.channel = mForcedApChannel; + if (mForcedApChannel <= ApConfigUtil.HIGHEST_2G_AP_CHANNEL) { + ifaceParams.channelParams.band = IHostapd.Band.BAND_2_4_GHZ; + } else { + ifaceParams.channelParams.band = IHostapd.Band.BAND_5_GHZ; + } + } else if (mEnableAcs) { ifaceParams.channelParams.enableAcs = true; ifaceParams.channelParams.acsShouldExcludeDfs = true; } else { diff --git a/service/java/com/android/server/wifi/WifiCountryCode.java b/service/java/com/android/server/wifi/WifiCountryCode.java index a6695084b..499c159fa 100644 --- a/service/java/com/android/server/wifi/WifiCountryCode.java +++ b/service/java/com/android/server/wifi/WifiCountryCode.java @@ -48,6 +48,7 @@ public class WifiCountryCode { private String mTelephonyCountryTimestamp = null; private String mDriverCountryTimestamp = null; private String mReadyTimestamp = null; + private boolean mForceCountryCode = false; public WifiCountryCode( WifiNative wifiNative, @@ -110,6 +111,36 @@ public class WifiCountryCode { } } + /** + * Enable force-country-code mode + * @param countryCode The forced two-letter country code + */ + synchronized void enableForceCountryCode(String countryCode) { + if (TextUtils.isEmpty(countryCode)) { + Log.d(TAG, "Fail to force country code because the received country code is empty"); + return; + } + mForceCountryCode = true; + mTelephonyCountryCode = countryCode.toUpperCase(Locale.US); + // If wpa_supplicant is ready we set the country code now, otherwise it will be + // set once wpa_supplicant is ready. + if (mReady) { + updateCountryCode(); + } else { + Log.d(TAG, "skip update supplicant not ready yet"); + } + } + + /** + * Disable force-country-code mode + */ + synchronized void disableForceCountryCode() { + mForceCountryCode = false; + // Set mTelephonyCountryCode to null so that default country code is used until + // next call of setCountryCode(). + mTelephonyCountryCode = null; + } + /** * Handle country code change request. * @param countryCode The country code intended to set. @@ -118,6 +149,10 @@ public class WifiCountryCode { * @return Returns true if the country code passed in is acceptable. */ public synchronized boolean setCountryCode(String countryCode) { + if (mForceCountryCode) { + Log.d(TAG, "Country code can't be set because it is the force-country-code mode"); + return false; + } Log.d(TAG, "Receive set country code request: " + countryCode); mTelephonyCountryTimestamp = FORMATTER.format(new Date(System.currentTimeMillis())); diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index ade295c63..8095bfac6 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -748,4 +748,8 @@ public class WifiInjector { public IpMemoryStore getIpMemoryStore() { return mIpMemoryStore; } + + public HostapdHal getHostapdHal() { + return mHostapdHal; + } } diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java index 256541670..b2289a832 100644 --- a/service/java/com/android/server/wifi/WifiShellCommand.java +++ b/service/java/com/android/server/wifi/WifiShellCommand.java @@ -18,10 +18,14 @@ package com.android.server.wifi; import android.app.AppGlobals; import android.content.pm.IPackageManager; +import android.net.wifi.WifiScanner; import android.os.Binder; import android.os.ShellCommand; +import com.android.server.wifi.util.ApConfigUtil; + import java.io.PrintWriter; +import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; @@ -47,6 +51,9 @@ public class WifiShellCommand extends ShellCommand { private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; private final WifiConfigManager mWifiConfigManager; private final IPackageManager mPM; + private final WifiNative mWifiNative; + private final HostapdHal mHostapdHal; + private final WifiCountryCode mWifiCountryCode; WifiShellCommand(WifiInjector wifiInjector) { mClientModeImpl = wifiInjector.getClientModeImpl(); @@ -54,6 +61,9 @@ public class WifiShellCommand extends ShellCommand { mWifiNetworkSuggestionsManager = wifiInjector.getWifiNetworkSuggestionsManager(); mWifiConfigManager = wifiInjector.getWifiConfigManager(); mPM = AppGlobals.getPackageManager(); + mHostapdHal = wifiInjector.getHostapdHal(); + mWifiNative = wifiInjector.getWifiNative(); + mWifiCountryCode = wifiInjector.getWifiCountryCode(); } @Override @@ -179,6 +189,62 @@ public class WifiShellCommand extends ShellCommand { case "send-link-probe": { return sendLinkProbe(pw); } + case "force-softap-channel": { + String nextArg = getNextArgRequired(); + if ("enabled".equals(nextArg)) { + int apChannelMHz; + try { + apChannelMHz = Integer.parseInt(getNextArgRequired()); + } catch (NumberFormatException e) { + pw.println("Invalid argument to 'force-softap-channel enabled' " + + "- must be a positive integer"); + return -1; + } + int apChannel = ApConfigUtil.convertFrequencyToChannel(apChannelMHz); + if (apChannel == -1 || !isApChannelMHzValid(apChannelMHz)) { + pw.println("Invalid argument to 'force-softap-channel enabled' " + + "- must be a valid WLAN channel"); + return -1; + } + mHostapdHal.enableForceSoftApChannel(apChannel); + return 0; + } else if ("disabled".equals(nextArg)) { + mHostapdHal.disableForceSoftApChannel(); + return 0; + } else { + pw.println( + "Invalid argument to 'force-softap-channel' - must be 'enabled'" + + " or 'disabled'"); + return -1; + } + } + case "force-country-code": { + String nextArg = getNextArgRequired(); + if ("enabled".equals(nextArg)) { + String countryCode = getNextArgRequired(); + if (!(countryCode.length() == 2 + && countryCode.chars().allMatch(Character::isLetter))) { + pw.println("Invalid argument to 'force-country-code enabled' " + + "- must be a two-letter string"); + return -1; + } + mWifiCountryCode.enableForceCountryCode(countryCode); + return 0; + } else if ("disabled".equals(nextArg)) { + mWifiCountryCode.disableForceCountryCode(); + return 0; + } else { + pw.println( + "Invalid argument to 'force-country-code' - must be 'enabled'" + + " or 'disabled'"); + return -1; + } + } + case "get-country-code": { + pw.println("Wifi Country Code = " + + mWifiCountryCode.getCountryCode()); + return 0; + } default: return handleDefaultCommands(cmd); } @@ -214,6 +280,25 @@ public class WifiShellCommand extends ShellCommand { return 0; } + private boolean isApChannelMHzValid(int apChannelMHz) { + int[] allowed2gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ); + int[] allowed5gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ); + int[] allowed5gDfsFreq = + mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY); + if (allowed2gFreq == null) { + allowed2gFreq = new int[0]; + } + if (allowed5gFreq == null) { + allowed5gFreq = new int[0]; + } + if (allowed5gDfsFreq == null) { + allowed5gDfsFreq = new int[0]; + } + return (Arrays.binarySearch(allowed2gFreq, apChannelMHz) >= 0 + || Arrays.binarySearch(allowed5gFreq, apChannelMHz) >= 0 + || Arrays.binarySearch(allowed5gDfsFreq, apChannelMHz) >= 0); + } + private void checkRootPermission() { final int uid = Binder.getCallingUid(); if (uid == 0) { @@ -252,6 +337,13 @@ public class WifiShellCommand extends ShellCommand { pw.println(" Clears the deleted ephemeral networks list."); pw.println(" send-link-probe"); pw.println(" Manually triggers a link probe."); + pw.println(" force-softap-channel enabled | disabled"); + pw.println(" Sets whether soft AP channel is forced to MHz"); + pw.println(" or left for normal operation."); + pw.println(" force-country-code enabled | disabled "); + pw.println(" Sets country code to or left for normal value"); + pw.println(" get-country-code"); + pw.println(" Gets country code as a two-letter string"); pw.println(); } } diff --git a/service/java/com/android/server/wifi/util/ApConfigUtil.java b/service/java/com/android/server/wifi/util/ApConfigUtil.java index dfda45b7d..c3a4c0c95 100644 --- a/service/java/com/android/server/wifi/util/ApConfigUtil.java +++ b/service/java/com/android/server/wifi/util/ApConfigUtil.java @@ -33,7 +33,7 @@ public class ApConfigUtil { public static final int DEFAULT_AP_BAND = WifiConfiguration.AP_BAND_2GHZ; public static final int DEFAULT_AP_CHANNEL = 6; - + public static final int HIGHEST_2G_AP_CHANNEL = 14; /* Return code for updateConfiguration. */ public static final int SUCCESS = 0; public static final int ERROR_NO_CHANNEL = 1; -- cgit v1.2.3