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