• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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