1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Context; 22 import android.net.wifi.WifiManager; 23 import android.net.wifi.WifiMigration; 24 import android.os.Handler; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import com.android.internal.annotations.GuardedBy; 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.server.wifi.util.SettingsMigrationDataHolder; 31 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 32 import com.android.server.wifi.util.XmlUtil; 33 34 import org.xmlpull.v1.XmlPullParser; 35 import org.xmlpull.v1.XmlPullParserException; 36 import org.xmlpull.v1.XmlSerializer; 37 38 import java.io.FileDescriptor; 39 import java.io.IOException; 40 import java.io.PrintWriter; 41 import java.util.ArrayList; 42 import java.util.HashMap; 43 import java.util.List; 44 import java.util.Map; 45 import java.util.Objects; 46 47 /** 48 * Store data for storing wifi settings. These are key (string) / value pairs that are stored in 49 * WifiConfigStore.xml file in a separate section. 50 */ 51 public class WifiSettingsConfigStore { 52 private static final String TAG = "WifiSettingsConfigStore"; 53 54 // List of all allowed keys. 55 private static final ArrayList<Key> sKeys = new ArrayList<>(); 56 57 /******** Wifi shared pref keys ***************/ 58 /** 59 * Indicate whether factory reset request is pending. 60 */ 61 public static final Key<Boolean> WIFI_P2P_PENDING_FACTORY_RESET = 62 new Key<>("wifi_p2p_pending_factory_reset", false); 63 64 /** 65 * Allow scans to be enabled even wifi is turned off. 66 */ 67 public static final Key<Boolean> WIFI_SCAN_ALWAYS_AVAILABLE = 68 new Key<>("wifi_scan_always_enabled", false); 69 70 /** 71 * Whether wifi scan throttle is enabled or not. 72 */ 73 public static final Key<Boolean> WIFI_SCAN_THROTTLE_ENABLED = 74 new Key<>("wifi_scan_throttle_enabled", true); 75 76 /** 77 * Setting to enable verbose logging in Wi-Fi. 78 */ 79 public static final Key<Boolean> WIFI_VERBOSE_LOGGING_ENABLED = 80 new Key<>("wifi_verbose_logging_enabled", false); 81 82 /** 83 * Setting to enable verbose logging in Wi-Fi Aware. 84 */ 85 public static final Key<Boolean> WIFI_AWARE_VERBOSE_LOGGING_ENABLED = 86 new Key<>("wifi_aware_verbose_logging_enabled", false); 87 88 /** 89 * The Wi-Fi peer-to-peer device name 90 */ 91 public static final Key<String> WIFI_P2P_DEVICE_NAME = 92 new Key<>("wifi_p2p_device_name", null); 93 94 /** 95 * The Wi-Fi peer-to-peer device mac address 96 */ 97 public static final Key<String> WIFI_P2P_DEVICE_ADDRESS = 98 new Key<>("wifi_p2p_device_address", null); 99 100 /** 101 * Whether Wifi scoring is enabled or not. 102 */ 103 public static final Key<Boolean> WIFI_SCORING_ENABLED = 104 new Key<>("wifi_scoring_enabled", true); 105 106 /** 107 * Whether Wifi Passpoint is enabled or not. 108 */ 109 public static final Key<Boolean> WIFI_PASSPOINT_ENABLED = 110 new Key<>("wifi_passpoint_enabled", true); 111 112 /** 113 * Whether Wifi Multi Internet is enabled for multi ap, dbs or disabled. 114 */ 115 public static final Key<Integer> WIFI_MULTI_INTERNET_MODE = 116 new Key<Integer>("wifi_multi_internet_mode", 117 WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED); 118 119 /** 120 * Store the STA factory MAC address retrieved from the driver on the first bootup. 121 */ 122 public static final Key<String> WIFI_STA_FACTORY_MAC_ADDRESS = 123 new Key<>("wifi_sta_factory_mac_address", null); 124 125 /** 126 * Store the Secondary STA factory MAC address retrieved from the driver on the first bootup. 127 */ 128 public static final Key<String> SECONDARY_WIFI_STA_FACTORY_MAC_ADDRESS = 129 new Key<>("secondary_wifi_sta_factory_mac_address", null); 130 131 132 /** 133 * Store the default country code updated via {@link WifiManager#setDefaultCountryCode(String)} 134 */ 135 public static final Key<String> WIFI_DEFAULT_COUNTRY_CODE = 136 new Key<>("wifi_default_country_code", WifiCountryCode.getOemDefaultCountryCode()); 137 138 /** 139 * Store the supported features retrieved from WiFi HAL and Supplicant HAL 140 */ 141 public static final Key<Long> WIFI_NATIVE_SUPPORTED_FEATURES = 142 new Key<>("wifi_native_supported_features", 0L); 143 144 /** 145 * Store the supported features retrieved from WiFi HAL and Supplicant HAL 146 */ 147 public static final Key<Integer> WIFI_NATIVE_SUPPORTED_STA_BANDS = 148 new Key<>("wifi_native_supported_sta_bands", 0); 149 150 /** 151 * Store the static chip info retrieved from WiFi HAL 152 */ 153 public static final Key<String> WIFI_STATIC_CHIP_INFO = new Key<>("wifi_static_chip_info", ""); 154 155 /** 156 * Store the last country code used by Soft AP. 157 */ 158 public static final Key<String> WIFI_SOFT_AP_COUNTRY_CODE = 159 new Key<>("wifi_last_country_code", ""); 160 161 /** 162 * Store the available channel frequencies in a JSON array for Soft AP for the last country 163 * code used. 164 */ 165 public static final Key<String> WIFI_AVAILABLE_SOFT_AP_FREQS_MHZ = 166 new Key<>("wifi_available_soft_ap_freqs_mhz", "[]"); 167 168 /** 169 * Whether to show a dialog when third party apps attempt to enable wifi. 170 */ 171 public static final Key<Boolean> SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI = 172 new Key<>("show_dialog_when_third_party_apps_enable_wifi", false); 173 174 /** 175 * Whether the 176 * {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)} API was 177 * called to set the value of {@link #SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI}. 178 */ 179 public static final Key<Boolean> SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI_SET_BY_API = 180 new Key<>("show_dialog_when_third_party_apps_enable_wifi_set_by_api", false); 181 182 /** 183 * AIDL version implemented by the Supplicant service. 184 */ 185 public static final Key<Integer> SUPPLICANT_HAL_AIDL_SERVICE_VERSION = 186 new Key<>("supplicant_hal_aidl_service_version", -1); 187 188 /** 189 * Whether the WEP network is allowed or not. 190 */ 191 public static final Key<Boolean> WIFI_WEP_ALLOWED = new Key<>("wep_allowed", true); 192 193 /** 194 * Store wiphy capability for 11be support. 195 */ 196 public static final Key<Boolean> WIFI_WIPHY_11BE_SUPPORTED = 197 new Key<>("wifi_wiphy_11be_supported", true); 198 199 /** 200 * Whether the D2D is allowed or not when infra sta is disabled. 201 */ 202 public static final Key<Boolean> D2D_ALLOWED_WHEN_INFRA_STA_DISABLED = 203 new Key<>("d2d_allowed_when_infra_sta_disabled", false); 204 205 // List of all keys which require to backup and restore. 206 private static final List<Key> sBackupRestoreKeys = List.of( 207 WIFI_WEP_ALLOWED, 208 D2D_ALLOWED_WHEN_INFRA_STA_DISABLED); 209 /******** Wifi shared pref keys ***************/ 210 211 private final Context mContext; 212 private final Handler mHandler; 213 private final SettingsMigrationDataHolder mSettingsMigrationDataHolder; 214 private final WifiConfigManager mWifiConfigManager; 215 216 private final Object mLock = new Object(); 217 @GuardedBy("mLock") 218 private final Map<String, Object> mSettings = new HashMap<>(); 219 @GuardedBy("mLock") 220 private final Map<String, Map<OnSettingsChangedListener, Handler>> mListeners = 221 new HashMap<>(); 222 private WifiMigration.SettingsMigrationData mCachedMigrationData = null; 223 224 private boolean mHasNewDataToSerialize = false; 225 226 /** 227 * Interface for a settings change listener. 228 * @param <T> Type of the value. 229 */ 230 public interface OnSettingsChangedListener<T> { 231 /** 232 * Invoked when a particular key settings changes. 233 * 234 * @param key Key that was changed. 235 * @param newValue New value that was assigned to the key. 236 */ onSettingsChanged(@onNull Key<T> key, @Nullable T newValue)237 void onSettingsChanged(@NonNull Key<T> key, @Nullable T newValue); 238 } 239 WifiSettingsConfigStore(@onNull Context context, @NonNull Handler handler, @NonNull SettingsMigrationDataHolder settingsMigrationDataHolder, @NonNull WifiConfigManager wifiConfigManager, @NonNull WifiConfigStore wifiConfigStore)240 public WifiSettingsConfigStore(@NonNull Context context, @NonNull Handler handler, 241 @NonNull SettingsMigrationDataHolder settingsMigrationDataHolder, 242 @NonNull WifiConfigManager wifiConfigManager, 243 @NonNull WifiConfigStore wifiConfigStore) { 244 mContext = context; 245 mHandler = handler; 246 mSettingsMigrationDataHolder = settingsMigrationDataHolder; 247 mWifiConfigManager = wifiConfigManager; 248 249 // Register our data store. 250 wifiConfigStore.registerStoreData(new StoreData()); 251 } 252 getAllKeys()253 public ArrayList<Key> getAllKeys() { 254 return sKeys; 255 } 256 getAllBackupRestoreKeys()257 public List<Key> getAllBackupRestoreKeys() { 258 return sBackupRestoreKeys; 259 } 260 invokeAllListeners()261 private void invokeAllListeners() { 262 synchronized (mLock) { 263 for (Key key : sKeys) { 264 invokeListeners(key); 265 } 266 } 267 } 268 invokeListeners(@onNull Key<T> key)269 private <T> void invokeListeners(@NonNull Key<T> key) { 270 synchronized (mLock) { 271 if (!mSettings.containsKey(key.key)) return; 272 Object newValue = mSettings.get(key.key); 273 Map<OnSettingsChangedListener, Handler> listeners = mListeners.get(key.key); 274 if (listeners == null || listeners.isEmpty()) return; 275 for (Map.Entry<OnSettingsChangedListener, Handler> listener 276 : listeners.entrySet()) { 277 // Trigger the callback in the appropriate handler. 278 listener.getValue().post(() -> 279 listener.getKey().onSettingsChanged(key, newValue)); 280 } 281 } 282 } 283 284 /** 285 * Trigger config store writes and invoke listeners in the main wifi service looper's handler. 286 */ triggerSaveToStoreAndInvokeAllListeners()287 private void triggerSaveToStoreAndInvokeAllListeners() { 288 mHandler.post(() -> { 289 mHasNewDataToSerialize = true; 290 mWifiConfigManager.saveToStore(); 291 292 invokeAllListeners(); 293 }); 294 } 295 296 /** 297 * Trigger config store writes and invoke listeners in the main wifi service looper's handler. 298 */ triggerSaveToStoreAndInvokeListeners(@onNull Key<T> key)299 private <T> void triggerSaveToStoreAndInvokeListeners(@NonNull Key<T> key) { 300 mHandler.post(() -> { 301 mHasNewDataToSerialize = true; 302 mWifiConfigManager.saveToStore(); 303 304 invokeListeners(key); 305 }); 306 } 307 308 /** 309 * Performs a one time migration from Settings.Global values to settings store. Only 310 * performed one time if the settings store is empty. 311 */ migrateFromSettingsIfNeeded()312 private void migrateFromSettingsIfNeeded() { 313 if (!mSettings.isEmpty()) return; // already migrated. 314 315 mCachedMigrationData = mSettingsMigrationDataHolder.retrieveData(); 316 if (mCachedMigrationData == null) { 317 Log.e(TAG, "No settings data to migrate"); 318 return; 319 } 320 Log.i(TAG, "Migrating data out of settings to shared preferences"); 321 322 mSettings.put(WIFI_P2P_DEVICE_NAME.key, 323 mCachedMigrationData.getP2pDeviceName()); 324 mSettings.put(WIFI_P2P_PENDING_FACTORY_RESET.key, 325 mCachedMigrationData.isP2pFactoryResetPending()); 326 mSettings.put(WIFI_SCAN_ALWAYS_AVAILABLE.key, 327 mCachedMigrationData.isScanAlwaysAvailable()); 328 mSettings.put(WIFI_SCAN_THROTTLE_ENABLED.key, 329 mCachedMigrationData.isScanThrottleEnabled()); 330 mSettings.put(WIFI_VERBOSE_LOGGING_ENABLED.key, 331 mCachedMigrationData.isVerboseLoggingEnabled()); 332 triggerSaveToStoreAndInvokeAllListeners(); 333 } 334 335 /** 336 * Store a value to the stored settings. 337 * 338 * @param key One of the settings keys. 339 * @param value Value to be stored. 340 */ put(@onNull Key<T> key, @Nullable T value)341 public <T> void put(@NonNull Key<T> key, @Nullable T value) { 342 synchronized (mLock) { 343 mSettings.put(key.key, value); 344 } 345 triggerSaveToStoreAndInvokeListeners(key); 346 } 347 348 /** 349 * Retrieve a value from the stored settings. 350 * 351 * @param key One of the settings keys. 352 * @return value stored in settings, defValue if the key does not exist. 353 */ get(@onNull Key<T> key)354 public @Nullable <T> T get(@NonNull Key<T> key) { 355 synchronized (mLock) { 356 return (T) mSettings.getOrDefault(key.key, key.defaultValue); 357 } 358 } 359 360 /** 361 * Register for settings change listener. 362 * 363 * @param key One of the settings keys. 364 * @param listener Listener to be registered. 365 * @param handler Handler to post the listener 366 */ registerChangeListener(@onNull Key<T> key, @NonNull OnSettingsChangedListener<T> listener, @NonNull Handler handler)367 public <T> void registerChangeListener(@NonNull Key<T> key, 368 @NonNull OnSettingsChangedListener<T> listener, @NonNull Handler handler) { 369 synchronized (mLock) { 370 mListeners.computeIfAbsent( 371 key.key, ignore -> new HashMap<>()).put(listener, handler); 372 } 373 } 374 375 /** 376 * Unregister for settings change listener. 377 * 378 * @param key One of the settings keys. 379 * @param listener Listener to be unregistered. 380 */ unregisterChangeListener(@onNull Key<T> key, @NonNull OnSettingsChangedListener<T> listener)381 public <T> void unregisterChangeListener(@NonNull Key<T> key, 382 @NonNull OnSettingsChangedListener<T> listener) { 383 synchronized (mLock) { 384 Map<OnSettingsChangedListener, Handler> listeners = mListeners.get(key.key); 385 if (listeners == null || listeners.isEmpty()) { 386 Log.e(TAG, "No listeners for " + key); 387 return; 388 } 389 if (listeners.remove(listener) == null) { 390 Log.e(TAG, "Unknown listener for " + key); 391 } 392 } 393 } 394 395 /** 396 * Dump output for debugging. 397 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)398 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 399 pw.println(); 400 pw.println("Dump of " + TAG); 401 pw.println("Settings:"); 402 for (Map.Entry<String, Object> entry : mSettings.entrySet()) { 403 pw.print(entry.getKey()); 404 pw.print("="); 405 pw.println(entry.getValue()); 406 } 407 if (mCachedMigrationData == null) return; 408 pw.println("Migration data:"); 409 pw.print(WIFI_P2P_DEVICE_NAME.key); 410 pw.print("="); 411 pw.println(mCachedMigrationData.getP2pDeviceName()); 412 pw.print(WIFI_P2P_PENDING_FACTORY_RESET.key); 413 pw.print("="); 414 pw.println(mCachedMigrationData.isP2pFactoryResetPending()); 415 pw.print(WIFI_SCAN_ALWAYS_AVAILABLE.key); 416 pw.print("="); 417 pw.println(mCachedMigrationData.isScanAlwaysAvailable()); 418 pw.print(WIFI_SCAN_THROTTLE_ENABLED.key); 419 pw.print("="); 420 pw.println(mCachedMigrationData.isScanThrottleEnabled()); 421 pw.print(WIFI_VERBOSE_LOGGING_ENABLED.key); 422 pw.print("="); 423 pw.println(mCachedMigrationData.isVerboseLoggingEnabled()); 424 pw.println(); 425 } 426 427 /** 428 * Base class to store string key and its default value. 429 * @param <T> Type of the value. 430 */ 431 public static class Key<T> { 432 public final String key; 433 public final T defaultValue; 434 Key(@onNull String key, T defaultValue)435 private Key(@NonNull String key, T defaultValue) { 436 this.key = key; 437 this.defaultValue = defaultValue; 438 sKeys.add(this); 439 } 440 441 @VisibleForTesting getKey()442 public String getKey() { 443 return key; 444 } 445 446 @Override toString()447 public String toString() { 448 return "[Key " + key + ", DefaultValue: " + defaultValue + "]"; 449 } 450 451 @Override equals(Object o)452 public boolean equals(Object o) { 453 if (o == this) { 454 return true; 455 } 456 457 // null instanceof [type]" also returns false 458 if (!(o instanceof Key)) { 459 return false; 460 } 461 462 Key anotherKey = (Key) o; 463 return Objects.equals(key, anotherKey.key) 464 && Objects.equals(defaultValue, anotherKey.defaultValue); 465 } 466 467 @Override hashCode()468 public int hashCode() { 469 return Objects.hash(key, defaultValue); 470 } 471 } 472 473 /** 474 * Store data for persisting the settings data to config store. 475 */ 476 public class StoreData implements WifiConfigStore.StoreData { 477 public static final String XML_TAG_SECTION_HEADER = "Settings"; 478 public static final String XML_TAG_VALUES = "Values"; 479 480 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)481 public void serializeData(XmlSerializer out, 482 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 483 throws XmlPullParserException, IOException { 484 synchronized (mLock) { 485 XmlUtil.writeNextValue(out, XML_TAG_VALUES, mSettings); 486 } 487 } 488 489 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)490 public void deserializeData(XmlPullParser in, int outerTagDepth, 491 @WifiConfigStore.Version int version, 492 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 493 throws XmlPullParserException, IOException { 494 if (in == null) { 495 // Empty read triggers the migration since it indicates that there is no settings 496 // data stored in the settings store. 497 migrateFromSettingsIfNeeded(); 498 return; 499 } 500 Map<String, Object> values = deserializeSettingsData(in, outerTagDepth); 501 if (values != null) { 502 synchronized (mLock) { 503 mSettings.putAll(values); 504 // Invoke all the registered listeners. 505 invokeAllListeners(); 506 } 507 } 508 } 509 510 /** 511 * Parse out the wifi settings from the input xml stream. 512 */ deserializeSettingsData( XmlPullParser in, int outerTagDepth)513 public static Map<String, Object> deserializeSettingsData( 514 XmlPullParser in, int outerTagDepth) 515 throws XmlPullParserException, IOException { 516 Map<String, Object> values = null; 517 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 518 String[] valueName = new String[1]; 519 Object value = XmlUtil.readCurrentValue(in, valueName); 520 if (TextUtils.isEmpty(valueName[0])) { 521 throw new XmlPullParserException("Missing value name"); 522 } 523 switch (valueName[0]) { 524 case XML_TAG_VALUES: 525 values = (Map) value; 526 break; 527 default: 528 Log.w(TAG, "Ignoring unknown tag under " + XML_TAG_SECTION_HEADER + ": " 529 + valueName[0]); 530 break; 531 } 532 } 533 return values; 534 } 535 536 @Override resetData()537 public void resetData() { 538 synchronized (mLock) { 539 mSettings.clear(); 540 } 541 } 542 543 @Override hasNewDataToSerialize()544 public boolean hasNewDataToSerialize() { 545 return mHasNewDataToSerialize; 546 } 547 548 @Override getName()549 public String getName() { 550 return XML_TAG_SECTION_HEADER; 551 } 552 553 @Override getStoreFileId()554 public @WifiConfigStore.StoreFileId int getStoreFileId() { 555 // Shared general store. 556 return WifiConfigStore.STORE_FILE_SHARED_GENERAL; 557 } 558 } 559 } 560