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