diff options
26 files changed, 969 insertions, 368 deletions
diff --git a/service/java/com/android/server/wifi/BaseWifiService.java b/service/java/com/android/server/wifi/BaseWifiService.java index 08a7a9e7f..16e8eb5ee 100644 --- a/service/java/com/android/server/wifi/BaseWifiService.java +++ b/service/java/com/android/server/wifi/BaseWifiService.java @@ -279,6 +279,11 @@ public class BaseWifiService extends IWifiManager.Stub { } @Override + public void setScanAlwaysAvailable(boolean isAvailable) { + throw new UnsupportedOperationException(); + } + + @Override public boolean isScanAlwaysAvailable() { throw new UnsupportedOperationException(); } diff --git a/service/java/com/android/server/wifi/ScanRequestProxy.java b/service/java/com/android/server/wifi/ScanRequestProxy.java index 642cca101..4e071815f 100644 --- a/service/java/com/android/server/wifi/ScanRequestProxy.java +++ b/service/java/com/android/server/wifi/ScanRequestProxy.java @@ -16,6 +16,8 @@ package com.android.server.wifi; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_SCAN_THROTTLE_ENABLED; + import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AppOpsManager; @@ -31,7 +33,6 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; import android.os.WorkSource; -import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -88,7 +89,7 @@ public class ScanRequestProxy { private final WifiPermissionsUtil mWifiPermissionsUtil; private final WifiMetrics mWifiMetrics; private final Clock mClock; - private final FrameworkFacade mFrameworkFacade; + private final WifiSettingsConfigStore mSettingsConfigStore; private WifiScanner mWifiScanner; // Verbose logging flag. @@ -193,7 +194,7 @@ public class ScanRequestProxy { ScanRequestProxy(Context context, AppOpsManager appOpsManager, ActivityManager activityManager, WifiInjector wifiInjector, WifiConfigManager configManager, WifiPermissionsUtil wifiPermissionUtil, WifiMetrics wifiMetrics, Clock clock, - FrameworkFacade frameworkFacade, Handler handler) { + Handler handler, WifiSettingsConfigStore settingsConfigStore) { mContext = context; mHandler = handler; mAppOps = appOpsManager; @@ -203,7 +204,7 @@ public class ScanRequestProxy { mWifiPermissionsUtil = wifiPermissionUtil; mWifiMetrics = wifiMetrics; mClock = clock; - mFrameworkFacade = frameworkFacade; + mSettingsConfigStore = settingsConfigStore; mRegisteredScanResultsCallbacks = new RemoteCallbackList<>(); } @@ -222,8 +223,7 @@ public class ScanRequestProxy { if (mWifiScanner == null) { mWifiScanner = mWifiInjector.getWifiScanner(); // Start listening for throttle settings change after we retrieve scanner instance. - mThrottleEnabled = mFrameworkFacade.getIntegerSetting( - mContext, Settings.Global.WIFI_SCAN_THROTTLE_ENABLED, 1) == 1; + mThrottleEnabled = mSettingsConfigStore.getBoolean(WIFI_SCAN_THROTTLE_ENABLED, true); if (mVerboseLoggingEnabled) { Log.v(TAG, "Scan throttle enabled " + mThrottleEnabled); } @@ -524,8 +524,7 @@ public class ScanRequestProxy { */ public void setScanThrottleEnabled(boolean enable) { mThrottleEnabled = enable; - mFrameworkFacade.setIntegerSetting( - mContext, Settings.Global.WIFI_SCAN_THROTTLE_ENABLED, enable ? 1 : 0); + mSettingsConfigStore.putBoolean(WIFI_SCAN_THROTTLE_ENABLED, enable); Log.i(TAG, "Scan throttle enabled " + mThrottleEnabled); } diff --git a/service/java/com/android/server/wifi/ScoringParams.java b/service/java/com/android/server/wifi/ScoringParams.java index 216848771..0a29b57c7 100644 --- a/service/java/com/android/server/wifi/ScoringParams.java +++ b/service/java/com/android/server/wifi/ScoringParams.java @@ -18,10 +18,7 @@ package com.android.server.wifi; import android.annotation.NonNull; import android.content.Context; -import android.database.ContentObserver; import android.net.wifi.WifiInfo; -import android.os.Handler; -import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -238,11 +235,6 @@ public class ScoringParams { mContext = context; } - public ScoringParams(Context context, FrameworkFacade facade, Handler handler) { - mContext = context; - setupContentObserver(context, facade, handler); - } - private void loadResources(Context context) { if (mVal != null) return; mVal = new Values(); @@ -297,29 +289,6 @@ public class ScoringParams { } } - private void setupContentObserver(Context context, FrameworkFacade facade, Handler handler) { - final ScoringParams self = this; - String defaults = self.toString(); - ContentObserver observer = new ContentObserver(handler) { - @Override - public void onChange(boolean selfChange) { - String params = facade.getStringSetting( - context, Settings.Global.WIFI_SCORE_PARAMS); - self.update(defaults); - if (!self.update(params)) { - Log.e(TAG, "Error in " + Settings.Global.WIFI_SCORE_PARAMS + ": " - + sanitize(params)); - } - Log.i(TAG, self.toString()); - } - }; - facade.registerContentObserver(context, - Settings.Global.getUriFor(Settings.Global.WIFI_SCORE_PARAMS), - true, - observer); - observer.onChange(false); - } - private static final String COMMA_KEY_VAL_STAR = "^(,[A-Za-z_][A-Za-z0-9_]*=[0-9.:+-]+)*$"; /** @@ -328,6 +297,7 @@ public class ScoringParams { * @param kvList is a comma-separated key=value list. * @return true for success */ + @VisibleForTesting public boolean update(String kvList) { if (kvList == null || "".equals(kvList)) { return true; diff --git a/service/java/com/android/server/wifi/SoftApBackupRestore.java b/service/java/com/android/server/wifi/SoftApBackupRestore.java index 292a39e7a..84d9e7564 100644 --- a/service/java/com/android/server/wifi/SoftApBackupRestore.java +++ b/service/java/com/android/server/wifi/SoftApBackupRestore.java @@ -16,9 +16,11 @@ package com.android.server.wifi; +import android.content.Context; import android.net.MacAddress; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiOemMigrationHook; import android.util.BackupUtils; import android.util.Log; @@ -47,11 +49,14 @@ public class SoftApBackupRestore { /** * Current backup data version. */ - private static final int CURRENT_SAP_BACKUP_DATA_VERSION = 5; + private static final int CURRENT_SAP_BACKUP_DATA_VERSION = 6; private static final int ETHER_ADDR_LEN = 6; // Byte array size of MacAddress - public SoftApBackupRestore() { + private final Context mContext; + + public SoftApBackupRestore(Context context) { + mContext = context; } /** @@ -82,6 +87,7 @@ public class SoftApBackupRestore { out.writeBoolean(config.isClientControlByUserEnabled()); writeMacAddressList(out, config.getBlockedClientList()); writeMacAddressList(out, config.getAllowedClientList()); + out.writeBoolean(config.isAutoShutdownEnabled()); } catch (IOException io) { Log.e(TAG, "Invalid configuration received, IOException " + io); return new byte[0]; @@ -147,6 +153,18 @@ public class SoftApBackupRestore { macAddressListFromByteArray(in, numberOfAllowedClient)); configBuilder.setClientList(blockedList, allowedList); } + if (version >= 6) { + configBuilder.setAutoShutdownEnabled(in.readBoolean()); + } else { + // Migrate data out of settings. + WifiOemMigrationHook.SettingsMigrationData migrationData = + WifiOemMigrationHook.loadFromSettings(mContext); + if (migrationData == null) { + Log.e(TAG, "No migration data present"); + } else { + configBuilder.setAutoShutdownEnabled(migrationData.isSoftApTimeoutEnabled()); + } + } } catch (IOException io) { Log.e(TAG, "Invalid backup data received, IOException: " + io); return null; diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java index 705680ee6..4f91f1936 100644 --- a/service/java/com/android/server/wifi/SoftApManager.java +++ b/service/java/com/android/server/wifi/SoftApManager.java @@ -24,7 +24,6 @@ import static com.android.server.wifi.util.ApConfigUtil.SUCCESS; import android.annotation.NonNull; import android.content.Context; import android.content.Intent; -import android.database.ContentObserver; import android.net.MacAddress; import android.net.wifi.ScanResult; import android.net.wifi.SoftApCapability; @@ -39,7 +38,6 @@ import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.os.UserHandle; -import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -196,6 +194,7 @@ public class SoftApManager implements ActiveModeManager { if (softApConfig != null) { mBlockedClientList = new HashSet<>(softApConfig.getBlockedClientList()); mAllowedClientList = new HashSet<>(softApConfig.getAllowedClientList()); + mTimeoutEnabled = softApConfig.isAutoShutdownEnabled(); } } @@ -479,7 +478,6 @@ public class SoftApManager implements ActiveModeManager { public static final int CMD_INTERFACE_STATUS_CHANGED = 3; public static final int CMD_ASSOCIATED_STATIONS_CHANGED = 4; public static final int CMD_NO_ASSOCIATED_STATIONS_TIMEOUT = 5; - public static final int CMD_TIMEOUT_TOGGLE_CHANGED = 6; public static final int CMD_INTERFACE_DESTROYED = 7; public static final int CMD_INTERFACE_DOWN = 8; public static final int CMD_SOFT_AP_CHANNEL_SWITCHED = 9; @@ -583,6 +581,7 @@ public class SoftApManager implements ActiveModeManager { newConfig, mCurrentSoftApCapability); mBlockedClientList = new HashSet<>(newConfig.getBlockedClientList()); mAllowedClientList = new HashSet<>(newConfig.getAllowedClientList()); + mTimeoutEnabled = newConfig.isAutoShutdownEnabled(); break; default: // Ignore all other commands. @@ -595,40 +594,6 @@ public class SoftApManager implements ActiveModeManager { private class StartedState extends State { private WakeupMessage mSoftApTimeoutMessage; - private SoftApTimeoutEnabledSettingObserver mSettingObserver; - - /** - * Observer for timeout settings changes. - */ - private class SoftApTimeoutEnabledSettingObserver extends ContentObserver { - SoftApTimeoutEnabledSettingObserver(Handler handler) { - super(handler); - } - - public void register() { - mFrameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.SOFT_AP_TIMEOUT_ENABLED), - true, this); - mTimeoutEnabled = getValue(); - } - - public void unregister() { - mFrameworkFacade.unregisterContentObserver(mContext, this); - } - - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - mStateMachine.sendMessage(SoftApStateMachine.CMD_TIMEOUT_TOGGLE_CHANGED, - getValue() ? 1 : 0); - } - - private boolean getValue() { - boolean enabled = mFrameworkFacade.getIntegerSetting(mContext, - Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1) == 1; - return enabled; - } - } private void scheduleTimeoutMessage() { if (!mTimeoutEnabled || mConnectedClients.size() != 0) { @@ -804,11 +769,6 @@ public class SoftApManager implements ActiveModeManager { mSoftApTimeoutMessage = new WakeupMessage(mContext, handler, SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG, SoftApStateMachine.CMD_NO_ASSOCIATED_STATIONS_TIMEOUT); - mSettingObserver = new SoftApTimeoutEnabledSettingObserver(handler); - - if (mSettingObserver != null) { - mSettingObserver.register(); - } mSarManager.setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED); @@ -823,9 +783,6 @@ public class SoftApManager implements ActiveModeManager { stopSoftAp(); } - if (mSettingObserver != null) { - mSettingObserver.unregister(); - } Log.d(TAG, "Resetting num stations on stop"); if (mConnectedClients.size() != 0) { mConnectedClients.clear(); @@ -899,14 +856,6 @@ public class SoftApManager implements ActiveModeManager { } setSoftApChannel(message.arg1, message.arg2); break; - case CMD_TIMEOUT_TOGGLE_CHANGED: - boolean isEnabled = (message.arg1 == 1); - if (mTimeoutEnabled == isEnabled) { - break; - } - mTimeoutEnabled = isEnabled; - scheduleTimeoutMessage(); - break; case CMD_INTERFACE_STATUS_CHANGED: boolean isUp = message.arg1 == 1; onUpChanged(isUp); @@ -972,9 +921,11 @@ public class SoftApManager implements ActiveModeManager { Log.d(TAG, "Configuration changed to " + newConfig); boolean needRescheduleTimer = mApConfig.getSoftApConfiguration().getShutdownTimeoutMillis() - != newConfig.getShutdownTimeoutMillis(); + != newConfig.getShutdownTimeoutMillis() + || mTimeoutEnabled != newConfig.isAutoShutdownEnabled(); mBlockedClientList = new HashSet<>(newConfig.getBlockedClientList()); mAllowedClientList = new HashSet<>(newConfig.getAllowedClientList()); + mTimeoutEnabled = newConfig.isAutoShutdownEnabled(); mApConfig = new SoftApModeConfiguration(mApConfig.getTargetMode(), newConfig, mCurrentSoftApCapability); updateClientConnection(); diff --git a/service/java/com/android/server/wifi/SoftApStoreData.java b/service/java/com/android/server/wifi/SoftApStoreData.java index 851fdb2ac..e4f874c23 100644 --- a/service/java/com/android/server/wifi/SoftApStoreData.java +++ b/service/java/com/android/server/wifi/SoftApStoreData.java @@ -17,8 +17,10 @@ package com.android.server.wifi; import android.annotation.Nullable; +import android.content.Context; import android.net.MacAddress; import android.net.wifi.SoftApConfiguration; +import android.net.wifi.WifiOemMigrationHook; import android.text.TextUtils; import android.util.Log; @@ -49,11 +51,13 @@ public class SoftApStoreData implements WifiConfigStore.StoreData { private static final String XML_TAG_AP_BAND = "ApBand"; private static final String XML_TAG_PASSPHRASE = "Passphrase"; private static final String XML_TAG_MAX_NUMBER_OF_CLIENTS = "MaxNumberOfClients"; + private static final String XML_TAG_AUTO_SHUTDOWN_ENABLED = "AutoShutdownEnabled"; private static final String XML_TAG_SHUTDOWN_TIMEOUT_MILLIS = "ShutdownTimeoutMillis"; private static final String XML_TAG_CLIENT_CONTROL_BY_USER = "ClientControlByUser"; private static final String XML_TAG_BLOCKED_CLIENT_LIST = "BlockedClientList"; private static final String XML_TAG_ALLOWED_CLIENT_LIST = "AllowedClientList"; + private final Context mContext; private final DataSource mDataSource; private final WifiOemConfigStoreMigrationDataHolder mWifiOemConfigStoreMigrationDataHolder; @@ -91,8 +95,10 @@ public class SoftApStoreData implements WifiConfigStore.StoreData { * * @param dataSource The DataSource that implements the update and retrieval of the SSID set. */ - SoftApStoreData(DataSource dataSource, + SoftApStoreData(Context context, + DataSource dataSource, WifiOemConfigStoreMigrationDataHolder wifiOemConfigStoreMigrationDataHolder) { + mContext = context; mDataSource = dataSource; mWifiOemConfigStoreMigrationDataHolder = wifiOemConfigStoreMigrationDataHolder; } @@ -117,6 +123,8 @@ public class SoftApStoreData implements WifiConfigStore.StoreData { softApConfig.getMaxNumberOfClients()); XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CONTROL_BY_USER, softApConfig.isClientControlByUserEnabled()); + XmlUtil.writeNextValue(out, XML_TAG_AUTO_SHUTDOWN_ENABLED, + softApConfig.isAutoShutdownEnabled()); XmlUtil.writeNextValue(out, XML_TAG_SHUTDOWN_TIMEOUT_MILLIS, softApConfig.getShutdownTimeoutMillis()); XmlUtil.writeNextSectionStart(out, XML_TAG_BLOCKED_CLIENT_LIST); @@ -160,6 +168,7 @@ public class SoftApStoreData implements WifiConfigStore.StoreData { int apBand = -1; List<MacAddress> blockedList = new ArrayList<>(); List<MacAddress> allowedList = new ArrayList<>(); + boolean autoShutdownEnabledTagPresent = false; try { while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { if (in.getAttributeValue(null, "name") != null) { @@ -196,6 +205,10 @@ public class SoftApStoreData implements WifiConfigStore.StoreData { case XML_TAG_MAX_NUMBER_OF_CLIENTS: softApConfigBuilder.setMaxNumberOfClients((int) value); break; + case XML_TAG_AUTO_SHUTDOWN_ENABLED: + softApConfigBuilder.setAutoShutdownEnabled((boolean) value); + autoShutdownEnabledTagPresent = true; + break; case XML_TAG_SHUTDOWN_TIMEOUT_MILLIS: softApConfigBuilder.setShutdownTimeoutMillis((int) value); break; @@ -247,6 +260,17 @@ public class SoftApStoreData implements WifiConfigStore.StoreData { if (securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) { softApConfigBuilder.setPassphrase(passphrase, securityType); } + if (!autoShutdownEnabledTagPresent) { + // Migrate data out of settings. + WifiOemMigrationHook.SettingsMigrationData migrationData = + WifiOemMigrationHook.loadFromSettings(mContext); + if (migrationData == null) { + Log.e(TAG, "No migration data present"); + } else { + softApConfigBuilder.setAutoShutdownEnabled( + migrationData.isSoftApTimeoutEnabled()); + } + } } catch (IllegalArgumentException e) { Log.e(TAG, "Failed to parse configuration" + e); return; diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index c035ee45b..e6dcb6368 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -158,6 +158,7 @@ public class WifiInjector { private NetdWrapper mNetdWrapper; private final WifiHealthMonitor mWifiHealthMonitor; private final WifiOemConfigStoreMigrationDataHolder mOemConfigStoreMigrationDataHolder; + private final WifiSettingsConfigStore mSettingsConfigStore; public WifiInjector(Context context) { if (context == null) { @@ -186,7 +187,6 @@ public class WifiInjector { mConnectionFailureNotificationBuilder = new ConnectionFailureNotificationBuilder( mContext, getWifiStackPackageName(), mFrameworkFacade); mBatteryStats = context.getSystemService(BatteryStatsManager.class); - mSettingsStore = new WifiSettingsStore(mContext); mWifiPermissionsWrapper = new WifiPermissionsWrapper(mContext); mNetworkScoreManager = mContext.getSystemService(NetworkScoreManager.class); mWifiNetworkScoreCache = new WifiNetworkScoreCache(mContext); @@ -197,7 +197,7 @@ public class WifiInjector { mWifiPermissionsUtil = new WifiPermissionsUtil(mWifiPermissionsWrapper, mContext, mUserManager, this); mWifiBackupRestore = new WifiBackupRestore(mWifiPermissionsUtil); - mSoftApBackupRestore = new SoftApBackupRestore(); + mSoftApBackupRestore = new SoftApBackupRestore(mContext); mWifiStateTracker = new WifiStateTracker(mBatteryStats); mWifiThreadRunner = new WifiThreadRunner(wifiHandler); mWifiP2pServiceHandlerThread = new HandlerThread("WifiP2pService"); @@ -264,6 +264,9 @@ public class WifiInjector { new NetworkListUserStoreData(mContext, mOemConfigStoreMigrationDataHolder), new RandomizedMacStoreData(), mFrameworkFacade, wifiHandler, mDeviceConfigFacade, mWifiScoreCard); + mSettingsConfigStore = new WifiSettingsConfigStore(context, wifiHandler, mWifiConfigManager, + mWifiConfigStore); + mSettingsStore = new WifiSettingsStore(mContext, mSettingsConfigStore); mWifiMetrics.setWifiConfigManager(mWifiConfigManager); mWifiConnectivityHelper = new WifiConnectivityHelper(mWifiNative); @@ -307,7 +310,7 @@ public class WifiInjector { (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE), (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE), this, mWifiConfigManager, - mWifiPermissionsUtil, mWifiMetrics, mClock, mFrameworkFacade, wifiHandler); + mWifiPermissionsUtil, mWifiMetrics, mClock, wifiHandler, mSettingsConfigStore); mSarManager = new SarManager(mContext, makeTelephonyManager(), wifiLooper, mWifiNative); mWifiDiagnostics = new WifiDiagnostics( @@ -672,7 +675,7 @@ public class WifiInjector { */ public SoftApStoreData makeSoftApStoreData( SoftApStoreData.DataSource dataSource) { - return new SoftApStoreData(dataSource, mOemConfigStoreMigrationDataHolder); + return new SoftApStoreData(mContext, dataSource, mOemConfigStoreMigrationDataHolder); } public WifiPermissionsUtil getWifiPermissionsUtil() { @@ -813,4 +816,8 @@ public class WifiInjector { public ThroughputPredictor getThroughputPredictor() { return mThroughputPredictor; } + + public WifiSettingsConfigStore getSettingsConfigStore() { + return mSettingsConfigStore; + } } diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index 9f3532312..08f4cf39a 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -27,6 +27,8 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; + import android.annotation.CheckResult; import android.annotation.NonNull; import android.annotation.Nullable; @@ -41,7 +43,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; -import android.database.ContentObserver; import android.net.DhcpInfo; import android.net.DhcpResultsParcelable; import android.net.InetAddresses; @@ -339,12 +340,14 @@ public class WifiServiceImpl extends BaseWifiService { */ public void checkAndStartWifi() { mWifiThreadRunner.post(() -> { + if (!mWifiConfigManager.loadFromStore()) { + Log.e(TAG, "Failed to load from config store"); + } // Check if wi-fi needs to be enabled boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); Log.i(TAG, "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); - registerForScanModeChange(); mContext.registerReceiver( new BroadcastReceiver() { @Override @@ -407,9 +410,6 @@ public class WifiServiceImpl extends BaseWifiService { } mContext.registerReceiver(mReceiver, intentFilter); mMemoryStoreImpl.start(); - if (!mWifiConfigManager.loadFromStore()) { - Log.e(TAG, "Failed to load from config store"); - } mPasspointManager.initializeProvisioner( mWifiInjector.getPasspointProvisionerHandlerThread().getLooper()); mClientModeImpl.handleBootCompleted(); @@ -1886,6 +1886,17 @@ public class WifiServiceImpl extends BaseWifiService { } /** + * see {@link android.net.wifi.WifiManager#setScanAlwaysAvailable(boolean)} + */ + @Override + public void setScanAlwaysAvailable(boolean isAvailable) { + enforceNetworkSettingsPermission(); + mLog.info("setScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush(); + mSettingsStore.handleWifiScanAlwaysAvailableToggled(isAvailable); + mActiveModeWarden.scanAlwaysModeChanged(); + } + + /** * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()} */ @Override @@ -3021,23 +3032,6 @@ public class WifiServiceImpl extends BaseWifiService { } }; - /** - * Observes settings changes to scan always mode. - */ - private void registerForScanModeChange() { - ContentObserver contentObserver = new ContentObserver(null) { - @Override - public void onChange(boolean selfChange) { - mSettingsStore.handleWifiScanAlwaysAvailableToggled(); - mActiveModeWarden.scanAlwaysModeChanged(); - } - }; - mFrameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE), - false, contentObserver); - - } - private void registerForBroadcasts() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); @@ -3277,8 +3271,8 @@ public class WifiServiceImpl extends BaseWifiService { mLog.info("enableVerboseLogging uid=% verbose=%") .c(Binder.getCallingUid()) .c(verbose).flush(); - mFacade.setIntegerSetting( - mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose); + mWifiInjector.getSettingsConfigStore().putBoolean( + WIFI_VERBOSE_LOGGING_ENABLED, verbose > 0); enableVerboseLoggingInternal(verbose); } @@ -3295,8 +3289,8 @@ public class WifiServiceImpl extends BaseWifiService { if (mVerboseLoggingEnabled) { mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush(); } - return mFacade.getIntegerSetting( - mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0); + return mWifiInjector.getSettingsConfigStore().getBoolean( + WIFI_VERBOSE_LOGGING_ENABLED, false) ? 1 : 0; } @Override diff --git a/service/java/com/android/server/wifi/WifiSettingsConfigStore.java b/service/java/com/android/server/wifi/WifiSettingsConfigStore.java new file mode 100644 index 000000000..7e072776c --- /dev/null +++ b/service/java/com/android/server/wifi/WifiSettingsConfigStore.java @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2020 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.annotation.StringDef; +import android.content.Context; +import android.net.wifi.WifiOemMigrationHook; +import android.os.Handler; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +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.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; +import java.util.Map; + +/** + * Store data for storing wifi settings. These are key (string) / value pairs that are stored in + * WifiConfigStore.xml file in a separate section. + * TODO(b/149738301): Rework this class. + */ +public class WifiSettingsConfigStore { + private static final String TAG = "WifiSettingsConfigStore"; + + /******** Wifi shared pref keys ***************/ + @StringDef({ + WIFI_P2P_DEVICE_NAME, + WIFI_P2P_PENDING_FACTORY_RESET, + WIFI_SCAN_ALWAYS_AVAILABLE, + WIFI_SCAN_THROTTLE_ENABLED, + WIFI_VERBOSE_LOGGING_ENABLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface WifiSettingsKey {} + + /** + * The Wi-Fi peer-to-peer device name + */ + public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name"; + + /** + * Indicate whether factory reset request is pending. + */ + public static final String WIFI_P2P_PENDING_FACTORY_RESET = "wifi_p2p_pending_factory_reset"; + + /** + * Allow scans to be enabled even wifi is turned off. + */ + public static final String WIFI_SCAN_ALWAYS_AVAILABLE = "wifi_scan_always_enabled"; + + /** + * Whether wifi scan throttle is enabled or not. + */ + public static final String WIFI_SCAN_THROTTLE_ENABLED = "wifi_scan_throttle_enabled"; + + /** + * Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1 + * will enable it. In the future, additional values may be supported. + */ + public static final String WIFI_VERBOSE_LOGGING_ENABLED = "wifi_verbose_logging_enabled"; + /******** Wifi shared pref keys ***************/ + + private final Context mContext; + private final Handler mHandler; + private final WifiConfigManager mWifiConfigManager; + + private final Object mLock = new Object(); + @GuardedBy("mLock") + private final Map<String, Object> mSettings = new HashMap<>(); + @GuardedBy("mLock") + private final Map<String, Map<OnSettingsChangedListener, Handler>> mListeners = + new HashMap<>(); + + private boolean mHasNewDataToSerialize = false; + + /** + * Interface for a settings change listener. + */ + public interface OnSettingsChangedListener { + /** + * Invoked when a particular key settings changes. + * + * @param key Key that was changed. + * @param newValue New value that was assigned to the key. + */ + void onSettingsChanged(@NonNull @WifiSettingsKey String key, @NonNull Object newValue); + } + + public WifiSettingsConfigStore(@NonNull Context context, @NonNull Handler handler, + @NonNull WifiConfigManager wifiConfigManager, + @NonNull WifiConfigStore wifiConfigStore) { + mContext = context; + mHandler = handler; + mWifiConfigManager = wifiConfigManager; + + // Register our data store. + wifiConfigStore.registerStoreData(new StoreData()); + } + + private void invokeAllListeners() { + synchronized (mLock) { + for (String key : mSettings.keySet()) { + invokeListeners(key); + } + } + } + + private void invokeListeners(@NonNull @WifiSettingsKey String key) { + synchronized (mLock) { + Object newValue = mSettings.get(key); + Map<OnSettingsChangedListener, Handler> listeners = mListeners.get(key); + if (listeners == null || listeners.isEmpty()) return; + for (Map.Entry<OnSettingsChangedListener, Handler> listener + : listeners.entrySet()) { + // Trigger the callback in the appropriate handler. + listener.getValue().post(() -> listener.getKey().onSettingsChanged(key, newValue)); + } + } + } + + /** + * Trigger config store writes and invoke listeners in the main wifi service looper's handler. + */ + private void triggerSaveToStoreAndInvokeAllListeners() { + mHandler.post(() -> { + mHasNewDataToSerialize = true; + mWifiConfigManager.saveToStore(true); + + invokeAllListeners(); + }); + } + + /** + * Trigger config store writes and invoke listeners in the main wifi service looper's handler. + */ + private void triggerSaveToStoreAndInvokeListeners(@NonNull @WifiSettingsKey String key) { + mHandler.post(() -> { + mHasNewDataToSerialize = true; + mWifiConfigManager.saveToStore(true); + + invokeListeners(key); + }); + } + + /** + * Performs a one time migration from Settings.Global values to settings store. Only + * performed one time if the settings store is empty. + */ + private void migrateFromSettingsIfNeeded() { + if (!mSettings.isEmpty()) return; // already migrated. + + WifiOemMigrationHook.SettingsMigrationData dataToMigrate = + WifiOemMigrationHook.loadFromSettings(mContext); + if (dataToMigrate == null) { + Log.e(TAG, "Not settings data to migrate"); + return; + } + Log.i(TAG, "Migrating data out of settings to shared preferences"); + + mSettings.put(WIFI_P2P_DEVICE_NAME, dataToMigrate.getP2pDeviceName()); + mSettings.put(WIFI_P2P_PENDING_FACTORY_RESET, dataToMigrate.isP2pFactoryResetPending()); + mSettings.put(WIFI_SCAN_THROTTLE_ENABLED, dataToMigrate.isScanThrottleEnabled()); + mSettings.put(WIFI_VERBOSE_LOGGING_ENABLED, dataToMigrate.isVerboseLoggingEnabled()); + triggerSaveToStoreAndInvokeAllListeners(); + } + + /** + * Store an int value to the stored settings. + * + * @param key One of the settings keys. + * @param value Value to be stored. + */ + public void putInt(@NonNull @WifiSettingsKey String key, int value) { + synchronized (mLock) { + mSettings.put(key, value); + } + triggerSaveToStoreAndInvokeListeners(key); + } + + /** + * Store a boolean value to the stored settings. + * + * @param key One of the settings keys. + * @param value Value to be stored. + */ + public void putBoolean(@NonNull @WifiSettingsKey String key, boolean value) { + synchronized (mLock) { + mSettings.put(key, value); + } + triggerSaveToStoreAndInvokeListeners(key); + } + + /** + * Store a String value to the stored settings. + * + * @param key One of the settings keys. + * @param value Value to be stored. + */ + public void putString(@NonNull @WifiSettingsKey String key, @NonNull String value) { + synchronized (mLock) { + mSettings.put(key, value); + } + triggerSaveToStoreAndInvokeListeners(key); + } + + /** + * Retrieve an int value from the stored settings. + * + * @param key One of the settings keys. + * @param defValue Default value to be returned if the key does not exist. + * @return value stored in settings, defValue if the key does not exist. + */ + public int getInt(@NonNull @WifiSettingsKey String key, int defValue) { + synchronized (mLock) { + return (int) mSettings.getOrDefault(key, defValue); + } + } + + /** + * Retrieve a boolean value from the stored settings. + * + * @param key One of the settings keys. + * @param defValue Default value to be returned if the key does not exist. + * @return value stored in settings, defValue if the key does not exist. + */ + public boolean getBoolean(@NonNull @WifiSettingsKey String key, boolean defValue) { + synchronized (mLock) { + return (boolean) mSettings.getOrDefault(key, defValue); + } + } + + /** + * Retrieve a string value from the stored settings. + * + * @param key One of the settings keys. + * @param defValue Default value to be returned if the key does not exist. + * @return value stored in settings, defValue if the key does not exist. + */ + public @Nullable String getString(@NonNull @WifiSettingsKey String key, + @Nullable String defValue) { + synchronized (mLock) { + return (String) mSettings.getOrDefault(key, defValue); + } + } + + /** + * Register for settings change listener. + * + * @param key One of the settings keys. + * @param listener Listener to be registered. + * @param handler Handler to post the listener + */ + public void registerChangeListener(@NonNull @WifiSettingsKey String key, + @NonNull OnSettingsChangedListener listener, @NonNull Handler handler) { + synchronized (mLock) { + mListeners.computeIfAbsent(key, ignore -> new HashMap<>()).put(listener, handler); + } + } + + /** + * Unregister for settings change listener. + * + * @param key One of the settings keys. + * @param listener Listener to be unregistered. + */ + public void unregisterChangeListener(@NonNull @WifiSettingsKey String key, + @NonNull OnSettingsChangedListener listener) { + synchronized (mLock) { + Map<OnSettingsChangedListener, Handler> listeners = mListeners.get(key); + if (listeners == null || listeners.isEmpty()) { + Log.e(TAG, "No listeners for " + key); + return; + } + if (listeners.remove(listener) == null) { + Log.e(TAG, "Unknown listener for " + key); + } + } + } + + /** + * 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"; + + @Override + public void serializeData(XmlSerializer out, + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) + throws XmlPullParserException, IOException { + synchronized (mLock) { + XmlUtil.writeNextValue(out, XML_TAG_VALUES, mSettings); + } + } + + @Override + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) + throws XmlPullParserException, IOException { + if (in == null) { + // Empty read triggers the migration since it indicates that there is no settings + // data stored in the settings store. + migrateFromSettingsIfNeeded(); + return; + } + Map<String, Object> values = 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_VALUES: + values = (Map) value; + break; + default: + Log.w(TAG, "Ignoring unknown tag under " + XML_TAG_SECTION_HEADER + ": " + + valueName[0]); + break; + } + } + if (values != null) { + synchronized (mLock) { + mSettings.putAll(values); + // Invoke all the registered listeners. + invokeAllListeners(); + } + } + } + + @Override + public void resetData() { + synchronized (mLock) { + mSettings.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/WifiSettingsStore.java b/service/java/com/android/server/wifi/WifiSettingsStore.java index a2f962f62..f0887a2c6 100644 --- a/service/java/com/android/server/wifi/WifiSettingsStore.java +++ b/service/java/com/android/server/wifi/WifiSettingsStore.java @@ -39,17 +39,14 @@ public class WifiSettingsStore { /* Tracks current airplane mode state */ private boolean mAirplaneModeOn = false; - /* Tracks the setting of scan being available even when wi-fi is turned off - */ - private boolean mScanAlwaysAvailable; - private final Context mContext; + private final WifiSettingsConfigStore mSettingsConfigStore; - WifiSettingsStore(Context context) { + WifiSettingsStore(Context context, WifiSettingsConfigStore sharedPreferences) { mContext = context; + mSettingsConfigStore = sharedPreferences; mAirplaneModeOn = getPersistedAirplaneModeOn(); mPersistWifiState = getPersistedWifiState(); - mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); } public synchronized boolean isWifiToggleEnabled() { @@ -65,11 +62,11 @@ public class WifiSettingsStore { * @return {@code true} if airplane mode is on. */ public synchronized boolean isAirplaneModeOn() { - return mAirplaneModeOn; + return mAirplaneModeOn; } public synchronized boolean isScanAlwaysAvailable() { - return !mAirplaneModeOn && mScanAlwaysAvailable; + return !mAirplaneModeOn && getPersistedScanAlwaysAvailable(); } public synchronized boolean handleWifiToggled(boolean wifiEnabled) { @@ -116,8 +113,8 @@ public class WifiSettingsStore { return true; } - synchronized void handleWifiScanAlwaysAvailableToggled() { - mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); + synchronized void handleWifiScanAlwaysAvailableToggled(boolean isAvailable) { + persistScanAlwaysAvailableState(isAvailable); } void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -131,6 +128,11 @@ public class WifiSettingsStore { Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state); } + private void persistScanAlwaysAvailableState(boolean isAvailable) { + mSettingsConfigStore.putBoolean( + WifiSettingsConfigStore.WIFI_SCAN_ALWAYS_AVAILABLE, isAvailable); + } + /* Does Wi-Fi need to be disabled when airplane mode is on ? */ private boolean isAirplaneSensitive() { String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(), @@ -163,8 +165,7 @@ public class WifiSettingsStore { } private boolean getPersistedScanAlwaysAvailable() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, - 0) == 1; + return mSettingsConfigStore.getBoolean( + WifiSettingsConfigStore.WIFI_SCAN_ALWAYS_AVAILABLE, false); } } diff --git a/service/java/com/android/server/wifi/aware/WifiAwareService.java b/service/java/com/android/server/wifi/aware/WifiAwareService.java index 94d8bc77d..2389b9ccd 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareService.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareService.java @@ -71,7 +71,7 @@ public final class WifiAwareService extends SystemService { mImpl.start(awareHandlerThread, wifiAwareStateManager, wifiAwareShellCommand, wifiInjector.getWifiMetrics().getWifiAwareMetrics(), wifiInjector.getWifiPermissionsUtil(), - wifiInjector.getWifiPermissionsWrapper(), wifiInjector.getFrameworkFacade(), + wifiInjector.getWifiPermissionsWrapper(), wifiInjector.getSettingsConfigStore(), wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback, wifiInjector.makeNetdWrapper()); } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { diff --git a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java index 6158607be..92ef7fbed 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java @@ -16,12 +16,13 @@ package com.android.server.wifi.aware; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; + import android.Manifest; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; -import android.database.ContentObserver; import android.hardware.wifi.V1_0.NanStatusType; import android.net.wifi.aware.Characteristics; import android.net.wifi.aware.ConfigRequest; @@ -38,14 +39,13 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.provider.Settings; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.server.wifi.Clock; -import com.android.server.wifi.FrameworkFacade; 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; @@ -98,8 +98,8 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { public void start(HandlerThread handlerThread, WifiAwareStateManager awareStateManager, WifiAwareShellCommand awareShellCommand, WifiAwareMetrics awareMetrics, WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper, - FrameworkFacade frameworkFacade, WifiAwareNativeManager wifiAwareNativeManager, - WifiAwareNativeApi wifiAwareNativeApi, + WifiSettingsConfigStore settingsConfigStore, + WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi, WifiAwareNativeCallback wifiAwareNativeCallback, NetdWrapper netdWrapper) { Log.i(TAG, "Starting Wi-Fi Aware service"); @@ -112,34 +112,25 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { mStateManager.start(mContext, handlerThread.getLooper(), awareMetrics, wifiPermissionsUtil, permissionsWrapper, new Clock(), netdWrapper); - frameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true, - new ContentObserver(new Handler(handlerThread.getLooper())) { - @Override - public void onChange(boolean selfChange) { - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), - awareStateManager, - wifiAwareNativeManager, wifiAwareNativeApi, - wifiAwareNativeCallback); - } - }); - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), awareStateManager, - wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback); + settingsConfigStore.registerChangeListener( + WIFI_VERBOSE_LOGGING_ENABLED, + (key, newValue) -> enableVerboseLogging((boolean) newValue, awareStateManager, + wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback), + mHandler); + enableVerboseLogging(settingsConfigStore.getBoolean( + WIFI_VERBOSE_LOGGING_ENABLED, false), + awareStateManager, + wifiAwareNativeManager, wifiAwareNativeApi, + wifiAwareNativeCallback); }); } - private void enableVerboseLogging(int verbose, WifiAwareStateManager awareStateManager, + private void enableVerboseLogging(boolean verbose, WifiAwareStateManager awareStateManager, WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi, WifiAwareNativeCallback wifiAwareNativeCallback) { boolean dbg; - if (verbose > 0) { - dbg = true; - } else { - dbg = false; - } + dbg = verbose; if (VDBG) { dbg = true; // just override } diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java index 270fb4d7f..a6111c3ff 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java @@ -16,6 +16,10 @@ package com.android.server.wifi.p2p; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_DEVICE_NAME; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_PENDING_FACTORY_RESET; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; + import android.annotation.Nullable; import android.app.AlertDialog; import android.content.BroadcastReceiver; @@ -27,7 +31,6 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; -import android.database.ContentObserver; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.DhcpResultsParcelable; @@ -87,6 +90,7 @@ import com.android.internal.util.StateMachine; import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiLog; +import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.proto.nano.WifiMetricsProto.P2pConnectionEvent; import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiAsyncChannel; @@ -134,6 +138,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { private WifiInjector mWifiInjector; private WifiPermissionsUtil mWifiPermissionsUtil; private FrameworkFacade mFrameworkFacade; + private WifiSettingsConfigStore mSettingsConfigStore; private WifiP2pMetrics mWifiP2pMetrics; private static final Boolean JOIN_GROUP = true; @@ -458,6 +463,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mWifiInjector = wifiInjector; mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil(); mFrameworkFacade = mWifiInjector.getFrameworkFacade(); + mSettingsConfigStore = mWifiInjector.getSettingsConfigStore(); mWifiP2pMetrics = mWifiInjector.getWifiP2pMetrics(); mDetailedState = NetworkInfo.DetailedState.IDLE; @@ -858,25 +864,20 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { checkAndSendP2pStateChangedBroadcast(); }, getHandler()); - mFrameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), - true, new ContentObserver(new Handler(looper)) { - @Override - public void onChange(boolean selfChange) { - enableVerboseLogging(mFrameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); - } - }); + mSettingsConfigStore.registerChangeListener( + WIFI_VERBOSE_LOGGING_ENABLED, + (key, newValue) -> enableVerboseLogging((boolean) newValue), + getHandler()); } } /** * Enable verbose logging for all sub modules. */ - private void enableVerboseLogging(int verbose) { - mVerboseLoggingEnabled = verbose > 0; - mWifiNative.enableVerboseLogging(verbose); - mWifiMonitor.enableVerboseLogging(verbose); + private void enableVerboseLogging(boolean verbose) { + mVerboseLoggingEnabled = verbose; + mWifiNative.enableVerboseLogging(verbose ? 1 : 0); + mWifiMonitor.enableVerboseLogging(verbose ? 1 : 0); } public void registerForWifiMonitorEvents() { @@ -3614,8 +3615,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } private String getPersistedDeviceName() { - String deviceName = mFrameworkFacade.getStringSetting(mContext, - Settings.Global.WIFI_P2P_DEVICE_NAME); + String deviceName = mSettingsConfigStore.getString(WIFI_P2P_DEVICE_NAME, null); if (deviceName == null) { // We use the 4 digits of the ANDROID_ID to have a friendly // default that has low likelihood of collision with a peer @@ -3637,8 +3637,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mThisDevice.deviceName = devName; mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); - mFrameworkFacade.setStringSetting(mContext, - Settings.Global.WIFI_P2P_DEVICE_NAME, devName); + mSettingsConfigStore.putString(WIFI_P2P_DEVICE_NAME, devName); sendThisDeviceChangedBroadcast(); return true; } @@ -3686,8 +3685,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { mServiceDiscReqId = null; updatePersistentNetworks(RELOAD); - enableVerboseLogging(mFrameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); + enableVerboseLogging(mSettingsConfigStore.getBoolean( + WIFI_VERBOSE_LOGGING_ENABLED, false)); } private void updateThisDevice(int status) { @@ -4100,16 +4099,11 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } private void setPendingFactoryReset(boolean pending) { - mFrameworkFacade.setIntegerSetting(mContext, - Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET, - pending ? 1 : 0); + mSettingsConfigStore.putBoolean(WIFI_P2P_PENDING_FACTORY_RESET, pending); } private boolean isPendingFactoryReset() { - int val = mFrameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET, - 0); - return (val != 0); + return mSettingsConfigStore.getBoolean(WIFI_P2P_PENDING_FACTORY_RESET, false); } /** diff --git a/service/java/com/android/server/wifi/rtt/RttService.java b/service/java/com/android/server/wifi/rtt/RttService.java index 0d3e98943..17e455868 100644 --- a/service/java/com/android/server/wifi/rtt/RttService.java +++ b/service/java/com/android/server/wifi/rtt/RttService.java @@ -65,7 +65,7 @@ public class RttService extends SystemService { RttNative rttNative = new RttNative(mImpl, halDeviceManager); mImpl.start(handlerThread.getLooper(), wifiInjector.getClock(), awareManager, rttNative, - rttMetrics, wifiPermissionsUtil, wifiInjector.getFrameworkFacade()); + rttMetrics, wifiPermissionsUtil, wifiInjector.getSettingsConfigStore()); } } } diff --git a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java index 10db0af76..d8708d526 100644 --- a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java +++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java @@ -18,6 +18,8 @@ package com.android.server.wifi.rtt; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; + import android.annotation.NonNull; import android.app.ActivityManager; import android.content.BroadcastReceiver; @@ -25,7 +27,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.database.ContentObserver; import android.location.LocationManager; import android.net.MacAddress; import android.net.wifi.aware.IWifiAwareMacAddressProvider; @@ -49,14 +50,13 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.WorkSource; import android.os.WorkSource.WorkChain; -import android.provider.Settings; import android.util.Log; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.WakeupMessage; import com.android.server.wifi.Clock; -import com.android.server.wifi.FrameworkFacade; +import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.proto.nano.WifiMetricsProto; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.wifi.resources.R; @@ -240,11 +240,11 @@ public class RttServiceImpl extends IWifiRttManager.Stub { * @param rttNative The Native interface to the HAL. * @param rttMetrics The Wi-Fi RTT metrics object. * @param wifiPermissionsUtil Utility for permission checks. - * @param frameworkFacade Facade for framework classes, allows mocking. + * @param settingsConfigStore Used for retrieving verbose logging level. */ public void start(Looper looper, Clock clock, WifiAwareManager awareManager, RttNative rttNative, RttMetrics rttMetrics, WifiPermissionsUtil wifiPermissionsUtil, - FrameworkFacade frameworkFacade) { + WifiSettingsConfigStore settingsConfigStore) { mClock = clock; mAwareManager = awareManager; mRttNative = rttNative; @@ -273,18 +273,12 @@ public class RttServiceImpl extends IWifiRttManager.Stub { } }, intentFilter); - frameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true, - new ContentObserver(mRttServiceSynchronized.mHandler) { - @Override - public void onChange(boolean selfChange) { - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); - } - }); - - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); + settingsConfigStore.registerChangeListener( + WIFI_VERBOSE_LOGGING_ENABLED, + (key, newValue) -> enableVerboseLogging((boolean) newValue), + mRttServiceSynchronized.mHandler); + enableVerboseLogging(settingsConfigStore.getBoolean( + WIFI_VERBOSE_LOGGING_ENABLED, false)); mBackgroundProcessExecGapMs = mContext.getResources().getInteger( R.integer.config_wifiRttBackgroundExecGapMs); @@ -307,12 +301,8 @@ public class RttServiceImpl extends IWifiRttManager.Stub { }); } - private void enableVerboseLogging(int verbose) { - if (verbose > 0) { - mDbg = true; - } else { - mDbg = false; - } + private void enableVerboseLogging(boolean verbose) { + mDbg = verbose; if (VDBG) { mDbg = true; // just override } diff --git a/service/java/com/android/server/wifi/util/ApConfigUtil.java b/service/java/com/android/server/wifi/util/ApConfigUtil.java index 7c7925200..6cc8fdba9 100644 --- a/service/java/com/android/server/wifi/util/ApConfigUtil.java +++ b/service/java/com/android/server/wifi/util/ApConfigUtil.java @@ -33,6 +33,7 @@ import com.android.wifi.resources.R; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Random; /** @@ -532,10 +533,10 @@ public class ApConfigUtil { */ public static boolean checkConfigurationChangeNeedToRestart( SoftApConfiguration currentConfig, SoftApConfiguration newConfig) { - return currentConfig.getSsid() != newConfig.getSsid() + return !Objects.equals(currentConfig.getSsid(), newConfig.getSsid()) || currentConfig.getBssid() != newConfig.getBssid() || currentConfig.getSecurityType() != newConfig.getSecurityType() - || currentConfig.getPassphrase() != newConfig.getPassphrase() + || !Objects.equals(currentConfig.getPassphrase(), newConfig.getPassphrase()) || currentConfig.isHiddenSsid() != newConfig.isHiddenSsid() || currentConfig.getBand() != newConfig.getBand() || currentConfig.getChannel() != newConfig.getChannel(); diff --git a/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java b/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java index 7c3cc9cdf..41b6b66a9 100644 --- a/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREG import static com.android.server.wifi.ScanRequestProxy.SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS; import static com.android.server.wifi.ScanRequestProxy.SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_SCAN_THROTTLE_ENABLED; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -38,7 +39,6 @@ import android.os.IBinder; import android.os.UserHandle; import android.os.WorkSource; import android.os.test.TestLooper; -import android.provider.Settings; import androidx.test.filters.SmallTest; @@ -85,7 +85,7 @@ public class ScanRequestProxyTest extends WifiBaseTest { @Mock private WifiPermissionsUtil mWifiPermissionsUtil; @Mock private WifiMetrics mWifiMetrics; @Mock private Clock mClock; - @Mock private FrameworkFacade mFrameworkFacade; + @Mock private WifiSettingsConfigStore mWifiSettingsConfigStore; @Mock private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; @Mock private IScanResultsCallback mScanResultsCallback; @Mock private IScanResultsCallback mAnotherScanResultsCallback; @@ -138,14 +138,13 @@ public class ScanRequestProxyTest extends WifiBaseTest { new int[]{WifiScanner.WIFI_BAND_BOTH_WITH_DFS}); // Scan throttling is enabled by default. - when(mFrameworkFacade.getIntegerSetting( - eq(mContext), eq(Settings.Global.WIFI_SCAN_THROTTLE_ENABLED), anyInt())) - .thenReturn(1); + when(mWifiSettingsConfigStore.getBoolean(eq(WIFI_SCAN_THROTTLE_ENABLED), anyBoolean())) + .thenReturn(true); mLooper = new TestLooper(); mScanRequestProxy = new ScanRequestProxy(mContext, mAppOps, mActivityManager, mWifiInjector, mWifiConfigManager, mWifiPermissionsUtil, mWifiMetrics, mClock, - mFrameworkFacade, new Handler(mLooper.getLooper())); + new Handler(mLooper.getLooper()), mWifiSettingsConfigStore); when(mScanResultsCallback.asBinder()).thenReturn(mBinder); when(mAnotherScanResultsCallback.asBinder()).thenReturn(mAnotherBinder); } @@ -644,10 +643,8 @@ public class ScanRequestProxyTest extends WifiBaseTest { public void testSuccessiveScanRequestFromSameAppWhenThrottlingIsDisabledNotThrottled() { // Triggers the scan throttle setting registration. testEnableScanning(); - // Disable scan throttling & invoke the content observer callback. mScanRequestProxy.setScanThrottleEnabled(false); - verify(mFrameworkFacade).setIntegerSetting( - eq(mContext), eq(Settings.Global.WIFI_SCAN_THROTTLE_ENABLED), anyInt()); + verify(mWifiSettingsConfigStore).putBoolean(WIFI_SCAN_THROTTLE_ENABLED, false); long firstRequestMs = 782; when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs); diff --git a/tests/wifitests/src/com/android/server/wifi/ScoringParamsTest.java b/tests/wifitests/src/com/android/server/wifi/ScoringParamsTest.java index 4bb67a8f4..3c07bce1c 100644 --- a/tests/wifitests/src/com/android/server/wifi/ScoringParamsTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ScoringParamsTest.java @@ -19,19 +19,12 @@ package com.android.server.wifi; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; -import android.database.ContentObserver; import android.net.wifi.WifiInfo; -import android.os.Handler; -import android.provider.Settings; import androidx.test.filters.SmallTest; @@ -39,7 +32,6 @@ import com.android.wifi.resources.R; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -328,57 +320,4 @@ public class ScoringParamsTest extends WifiBaseTest { assertEquals(mGood6GHz, mScoringParams.getGoodRssi(6275)); assertEquals(mGood6GHz, mScoringParams.getGoodRssi(ScoringParams.BAND6)); } - - /** - * Additional mocks for handling Settings - */ - @Mock FrameworkFacade mFrameworkFacade; - @Mock Handler mHandler; - - /** - * Test getting updates from Settings - * - * Exercises the ContentObserver notification path - */ - @Test - public void testFullConstructorWithUpdatesFromSettings() throws Exception { - ArgumentCaptor<ContentObserver> captor = ArgumentCaptor.forClass(ContentObserver.class); - when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) - .thenReturn(null); - mScoringParams = new ScoringParams(mContext, mFrameworkFacade, mHandler); - verify(mFrameworkFacade) - .registerContentObserver(eq(mContext), any(), anyBoolean(), captor.capture()); - - String before = mScoringParams.toString(); - String changed = before.replace('8', '9'); - assertFalse(changed.equals(before)); - - when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) - .thenReturn(changed); - captor.getValue().onChange(/*selfChange*/ false); - assertEquals(changed, mScoringParams.toString()); - - when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) - .thenReturn(""); - captor.getValue().onChange(/*selfChange*/ false); - assertEquals(before, mScoringParams.toString()); - } - - @Test - public void testBadSettings() throws Exception { - ArgumentCaptor<ContentObserver> captor = ArgumentCaptor.forClass(ContentObserver.class); - when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) - .thenReturn(null); - mScoringParams = new ScoringParams(mContext, mFrameworkFacade, mHandler); - verify(mFrameworkFacade) - .registerContentObserver(eq(mContext), any(), anyBoolean(), captor.capture()); - - String before = mScoringParams.toString(); - String garbage = "what??"; - - when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) - .thenReturn(garbage); - captor.getValue().onChange(/*selfChange*/ false); - assertEquals(before, mScoringParams.toString()); - } } diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApBackupRestoreTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApBackupRestoreTest.java index 331ba92e4..c7565c6ca 100644 --- a/tests/wifitests/src/com/android/server/wifi/SoftApBackupRestoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SoftApBackupRestoreTest.java @@ -21,22 +21,32 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import android.content.Context; import android.net.MacAddress; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiOemMigrationHook; import android.util.BackupUtils; import androidx.test.filters.SmallTest; +import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.wifi.util.ApConfigUtil; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; /** * Unit tests for {@link com.android.server.wifi.SoftApBackupRestore}. @@ -44,15 +54,25 @@ import java.util.ArrayList; @SmallTest public class SoftApBackupRestoreTest extends WifiBaseTest { + @Mock private Context mContext; + @Mock private WifiOemMigrationHook.SettingsMigrationData mOemMigrationData; private SoftApBackupRestore mSoftApBackupRestore; + private final ArrayList<MacAddress> mTestBlockedList = new ArrayList<>(); + private final ArrayList<MacAddress> mTestAllowedList = new ArrayList<>(); private static final int LAST_WIFICOFIGURATION_BACKUP_VERSION = 3; private static final boolean TEST_CLIENTCONTROLENABLE = false; private static final int TEST_MAXNUMBEROFCLIENTS = 10; private static final int TEST_SHUTDOWNTIMEOUTMILLIS = 600_000; - private static final ArrayList<MacAddress> TEST_BLOCKEDLIST = new ArrayList<>(); private static final String TEST_BLOCKED_CLIENT = "11:22:33:44:55:66"; - private static final ArrayList<MacAddress> TEST_ALLOWEDLIST = new ArrayList<>(); private static final String TEST_ALLOWED_CLIENT = "aa:bb:cc:dd:ee:ff"; + private static final String TEST_SSID = "TestAP"; + private static final String TEST_PASSPHRASE = "TestPskPassphrase"; + private static final int TEST_SECURITY = SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION; + private static final int TEST_BAND = SoftApConfiguration.BAND_5GHZ; + private static final int TEST_CHANNEL = 40; + private static final boolean TEST_HIDDEN = false; + + MockitoSession mSession; /** * Asserts that the WifiConfigurations equal to SoftApConfiguration. @@ -76,10 +96,24 @@ public class SoftApBackupRestoreTest extends WifiBaseTest { assertEquals(backup.hiddenSSID, restore.isHiddenSsid()); } - @Before public void setUp() throws Exception { - mSoftApBackupRestore = new SoftApBackupRestore(); + MockitoAnnotations.initMocks(this); + + mSession = ExtendedMockito.mockitoSession() + .mockStatic(WifiOemMigrationHook.class, withSettings().lenient()) + .strictness(Strictness.LENIENT) + .startMocking(); + when(WifiOemMigrationHook.loadFromSettings(any(Context.class))) + .thenReturn(mOemMigrationData); + when(mOemMigrationData.isSoftApTimeoutEnabled()).thenReturn(true); + + mSoftApBackupRestore = new SoftApBackupRestore(mContext); + } + + @After + public void tearDown() throws Exception { + mSession.finishMocking(); } /** @@ -169,6 +203,7 @@ public class SoftApBackupRestoreTest extends WifiBaseTest { configBuilder.setPassphrase("TestPskPassphrase", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); configBuilder.setHiddenSsid(true); + configBuilder.setAutoShutdownEnabled(true); SoftApConfiguration config = configBuilder.build(); byte[] data = mSoftApBackupRestore.retrieveBackupDataFromSoftApConfiguration(config); @@ -190,6 +225,7 @@ public class SoftApBackupRestoreTest extends WifiBaseTest { configBuilder.setPassphrase("TestPskPassphrase", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); configBuilder.setHiddenSsid(true); + configBuilder.setAutoShutdownEnabled(false); SoftApConfiguration config = configBuilder.build(); byte[] data = mSoftApBackupRestore.retrieveBackupDataFromSoftApConfiguration(config); @@ -203,20 +239,19 @@ public class SoftApBackupRestoreTest extends WifiBaseTest { * Verifies that the serialization/de-serialization for wpa3-sae-transition softap config. */ @Test - public void testSoftApConfigBackupAndRestoreWithMaxShutDonwClientList() throws Exception { - TEST_BLOCKEDLIST.add(MacAddress.fromString(TEST_BLOCKED_CLIENT)); - TEST_ALLOWEDLIST.add(MacAddress.fromString(TEST_ALLOWED_CLIENT)); + public void testSoftApConfigBackupAndRestoreWithMaxShutDownClientList() throws Exception { + mTestBlockedList.add(MacAddress.fromString(TEST_BLOCKED_CLIENT)); + mTestAllowedList.add(MacAddress.fromString(TEST_ALLOWED_CLIENT)); SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); - configBuilder.setSsid("TestAP"); + configBuilder.setSsid(TEST_SSID); configBuilder.setBand(SoftApConfiguration.BAND_5GHZ); configBuilder.setChannel(40, SoftApConfiguration.BAND_5GHZ); - configBuilder.setPassphrase("TestPskPassphrase", - SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); - configBuilder.setHiddenSsid(true); + configBuilder.setPassphrase(TEST_PASSPHRASE, TEST_SECURITY); + configBuilder.setHiddenSsid(TEST_HIDDEN); configBuilder.setMaxNumberOfClients(TEST_MAXNUMBEROFCLIENTS); configBuilder.setShutdownTimeoutMillis(TEST_SHUTDOWNTIMEOUTMILLIS); configBuilder.enableClientControlByUser(TEST_CLIENTCONTROLENABLE); - configBuilder.setClientList(TEST_BLOCKEDLIST, TEST_ALLOWEDLIST); + configBuilder.setClientList(mTestBlockedList, mTestAllowedList); SoftApConfiguration config = configBuilder.build(); byte[] data = mSoftApBackupRestore.retrieveBackupDataFromSoftApConfiguration(config); @@ -225,4 +260,74 @@ public class SoftApBackupRestoreTest extends WifiBaseTest { assertThat(config).isEqualTo(restoredConfig); } + + /** + * Verifies that the restore of version 5 backup data will read the auto shutdown enable/disable + * tag from {@link WifiOemMigrationHook#loadFromSettings(Context)} + */ + @Test + public void testSoftApConfigRestoreFromVersion5() throws Exception { + mTestBlockedList.add(MacAddress.fromString(TEST_BLOCKED_CLIENT)); + mTestAllowedList.add(MacAddress.fromString(TEST_ALLOWED_CLIENT)); + SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); + configBuilder.setSsid(TEST_SSID); + configBuilder.setBand(TEST_BAND); + configBuilder.setChannel(TEST_CHANNEL, TEST_BAND); + configBuilder.setPassphrase(TEST_PASSPHRASE, TEST_SECURITY); + configBuilder.setHiddenSsid(TEST_HIDDEN); + configBuilder.setMaxNumberOfClients(TEST_MAXNUMBEROFCLIENTS); + configBuilder.setShutdownTimeoutMillis(TEST_SHUTDOWNTIMEOUTMILLIS); + configBuilder.enableClientControlByUser(TEST_CLIENTCONTROLENABLE); + configBuilder.setClientList(mTestBlockedList, mTestAllowedList); + + // Toggle on when migrating. + when(mOemMigrationData.isSoftApTimeoutEnabled()).thenReturn(true); + SoftApConfiguration expectedConfig = configBuilder.setAutoShutdownEnabled(true).build(); + SoftApConfiguration restoredConfig = + mSoftApBackupRestore.retrieveSoftApConfigurationFromBackupData( + retrieveVersion5BackupDataFromSoftApConfiguration(expectedConfig)); + assertEquals(expectedConfig, restoredConfig); + + // Toggle off when migrating. + when(mOemMigrationData.isSoftApTimeoutEnabled()).thenReturn(false); + expectedConfig = configBuilder.setAutoShutdownEnabled(false).build(); + restoredConfig = mSoftApBackupRestore.retrieveSoftApConfigurationFromBackupData( + retrieveVersion5BackupDataFromSoftApConfiguration(expectedConfig)); + assertEquals(expectedConfig, restoredConfig); + } + + /** + * This is a copy of the old serialization code (version 5) + * + * Changes: Version = 5, AutoShutdown tag is missing. + */ + private byte[] retrieveVersion5BackupDataFromSoftApConfiguration(SoftApConfiguration config) + throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos); + + out.writeInt(5); + BackupUtils.writeString(out, config.getSsid()); + out.writeInt(config.getBand()); + out.writeInt(config.getChannel()); + BackupUtils.writeString(out, config.getPassphrase()); + out.writeInt(config.getSecurityType()); + out.writeBoolean(config.isHiddenSsid()); + out.writeInt(config.getMaxNumberOfClients()); + out.writeInt(config.getShutdownTimeoutMillis()); + out.writeBoolean(config.isClientControlByUserEnabled()); + writeMacAddressList(out, config.getBlockedClientList()); + writeMacAddressList(out, config.getAllowedClientList()); + return baos.toByteArray(); + } + + private void writeMacAddressList(DataOutputStream out, List<MacAddress> macList) + throws IOException { + out.writeInt(macList.size()); + Iterator<MacAddress> iterator = macList.iterator(); + while (iterator.hasNext()) { + byte[] mac = iterator.next().toByteArray(); + out.write(mac, 0, 6); + } + } } diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java index 7b4c1cee6..e37e3a71e 100644 --- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java @@ -54,9 +54,7 @@ import android.app.test.TestAlarmManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; -import android.database.ContentObserver; import android.net.MacAddress; -import android.net.Uri; import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration.Builder; @@ -111,9 +109,8 @@ public class SoftApManagerTest extends WifiBaseTest { SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT; private static final int TEST_AP_BANDWIDTH_IN_SOFTAPINFO = SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT; private static final int[] EMPTY_CHANNEL_ARRAY = {}; - private final SoftApConfiguration mDefaultApConfig = createDefaultApConfig(); + private SoftApConfiguration mDefaultApConfig = createDefaultApConfig(); - private ContentObserver mContentObserver; private TestLooper mLooper; private TestAlarmManager mAlarmManager; private SoftApInfo mTestSoftApInfo; @@ -1473,9 +1470,10 @@ public class SoftApManagerTest extends WifiBaseTest { mTestSoftApCapability); startSoftApAndVerifyEnabled(apConfig); - when(mFrameworkFacade.getIntegerSetting( - mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); - mContentObserver.onChange(false); + SoftApConfiguration newConfig = new SoftApConfiguration.Builder(mDefaultApConfig) + .setAutoShutdownEnabled(false) + .build(); + mSoftApManager.updateConfiguration(newConfig); mLooper.dispatchAll(); // Verify timer is canceled @@ -1485,16 +1483,18 @@ public class SoftApManagerTest extends WifiBaseTest { @Test public void schedulesTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception { // start with timeout toggle disabled - when(mFrameworkFacade.getIntegerSetting( - mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); + mDefaultApConfig = new SoftApConfiguration.Builder(mDefaultApConfig) + .setAutoShutdownEnabled(false) + .build(); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, mTestSoftApCapability); startSoftApAndVerifyEnabled(apConfig); - when(mFrameworkFacade.getIntegerSetting( - mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(1); - mContentObserver.onChange(false); + SoftApConfiguration newConfig = new SoftApConfiguration.Builder(mDefaultApConfig) + .setAutoShutdownEnabled(true) + .build(); + mSoftApManager.updateConfiguration(newConfig); mLooper.dispatchAll(); // Verify timer is scheduled @@ -1505,8 +1505,9 @@ public class SoftApManagerTest extends WifiBaseTest { @Test public void doesNotScheduleTimeoutTimerOnStartWhenTimeoutIsDisabled() throws Exception { // start with timeout toggle disabled - when(mFrameworkFacade.getIntegerSetting( - mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); + mDefaultApConfig = new SoftApConfiguration.Builder(mDefaultApConfig) + .setAutoShutdownEnabled(false) + .build(); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, mTestSoftApCapability); @@ -1521,8 +1522,9 @@ public class SoftApManagerTest extends WifiBaseTest { public void doesNotScheduleTimeoutTimerWhenAllClientsDisconnectButTimeoutIsDisabled() throws Exception { // start with timeout toggle disabled - when(mFrameworkFacade.getIntegerSetting( - mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); + mDefaultApConfig = new SoftApConfiguration.Builder(mDefaultApConfig) + .setAutoShutdownEnabled(false) + .build(); SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, mTestSoftApCapability); @@ -1541,18 +1543,6 @@ public class SoftApManagerTest extends WifiBaseTest { } @Test - public void unregistersSettingsObserverOnStop() throws Exception { - SoftApModeConfiguration apConfig = - new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, - mTestSoftApCapability); - startSoftApAndVerifyEnabled(apConfig); - mSoftApManager.stop(); - mLooper.dispatchAll(); - - verify(mFrameworkFacade).unregisterContentObserver(eq(mContext), eq(mContentObserver)); - } - - @Test public void resetsFactoryMacWhenRandomizationOff() throws Exception { Builder configBuilder = new SoftApConfiguration.Builder(); configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); @@ -1751,8 +1741,6 @@ public class SoftApManagerTest extends WifiBaseTest { .build(); } - ArgumentCaptor<ContentObserver> observerCaptor = ArgumentCaptor.forClass( - ContentObserver.class); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); when(mWifiNative.setupInterfaceForSoftApMode(any())) @@ -1787,9 +1775,6 @@ public class SoftApManagerTest extends WifiBaseTest { softApConfig.getTargetMode()); verify(mListener).onStarted(); verify(mWifiMetrics).addSoftApUpChangedEvent(true, softApConfig.getTargetMode()); - verify(mFrameworkFacade).registerContentObserver(eq(mContext), any(Uri.class), eq(true), - observerCaptor.capture()); - mContentObserver = observerCaptor.getValue(); } private void checkApStateChangedBroadcast(Intent intent, int expectedCurrentState, diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java index 62e20cc18..f3317fdd6 100644 --- a/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java @@ -17,20 +17,27 @@ package com.android.server.wifi; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; +import android.content.Context; import android.net.MacAddress; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiOemMigrationHook; import android.util.Xml; import androidx.test.filters.SmallTest; +import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; @@ -40,6 +47,8 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; @@ -63,6 +72,7 @@ public class SoftApStoreDataTest extends WifiBaseTest { private static final int TEST_OLD_BAND = WifiConfiguration.AP_BAND_ANY; private static final int TEST_SECURITY = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK; private static final boolean TEST_CLIENT_CONTROL_BY_USER = false; + private static final boolean TEST_AUTO_SHUTDOWN_ENABLED = true; private static final int TEST_MAX_NUMBER_OF_CLIENTS = 10; private static final int TEST_SHUTDOWN_TIMEOUT_MILLIS = 600_000; private static final ArrayList<MacAddress> TEST_BLOCKEDLIST = new ArrayList<>(); @@ -97,6 +107,8 @@ public class SoftApStoreDataTest extends WifiBaseTest { + TEST_MAX_NUMBER_OF_CLIENTS + "\" />\n" + "<boolean name=\"ClientControlByUser\" value=\"" + TEST_CLIENT_CONTROL_BY_USER + "\" />\n" + + "<boolean name=\"AutoShutdownEnabled\" value=\"" + + TEST_AUTO_SHUTDOWN_ENABLED + "\" />\n" + "<int name=\"ShutdownTimeoutMillis\" value=\"" + TEST_SHUTDOWN_TIMEOUT_MILLIS + "\" />\n" + "<BlockedClientList>\n" @@ -106,14 +118,46 @@ public class SoftApStoreDataTest extends WifiBaseTest { + "<string name=\"ClientMacAddress\">" + TEST_ALLOWED_CLIENT + "</string>\n" + "</AllowedClientList>\n"; + private static final String TEST_SOFTAP_CONFIG_XML_STRING_WITH_ALL_CONFIG_EXCEPT_AUTO_SHUTDOWN = + "<string name=\"SSID\">" + TEST_SSID + "</string>\n" + + "<int name=\"ApBand\" value=\"" + TEST_BAND + "\" />\n" + + "<int name=\"Channel\" value=\"" + TEST_CHANNEL + "\" />\n" + + "<boolean name=\"HiddenSSID\" value=\"" + TEST_HIDDEN + "\" />\n" + + "<int name=\"SecurityType\" value=\"" + TEST_SECURITY + "\" />\n" + + "<string name=\"Passphrase\">" + TEST_PASSPHRASE + "</string>\n" + + "<int name=\"MaxNumberOfClients\" value=\"" + + TEST_MAX_NUMBER_OF_CLIENTS + "\" />\n" + + "<boolean name=\"ClientControlByUser\" value=\"" + + TEST_CLIENT_CONTROL_BY_USER + "\" />\n" + + "<int name=\"ShutdownTimeoutMillis\" value=\"" + + TEST_SHUTDOWN_TIMEOUT_MILLIS + "\" />\n" + + "<BlockedClientList>\n" + + "<string name=\"ClientMacAddress\">" + TEST_BLOCKED_CLIENT + "</string>\n" + + "</BlockedClientList>\n" + + "<AllowedClientList>\n" + + "<string name=\"ClientMacAddress\">" + TEST_ALLOWED_CLIENT + "</string>\n" + + "</AllowedClientList>\n"; + + @Mock private Context mContext; @Mock SoftApStoreData.DataSource mDataSource; @Mock WifiOemConfigStoreMigrationDataHolder mWifiOemConfigStoreMigrationDataHolder; + @Mock private WifiOemMigrationHook.SettingsMigrationData mOemMigrationData; + MockitoSession mSession; SoftApStoreData mSoftApStoreData; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mSoftApStoreData = new SoftApStoreData(mDataSource, mWifiOemConfigStoreMigrationDataHolder); + mSession = ExtendedMockito.mockitoSession() + .mockStatic(WifiOemMigrationHook.class, withSettings().lenient()) + .strictness(Strictness.LENIENT) + .startMocking(); + when(WifiOemMigrationHook.loadFromSettings(any(Context.class))) + .thenReturn(mOemMigrationData); + when(mOemMigrationData.isSoftApTimeoutEnabled()).thenReturn(true); + + mSoftApStoreData = + new SoftApStoreData(mContext, mDataSource, mWifiOemConfigStoreMigrationDataHolder); TEST_BLOCKEDLIST.add(MacAddress.fromString(TEST_BLOCKED_CLIENT)); TEST_ALLOWEDLIST.add(MacAddress.fromString(TEST_ALLOWED_CLIENT)); } @@ -125,6 +169,7 @@ public class SoftApStoreDataTest extends WifiBaseTest { public void cleanup() { TEST_BLOCKEDLIST.clear(); TEST_ALLOWEDLIST.clear(); + mSession.finishMocking(); } /** @@ -150,6 +195,7 @@ public class SoftApStoreDataTest extends WifiBaseTest { softApConfigBuilder.setBand(TEST_BAND); softApConfigBuilder.enableClientControlByUser(TEST_CLIENT_CONTROL_BY_USER); softApConfigBuilder.setMaxNumberOfClients(TEST_MAX_NUMBER_OF_CLIENTS); + softApConfigBuilder.setAutoShutdownEnabled(true); softApConfigBuilder.setShutdownTimeoutMillis(TEST_SHUTDOWN_TIMEOUT_MILLIS); softApConfigBuilder.setClientList(TEST_BLOCKEDLIST, TEST_ALLOWEDLIST); return softApConfigBuilder.build(); @@ -229,6 +275,7 @@ public class SoftApStoreDataTest extends WifiBaseTest { assertEquals(softApConfig.getBand(), TEST_BAND); assertEquals(softApConfig.isClientControlByUserEnabled(), TEST_CLIENT_CONTROL_BY_USER); assertEquals(softApConfig.getMaxNumberOfClients(), TEST_MAX_NUMBER_OF_CLIENTS); + assertTrue(softApConfig.isAutoShutdownEnabled()); assertEquals(softApConfig.getShutdownTimeoutMillis(), TEST_SHUTDOWN_TIMEOUT_MILLIS); assertEquals(softApConfig.getBlockedClientList(), TEST_BLOCKEDLIST); assertEquals(softApConfig.getAllowedClientList(), TEST_ALLOWEDLIST); @@ -419,4 +466,37 @@ public class SoftApStoreDataTest extends WifiBaseTest { assertEquals(softApConfig.getAllowedClientList(), TEST_ALLOWEDLIST); } + /** + * Verify that the store data is deserialized correctly using the predefined test XML data + * when the auto shutdown tag is retrieved from + * {@link WifiOemMigrationHook.loadFromSettings(Context)}. + * + * @throws Exception + */ + @Test + public void deserializeSoftApWithNoAutoShutdownTag() throws Exception { + + // Toggle on when migrating. + when(mOemMigrationData.isSoftApTimeoutEnabled()).thenReturn(true); + deserializeData( + TEST_SOFTAP_CONFIG_XML_STRING_WITH_ALL_CONFIG_EXCEPT_AUTO_SHUTDOWN.getBytes()); + ArgumentCaptor<SoftApConfiguration> softapConfigCaptor = + ArgumentCaptor.forClass(SoftApConfiguration.class); + verify(mDataSource).fromDeserialized(softapConfigCaptor.capture()); + SoftApConfiguration softApConfig = softapConfigCaptor.getValue(); + assertNotNull(softApConfig); + assertEquals(softApConfig.getSsid(), TEST_SSID); + assertTrue(softApConfig.isAutoShutdownEnabled()); + + // Toggle off when migrating. + when(mOemMigrationData.isSoftApTimeoutEnabled()).thenReturn(false); + deserializeData( + TEST_SOFTAP_CONFIG_XML_STRING_WITH_ALL_CONFIG_EXCEPT_AUTO_SHUTDOWN.getBytes()); + verify(mDataSource, times(2)).fromDeserialized(softapConfigCaptor.capture()); + softApConfig = softapConfigCaptor.getValue(); + assertNotNull(softApConfig); + assertEquals(softApConfig.getSsid(), TEST_SSID); + assertFalse(softApConfig.isAutoShutdownEnabled()); + } + } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java index a289171b4..586ab3222 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; import static com.google.common.truth.Truth.assertThat; @@ -304,6 +305,7 @@ public class WifiServiceImplTest extends WifiBaseTest { @Mock ISuggestionConnectionStatusListener mSuggestionConnectionStatusListener; @Mock IOnWifiActivityEnergyInfoListener mOnWifiActivityEnergyInfoListener; @Mock IWifiConnectedNetworkScorer mWifiConnectedNetworkScorer; + @Mock WifiSettingsConfigStore mWifiSettingsConfigStore; WifiLog mLog = new LogcatLog(TAG); @@ -374,6 +376,7 @@ public class WifiServiceImplTest extends WifiBaseTest { .thenReturn(mock(WifiNetworkScoreCache.class)); when(mWifiInjector.getWifiThreadRunner()) .thenReturn(new WifiThreadRunner(new Handler(mLooper.getLooper()))); + when(mWifiInjector.getSettingsConfigStore()).thenReturn(mWifiSettingsConfigStore); when(mClientModeImpl.syncStartSubscriptionProvisioning(anyInt(), any(OsuProvider.class), any(IProvisioningCallback.class), any())).thenReturn(true); // Create an OSU provider that can be provisioned via an open OSU AP @@ -1194,6 +1197,7 @@ public class WifiServiceImplTest extends WifiBaseTest { when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); mWifiServiceImpl.checkAndStartWifi(); mLooper.dispatchAll(); + verify(mWifiConfigManager).loadFromStore(); verify(mActiveModeWarden).start(); verify(mActiveModeWarden, never()).wifiToggled(); } @@ -1211,6 +1215,7 @@ public class WifiServiceImplTest extends WifiBaseTest { anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); mWifiServiceImpl.checkAndStartWifi(); mLooper.dispatchAll(); + verify(mWifiConfigManager).loadFromStore(); verify(mActiveModeWarden).start(); } @@ -3374,6 +3379,7 @@ public class WifiServiceImplTest extends WifiBaseTest { // before invocation. reset(mClientModeImpl); mWifiServiceImpl.enableVerboseLogging(1); + verify(mWifiSettingsConfigStore).putBoolean(WIFI_VERBOSE_LOGGING_ENABLED, true); verify(mClientModeImpl).enableVerboseLogging(anyInt()); } @@ -3390,6 +3396,8 @@ public class WifiServiceImplTest extends WifiBaseTest { // before invocation. reset(mClientModeImpl); mWifiServiceImpl.enableVerboseLogging(1); + verify(mWifiSettingsConfigStore, never()).putBoolean( + WIFI_VERBOSE_LOGGING_ENABLED, anyBoolean()); verify(mClientModeImpl, never()).enableVerboseLogging(anyInt()); } @@ -5036,7 +5044,6 @@ public class WifiServiceImplTest extends WifiBaseTest { mWifiServiceImpl.handleBootCompleted(); mLooper.dispatchAll(); - verify(mWifiConfigManager).loadFromStore(); verify(mPasspointManager).initializeProvisioner(any()); verify(mClientModeImpl).handleBootCompleted(); } @@ -5580,4 +5587,29 @@ public class WifiServiceImplTest extends WifiBaseTest { mLooper.stopAutoDispatchAndIgnoreExceptions(); verify(mWakeupController).isEnabled(); } + + @Test + public void testSetScanAlwaysAvailableWithNetworkSettingsPermission() { + doNothing().when(mContext) + .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + eq("WifiService")); + mWifiServiceImpl.setScanAlwaysAvailable(true); + verify(mSettingsStore).handleWifiScanAlwaysAvailableToggled(true); + verify(mActiveModeWarden).scanAlwaysModeChanged(); + + mWifiServiceImpl.setScanAlwaysAvailable(false); + verify(mSettingsStore).handleWifiScanAlwaysAvailableToggled(false); + verify(mActiveModeWarden, times(2)).scanAlwaysModeChanged(); + } + + @Test(expected = SecurityException.class) + public void testSetScanAlwaysAvailableWithNoNetworkSettingsPermission() { + doThrow(new SecurityException()).when(mContext) + .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), + eq("WifiService")); + + mWifiServiceImpl.setScanAlwaysAvailable(true); + verify(mSettingsStore, never()).handleWifiScanAlwaysAvailableToggled(anyBoolean()); + verify(mActiveModeWarden, never()).scanAlwaysModeChanged(); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiSettingsConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiSettingsConfigStoreTest.java new file mode 100644 index 000000000..22cb7f435 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/WifiSettingsConfigStoreTest.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +package com.android.server.wifi; + +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.validateMockitoUsage; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.os.Handler; +import android.os.test.TestLooper; +import android.util.Xml; + +import androidx.test.filters.SmallTest; + +import com.android.internal.util.FastXmlSerializer; +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.HashMap; +import java.util.Map; + + +/** + * Unit tests for {@link com.android.server.wifi.WifiSettingsConfigStore}. + */ +@SmallTest +public class WifiSettingsConfigStoreTest extends WifiBaseTest { + @Mock + private Context mContext; + @Mock + private WifiConfigStore mWifiConfigStore; + @Mock + private WifiConfigManager mWifiConfigManager; + + private TestLooper mLooper; + private WifiSettingsConfigStore mWifiSettingsConfigStore; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mLooper = new TestLooper(); + mWifiSettingsConfigStore = + new WifiSettingsConfigStore(mContext, new Handler(mLooper.getLooper()), + mWifiConfigManager, mWifiConfigStore); + } + + /** + * Called after each test + */ + @After + public void cleanup() { + validateMockitoUsage(); + } + + @Test + public void testSetterGetter() { + assertFalse(mWifiSettingsConfigStore.getBoolean(WIFI_VERBOSE_LOGGING_ENABLED, false)); + mWifiSettingsConfigStore.putBoolean(WIFI_VERBOSE_LOGGING_ENABLED, true); + mLooper.dispatchAll(); + assertTrue(mWifiSettingsConfigStore.getBoolean(WIFI_VERBOSE_LOGGING_ENABLED, false)); + verify(mWifiConfigManager).saveToStore(true); + } + + @Test + public void testChangeListener() { + WifiSettingsConfigStore.OnSettingsChangedListener listener = mock( + WifiSettingsConfigStore.OnSettingsChangedListener.class); + mWifiSettingsConfigStore.registerChangeListener(WIFI_VERBOSE_LOGGING_ENABLED, listener, + new Handler(mLooper.getLooper())); + + mWifiSettingsConfigStore.putBoolean(WIFI_VERBOSE_LOGGING_ENABLED, true); + mLooper.dispatchAll(); + + verify(listener).onSettingsChanged(WIFI_VERBOSE_LOGGING_ENABLED, true); + } + + @Test + public void testSaveAndLoadFromStore() throws Exception { + ArgumentCaptor<WifiConfigStore.StoreData> storeDataCaptor = ArgumentCaptor.forClass( + WifiConfigStore.StoreData.class); + verify(mWifiConfigStore).registerStoreData(storeDataCaptor.capture()); + assertNotNull(storeDataCaptor.getValue()); + + XmlPullParser in = createSettingsTestXmlForParsing(WIFI_VERBOSE_LOGGING_ENABLED, true); + + storeDataCaptor.getValue().resetData(); + storeDataCaptor.getValue().deserializeData(in, in.getDepth(), -1, null); + + assertTrue(mWifiSettingsConfigStore.getBoolean(WIFI_VERBOSE_LOGGING_ENABLED, false)); + } + + private XmlPullParser createSettingsTestXmlForParsing(String key, Object value) + throws Exception { + Map<String, Object> settings = new HashMap<>(); + // Serialize + settings.put(key, value); + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, "Test"); + XmlUtil.writeNextValue(out, "Values", settings); + XmlUtil.writeDocumentEnd(out, "Test"); + + // Start Deserializing + final XmlPullParser in = Xml.newPullParser(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + in.setInput(inputStream, StandardCharsets.UTF_8.name()); + XmlUtil.gotoDocumentStart(in, "Test"); + return in; + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java index 3e4089056..9675ad89a 100644 --- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java @@ -19,11 +19,9 @@ package com.android.server.wifi.aware; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -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.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; @@ -51,8 +49,8 @@ import android.util.SparseIntArray; import androidx.test.filters.SmallTest; -import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.WifiBaseTest; +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; @@ -103,7 +101,7 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { @Mock private WifiPermissionsUtil mWifiPermissionsUtil; @Mock private WifiPermissionsWrapper mPermissionsWrapperMock; @Mock - FrameworkFacade mFrameworkFacade; + WifiSettingsConfigStore mWifiSettingsConfigStore; /** * Using instead of spy to avoid native crash failures - possibly due to @@ -135,8 +133,6 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { mMockLooper = new TestLooper(); when(mHandlerThreadMock.getLooper()).thenReturn(mMockLooper.getLooper()); - doNothing().when(mFrameworkFacade).registerContentObserver(eq(mContextMock), any(), - anyBoolean(), any()); AppOpsManager appOpsMock = mock(AppOpsManager.class); when(mContextMock.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(appOpsMock); @@ -152,7 +148,8 @@ public class WifiAwareServiceImplTest extends WifiBaseTest { mDut = new WifiAwareServiceImplSpy(mContextMock); mDut.fakeUid = mDefaultUid; mDut.start(mHandlerThreadMock, mAwareStateManagerMock, mWifiAwareShellCommandMock, - mAwareMetricsMock, mWifiPermissionsUtil, mPermissionsWrapperMock, mFrameworkFacade, + mAwareMetricsMock, mWifiPermissionsUtil, mPermissionsWrapperMock, + mWifiSettingsConfigStore, mock(WifiAwareNativeManager.class), mock(WifiAwareNativeApi.class), mock(WifiAwareNativeCallback.class), mock(NetdWrapper.class)); mMockLooper.dispatchAll(); diff --git a/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java index 5f22974a4..adfa025ca 100644 --- a/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java @@ -16,6 +16,9 @@ package com.android.server.wifi.p2p; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_DEVICE_NAME; +import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_P2P_PENDING_FACTORY_RESET; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; @@ -70,7 +73,6 @@ import android.os.Messenger; import android.os.UserHandle; import android.os.UserManager; import android.os.test.TestLooper; -import android.provider.Settings; import androidx.test.filters.SmallTest; @@ -79,6 +81,7 @@ import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.HalDeviceManager; import com.android.server.wifi.WifiBaseTest; import com.android.server.wifi.WifiInjector; +import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.proto.nano.WifiMetricsProto.P2pConnectionEvent; import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiPermissionsUtil; @@ -141,6 +144,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { @Mock WifiInjector mWifiInjector; @Mock WifiManager mMockWifiManager; @Mock WifiPermissionsUtil mWifiPermissionsUtil; + @Mock WifiSettingsConfigStore mWifiSettingsConfigStore; @Mock WifiPermissionsWrapper mWifiPermissionsWrapper; @Mock WifiP2pNative mWifiNative; @Mock WifiP2pServiceInfo mTestWifiP2pServiceInfo; @@ -706,10 +710,10 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getResources()).thenReturn(mResources); - when(mFrameworkFacade.getStringSetting(any(), - eq(Settings.Global.WIFI_P2P_DEVICE_NAME))).thenReturn(thisDeviceName); - when(mFrameworkFacade.getIntegerSetting(any(), - eq(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET), eq(0))).thenReturn(0); + when(mWifiSettingsConfigStore.getString(eq(WIFI_P2P_DEVICE_NAME), any())) + .thenReturn(thisDeviceName); + when(mWifiSettingsConfigStore.getBoolean( + eq(WIFI_P2P_PENDING_FACTORY_RESET), eq(false))).thenReturn(false); when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); if (supported) { when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_WIFI_DIRECT))) @@ -727,6 +731,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { when(mWifiInjector.getWifiP2pNative()).thenReturn(mWifiNative); when(mWifiInjector.getWifiP2pServiceHandlerThread()).thenReturn(mHandlerThread); when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil); + when(mWifiInjector.getSettingsConfigStore()).thenReturn(mWifiSettingsConfigStore); // enable all permissions, disable specific permissions in tests when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); when(mWifiPermissionsUtil.checkNetworkStackPermission(anyInt())).thenReturn(true); @@ -2723,13 +2728,11 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { mTestThisDevice.deviceName = "another-name"; when(mWifiNative.setDeviceName(anyString())).thenReturn(true); - when(mFrameworkFacade.setStringSetting( - any(), eq(Settings.Global.WIFI_P2P_DEVICE_NAME), anyString())).thenReturn(true); sendSetDeviceNameMsg(mClientMessenger, mTestThisDevice); verify(mWifiNative).setDeviceName(eq(mTestThisDevice.deviceName)); verify(mWifiNative).setP2pSsidPostfix(eq("-" + mTestThisDevice.deviceName)); - verify(mFrameworkFacade).setStringSetting(eq(mContext), - eq(Settings.Global.WIFI_P2P_DEVICE_NAME), eq(mTestThisDevice.deviceName)); + verify(mWifiSettingsConfigStore).putString( + eq(WIFI_P2P_DEVICE_NAME), eq(mTestThisDevice.deviceName)); checkSendThisDeviceChangedBroadcast(); verify(mClientHandler).sendMessage(mMessageCaptor.capture()); Message message = mMessageCaptor.getValue(); @@ -3172,8 +3175,7 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { eq(UserManager.DISALLOW_NETWORK_RESET), any()); verify(mUserManager).hasUserRestrictionForUser(eq(UserManager.DISALLOW_CONFIG_WIFI), any()); verify(mWifiNative, atLeastOnce()).p2pListNetworks(any()); - verify(mFrameworkFacade).setIntegerSetting(eq(mContext), - eq(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET), eq(0)); + verify(mWifiSettingsConfigStore).putBoolean(eq(WIFI_P2P_PENDING_FACTORY_RESET), eq(false)); verify(mClientHandler).sendMessage(mMessageCaptor.capture()); Message message = mMessageCaptor.getValue(); assertEquals(WifiP2pManager.FACTORY_RESET_SUCCEEDED, message.what); @@ -3201,15 +3203,14 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { eq(UserManager.DISALLOW_NETWORK_RESET), any()); verify(mUserManager).hasUserRestrictionForUser(eq(UserManager.DISALLOW_CONFIG_WIFI), any()); verify(mWifiNative, never()).p2pListNetworks(any()); - verify(mFrameworkFacade).setIntegerSetting(eq(mContext), - eq(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET), eq(1)); + verify(mWifiSettingsConfigStore).putBoolean(eq(WIFI_P2P_PENDING_FACTORY_RESET), eq(true)); verify(mClientHandler).sendMessage(mMessageCaptor.capture()); Message message = mMessageCaptor.getValue(); assertEquals(WifiP2pManager.FACTORY_RESET_SUCCEEDED, message.what); // Move to enabled state - when(mFrameworkFacade.getIntegerSetting(eq(mContext), - eq(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET), anyInt())).thenReturn(1); + when(mWifiSettingsConfigStore.getBoolean( + eq(WIFI_P2P_PENDING_FACTORY_RESET), eq(false))).thenReturn(true); forceP2pEnabled(mClient1); verify(mWifiInjector, times(2)).getUserManager(); verify(mPackageManager, times(2)).getNameForUid(anyInt()); @@ -3219,10 +3220,8 @@ public class WifiP2pServiceImplTest extends WifiBaseTest { verify(mUserManager, times(2)).hasUserRestrictionForUser( eq(UserManager.DISALLOW_CONFIG_WIFI), any()); verify(mWifiNative, atLeastOnce()).p2pListNetworks(any()); - verify(mFrameworkFacade).getIntegerSetting(eq(mContext), - eq(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET), eq(0)); - verify(mFrameworkFacade).setIntegerSetting(eq(mContext), - eq(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET), eq(0)); + verify(mWifiSettingsConfigStore).getBoolean(eq(WIFI_P2P_PENDING_FACTORY_RESET), eq(false)); + verify(mWifiSettingsConfigStore).putBoolean(eq(WIFI_P2P_PENDING_FACTORY_RESET), eq(false)); checkSendP2pPersistentGroupsChangedBroadcast(); } diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java index e5c922d5a..ec08f4100 100644 --- a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java @@ -31,7 +31,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -72,9 +71,9 @@ import android.util.Pair; import androidx.test.filters.SmallTest; import com.android.server.wifi.Clock; -import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.MockResources; import com.android.server.wifi.WifiBaseTest; +import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.proto.nano.WifiMetricsProto; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.wifi.resources.R; @@ -156,7 +155,7 @@ public class RttServiceImplTest extends WifiBaseTest { public IRttCallback mockCallback; @Mock - FrameworkFacade mFrameworkFacade; + WifiSettingsConfigStore mWifiSettingsConfigStore; /** * Using instead of spy to avoid native crash failures - possibly due to @@ -196,8 +195,6 @@ public class RttServiceImplTest extends WifiBaseTest { R.integer.config_wifiRttBackgroundExecGapMs, BACKGROUND_PROCESS_EXEC_GAP_MS); mAlarmManager = new TestAlarmManager(); - doNothing().when(mFrameworkFacade).registerContentObserver(eq(mockContext), any(), - anyBoolean(), any()); when(mockContext.getSystemService(Context.ALARM_SERVICE)) .thenReturn(mAlarmManager.getAlarmManager()); mInOrder = inOrder(mAlarmManager.getAlarmManager(), mockContext); @@ -225,7 +222,7 @@ public class RttServiceImplTest extends WifiBaseTest { doAnswer(mBinderUnlinkToDeathCounter).when(mockIbinder).unlinkToDeath(any(), anyInt()); mDut.start(mMockLooper.getLooper(), mockClock, mockAwareManager, mockNative, - mockMetrics, mockPermissionUtil, mFrameworkFacade); + mockMetrics, mockPermissionUtil, mWifiSettingsConfigStore); mMockLooper.dispatchAll(); ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = ArgumentCaptor.forClass( BroadcastReceiver.class); |