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 P2P features. 140 */ 141 public static final Key<Long> WIFI_P2P_SUPPORTED_FEATURES = 142 new Key<>("wifi_p2p_supported_features", 0L); 143 144 /** 145 * Store the supported features retrieved from WiFi HAL and Supplicant HAL. Note that this 146 * value is deprecated and is replaced by {@link #WIFI_NATIVE_EXTENDED_SUPPORTED_FEATURES} 147 */ 148 public static final Key<Long> WIFI_NATIVE_SUPPORTED_FEATURES = 149 new Key<>("wifi_native_supported_features", 0L); 150 151 /** 152 * Store the extended supported features retrieved from WiFi HAL and Supplicant HAL 153 */ 154 public static final Key<long[]> WIFI_NATIVE_EXTENDED_SUPPORTED_FEATURES = 155 new Key<>("wifi_native_extended_supported_features", new long[0]); 156 157 /** 158 * Store the supported features retrieved from WiFi HAL and Supplicant HAL 159 */ 160 public static final Key<Integer> WIFI_NATIVE_SUPPORTED_STA_BANDS = 161 new Key<>("wifi_native_supported_sta_bands", 0); 162 163 /** 164 * Store the static chip info retrieved from WiFi HAL 165 */ 166 public static final Key<String> WIFI_STATIC_CHIP_INFO = new Key<>("wifi_static_chip_info", ""); 167 168 /** 169 * Store the last country code used by Soft AP. 170 */ 171 public static final Key<String> WIFI_SOFT_AP_COUNTRY_CODE = 172 new Key<>("wifi_last_country_code", ""); 173 174 /** 175 * Store the available channel frequencies in a JSON array for Soft AP for the last country 176 * code used. 177 */ 178 public static final Key<String> WIFI_AVAILABLE_SOFT_AP_FREQS_MHZ = 179 new Key<>("wifi_available_soft_ap_freqs_mhz", "[]"); 180 181 /** 182 * Whether to show a dialog when third party apps attempt to enable wifi. 183 */ 184 public static final Key<Boolean> SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI = 185 new Key<>("show_dialog_when_third_party_apps_enable_wifi", false); 186 187 /** 188 * Whether the 189 * {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)} API was 190 * called to set the value of {@link #SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI}. 191 */ 192 public static final Key<Boolean> SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI_SET_BY_API = 193 new Key<>("show_dialog_when_third_party_apps_enable_wifi_set_by_api", false); 194 195 /** 196 * AIDL version implemented by the Supplicant service. 197 */ 198 public static final Key<Integer> SUPPLICANT_HAL_AIDL_SERVICE_VERSION = 199 new Key<>("supplicant_hal_aidl_service_version", -1); 200 201 /** 202 * Whether the WEP network is allowed or not. 203 */ 204 public static final Key<Boolean> WIFI_WEP_ALLOWED = new Key<>("wep_allowed", true); 205 206 /** 207 * Store wiphy capability for 11be support. 208 */ 209 public static final Key<Boolean> WIFI_WIPHY_11BE_SUPPORTED = 210 new Key<>("wifi_wiphy_11be_supported", true); 211 212 /** 213 * Whether the D2D is allowed or not when infra sta is disabled. 214 */ 215 public static final Key<Boolean> D2D_ALLOWED_WHEN_INFRA_STA_DISABLED = 216 new Key<>("d2d_allowed_when_infra_sta_disabled", false); 217 218 // List of all keys which require to backup and restore. 219 private static final List<Key> sBackupRestoreKeys = List.of( 220 WIFI_WEP_ALLOWED, 221 D2D_ALLOWED_WHEN_INFRA_STA_DISABLED); 222 /******** Wifi shared pref keys ***************/ 223 224 private final Context mContext; 225 private final Handler mHandler; 226 private final SettingsMigrationDataHolder mSettingsMigrationDataHolder; 227 private final WifiConfigManager mWifiConfigManager; 228 229 private final Object mLock = new Object(); 230 @GuardedBy("mLock") 231 private final Map<String, Object> mSettings = new HashMap<>(); 232 @GuardedBy("mLock") 233 private final Map<String, Map<OnSettingsChangedListener, Handler>> mListeners = 234 new HashMap<>(); 235 private WifiMigration.SettingsMigrationData mCachedMigrationData = null; 236 237 private boolean mHasNewDataToSerialize = false; 238 239 /** 240 * Interface for a settings change listener. 241 * @param <T> Type of the value. 242 */ 243 public interface OnSettingsChangedListener<T> { 244 /** 245 * Invoked when a particular key settings changes. 246 * 247 * @param key Key that was changed. 248 * @param newValue New value that was assigned to the key. 249 */ onSettingsChanged(@onNull Key<T> key, @Nullable T newValue)250 void onSettingsChanged(@NonNull Key<T> key, @Nullable T newValue); 251 } 252 WifiSettingsConfigStore(@onNull Context context, @NonNull Handler handler, @NonNull SettingsMigrationDataHolder settingsMigrationDataHolder, @NonNull WifiConfigManager wifiConfigManager, @NonNull WifiConfigStore wifiConfigStore)253 public WifiSettingsConfigStore(@NonNull Context context, @NonNull Handler handler, 254 @NonNull SettingsMigrationDataHolder settingsMigrationDataHolder, 255 @NonNull WifiConfigManager wifiConfigManager, 256 @NonNull WifiConfigStore wifiConfigStore) { 257 mContext = context; 258 mHandler = handler; 259 mSettingsMigrationDataHolder = settingsMigrationDataHolder; 260 mWifiConfigManager = wifiConfigManager; 261 262 // Register our data store. 263 wifiConfigStore.registerStoreData(new StoreData()); 264 } 265 getAllKeys()266 public ArrayList<Key> getAllKeys() { 267 return sKeys; 268 } 269 getAllBackupRestoreKeys()270 public List<Key> getAllBackupRestoreKeys() { 271 return sBackupRestoreKeys; 272 } 273 invokeAllListeners()274 private void invokeAllListeners() { 275 synchronized (mLock) { 276 for (Key key : sKeys) { 277 invokeListeners(key); 278 } 279 } 280 } 281 invokeListeners(@onNull Key<T> key)282 private <T> void invokeListeners(@NonNull Key<T> key) { 283 synchronized (mLock) { 284 if (!mSettings.containsKey(key.key)) return; 285 Object newValue = mSettings.get(key.key); 286 Map<OnSettingsChangedListener, Handler> listeners = mListeners.get(key.key); 287 if (listeners == null || listeners.isEmpty()) return; 288 for (Map.Entry<OnSettingsChangedListener, Handler> listener 289 : listeners.entrySet()) { 290 // Trigger the callback in the appropriate handler. 291 listener.getValue().post(() -> 292 listener.getKey().onSettingsChanged(key, newValue)); 293 } 294 } 295 } 296 297 /** 298 * Trigger config store writes and invoke listeners in the main wifi service looper's handler. 299 */ triggerSaveToStoreAndInvokeAllListeners()300 private void triggerSaveToStoreAndInvokeAllListeners() { 301 mHandler.post(() -> { 302 mHasNewDataToSerialize = true; 303 mWifiConfigManager.saveToStore(); 304 305 invokeAllListeners(); 306 }); 307 } 308 309 /** 310 * Trigger config store writes and invoke listeners in the main wifi service looper's handler. 311 */ triggerSaveToStoreAndInvokeListeners(@onNull Key<T> key)312 private <T> void triggerSaveToStoreAndInvokeListeners(@NonNull Key<T> key) { 313 mHandler.post(() -> { 314 mHasNewDataToSerialize = true; 315 mWifiConfigManager.saveToStore(); 316 317 invokeListeners(key); 318 }); 319 } 320 321 /** 322 * Performs a one time migration from Settings.Global values to settings store. Only 323 * performed one time if the settings store is empty. 324 */ migrateFromSettingsIfNeeded()325 private void migrateFromSettingsIfNeeded() { 326 if (!mSettings.isEmpty()) return; // already migrated. 327 328 mCachedMigrationData = mSettingsMigrationDataHolder.retrieveData(); 329 if (mCachedMigrationData == null) { 330 Log.e(TAG, "No settings data to migrate"); 331 return; 332 } 333 Log.i(TAG, "Migrating data out of settings to shared preferences"); 334 335 mSettings.put(WIFI_P2P_DEVICE_NAME.key, 336 mCachedMigrationData.getP2pDeviceName()); 337 mSettings.put(WIFI_P2P_PENDING_FACTORY_RESET.key, 338 mCachedMigrationData.isP2pFactoryResetPending()); 339 mSettings.put(WIFI_SCAN_ALWAYS_AVAILABLE.key, 340 mCachedMigrationData.isScanAlwaysAvailable()); 341 mSettings.put(WIFI_SCAN_THROTTLE_ENABLED.key, 342 mCachedMigrationData.isScanThrottleEnabled()); 343 mSettings.put(WIFI_VERBOSE_LOGGING_ENABLED.key, 344 mCachedMigrationData.isVerboseLoggingEnabled()); 345 triggerSaveToStoreAndInvokeAllListeners(); 346 } 347 348 /** 349 * Store a value to the stored settings. 350 * 351 * @param key One of the settings keys. 352 * @param value Value to be stored. 353 */ put(@onNull Key<T> key, @Nullable T value)354 public <T> void put(@NonNull Key<T> key, @Nullable T value) { 355 synchronized (mLock) { 356 mSettings.put(key.key, value); 357 } 358 triggerSaveToStoreAndInvokeListeners(key); 359 } 360 361 /** 362 * Retrieve a value from the stored settings. 363 * 364 * @param key One of the settings keys. 365 * @return value stored in settings, defValue if the key does not exist. 366 */ get(@onNull Key<T> key)367 public @Nullable <T> T get(@NonNull Key<T> key) { 368 synchronized (mLock) { 369 return (T) mSettings.getOrDefault(key.key, key.defaultValue); 370 } 371 } 372 373 /** 374 * Register for settings change listener. 375 * 376 * @param key One of the settings keys. 377 * @param listener Listener to be registered. 378 * @param handler Handler to post the listener 379 */ registerChangeListener(@onNull Key<T> key, @NonNull OnSettingsChangedListener<T> listener, @NonNull Handler handler)380 public <T> void registerChangeListener(@NonNull Key<T> key, 381 @NonNull OnSettingsChangedListener<T> listener, @NonNull Handler handler) { 382 synchronized (mLock) { 383 mListeners.computeIfAbsent( 384 key.key, ignore -> new HashMap<>()).put(listener, handler); 385 } 386 } 387 388 /** 389 * Unregister for settings change listener. 390 * 391 * @param key One of the settings keys. 392 * @param listener Listener to be unregistered. 393 */ unregisterChangeListener(@onNull Key<T> key, @NonNull OnSettingsChangedListener<T> listener)394 public <T> void unregisterChangeListener(@NonNull Key<T> key, 395 @NonNull OnSettingsChangedListener<T> listener) { 396 synchronized (mLock) { 397 Map<OnSettingsChangedListener, Handler> listeners = mListeners.get(key.key); 398 if (listeners == null || listeners.isEmpty()) { 399 Log.e(TAG, "No listeners for " + key); 400 return; 401 } 402 if (listeners.remove(listener) == null) { 403 Log.e(TAG, "Unknown listener for " + key); 404 } 405 } 406 } 407 408 /** 409 * Dump output for debugging. 410 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)411 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 412 pw.println(); 413 pw.println("Dump of " + TAG); 414 pw.println("Settings:"); 415 for (Map.Entry<String, Object> entry : mSettings.entrySet()) { 416 pw.print(entry.getKey()); 417 pw.print("="); 418 pw.println(entry.getValue()); 419 } 420 if (mCachedMigrationData == null) return; 421 pw.println("Migration data:"); 422 pw.print(WIFI_P2P_DEVICE_NAME.key); 423 pw.print("="); 424 pw.println(mCachedMigrationData.getP2pDeviceName()); 425 pw.print(WIFI_P2P_PENDING_FACTORY_RESET.key); 426 pw.print("="); 427 pw.println(mCachedMigrationData.isP2pFactoryResetPending()); 428 pw.print(WIFI_SCAN_ALWAYS_AVAILABLE.key); 429 pw.print("="); 430 pw.println(mCachedMigrationData.isScanAlwaysAvailable()); 431 pw.print(WIFI_SCAN_THROTTLE_ENABLED.key); 432 pw.print("="); 433 pw.println(mCachedMigrationData.isScanThrottleEnabled()); 434 pw.print(WIFI_VERBOSE_LOGGING_ENABLED.key); 435 pw.print("="); 436 pw.println(mCachedMigrationData.isVerboseLoggingEnabled()); 437 pw.println(); 438 } 439 440 /** 441 * Base class to store string key and its default value. 442 * @param <T> Type of the value. 443 */ 444 public static class Key<T> { 445 public final String key; 446 public final T defaultValue; 447 Key(@onNull String key, T defaultValue)448 private Key(@NonNull String key, T defaultValue) { 449 this.key = key; 450 this.defaultValue = defaultValue; 451 sKeys.add(this); 452 } 453 454 @VisibleForTesting getKey()455 public String getKey() { 456 return key; 457 } 458 459 @Override toString()460 public String toString() { 461 return "[Key " + key + ", DefaultValue: " + defaultValue + "]"; 462 } 463 464 @Override equals(Object o)465 public boolean equals(Object o) { 466 if (o == this) { 467 return true; 468 } 469 470 // null instanceof [type]" also returns false 471 if (!(o instanceof Key)) { 472 return false; 473 } 474 475 Key anotherKey = (Key) o; 476 return Objects.equals(key, anotherKey.key) 477 && Objects.equals(defaultValue, anotherKey.defaultValue); 478 } 479 480 @Override hashCode()481 public int hashCode() { 482 return Objects.hash(key, defaultValue); 483 } 484 } 485 486 /** 487 * Store data for persisting the settings data to config store. 488 */ 489 public class StoreData implements WifiConfigStore.StoreData { 490 public static final String XML_TAG_SECTION_HEADER = "Settings"; 491 public static final String XML_TAG_VALUES = "Values"; 492 493 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)494 public void serializeData(XmlSerializer out, 495 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 496 throws XmlPullParserException, IOException { 497 synchronized (mLock) { 498 XmlUtil.writeNextValue(out, XML_TAG_VALUES, mSettings); 499 } 500 } 501 502 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)503 public void deserializeData(XmlPullParser in, int outerTagDepth, 504 @WifiConfigStore.Version int version, 505 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 506 throws XmlPullParserException, IOException { 507 if (in == null) { 508 // Empty read triggers the migration since it indicates that there is no settings 509 // data stored in the settings store. 510 migrateFromSettingsIfNeeded(); 511 return; 512 } 513 Map<String, Object> values = deserializeSettingsData(in, outerTagDepth); 514 if (values != null) { 515 synchronized (mLock) { 516 mSettings.putAll(values); 517 // Invoke all the registered listeners. 518 invokeAllListeners(); 519 } 520 } 521 } 522 523 /** 524 * Parse out the wifi settings from the input xml stream. 525 */ deserializeSettingsData( XmlPullParser in, int outerTagDepth)526 public static Map<String, Object> deserializeSettingsData( 527 XmlPullParser in, int outerTagDepth) 528 throws XmlPullParserException, IOException { 529 Map<String, Object> values = null; 530 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 531 String[] valueName = new String[1]; 532 Object value = XmlUtil.readCurrentValue(in, valueName); 533 if (TextUtils.isEmpty(valueName[0])) { 534 throw new XmlPullParserException("Missing value name"); 535 } 536 switch (valueName[0]) { 537 case XML_TAG_VALUES: 538 values = (Map) value; 539 break; 540 default: 541 Log.w(TAG, "Ignoring unknown tag under " + XML_TAG_SECTION_HEADER + ": " 542 + valueName[0]); 543 break; 544 } 545 } 546 return values; 547 } 548 549 @Override resetData()550 public void resetData() { 551 synchronized (mLock) { 552 mSettings.clear(); 553 } 554 } 555 556 @Override hasNewDataToSerialize()557 public boolean hasNewDataToSerialize() { 558 return mHasNewDataToSerialize; 559 } 560 561 @Override getName()562 public String getName() { 563 return XML_TAG_SECTION_HEADER; 564 } 565 566 @Override getStoreFileId()567 public @WifiConfigStore.StoreFileId int getStoreFileId() { 568 // Shared general store. 569 return WifiConfigStore.STORE_FILE_SHARED_GENERAL; 570 } 571 } 572 } 573