• 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.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