1 /*
2  * Copyright (C) 2015 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.net.wifi.ScanResult;
20 import android.net.wifi.WifiConfiguration;
21 import android.os.UserHandle;
22 import android.text.TextUtils;
23 
24 import androidx.annotation.NonNull;
25 
26 import com.android.server.wifi.util.WifiPermissionsUtil;
27 
28 import java.io.FileDescriptor;
29 import java.io.PrintWriter;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.Map;
34 
35 public class ConfigurationMap {
36     private final Map<Integer, WifiConfiguration> mPerID = new HashMap<>();
37 
38     private final Map<Integer, WifiConfiguration> mPerIDForCurrentUser = new HashMap<>();
39     private final Map<ScanResultMatchInfo, WifiConfiguration>
40             mScanResultMatchInfoMapForCurrentUser = new HashMap<>();
41 
42     @NonNull private final WifiPermissionsUtil mWifiPermissionsUtil;
43 
44     private int mCurrentUserId = UserHandle.SYSTEM.getIdentifier();
45 
ConfigurationMap(@onNull WifiPermissionsUtil wifiPermissionsUtil)46     ConfigurationMap(@NonNull WifiPermissionsUtil wifiPermissionsUtil) {
47         mWifiPermissionsUtil = wifiPermissionsUtil;
48     }
49 
50     /** Dump internal state for debugging. */
dump(FileDescriptor fd, PrintWriter pw, String[] args)51     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
52         pw.println("mPerId=" + mPerID);
53         pw.println("mPerIDForCurrentUser=" + mPerIDForCurrentUser);
54         pw.println("mScanResultMatchInfoMapForCurrentUser="
55                 + mScanResultMatchInfoMapForCurrentUser);
56         pw.println("mCurrentUserId=" + mCurrentUserId);
57     }
58 
59     // RW methods:
put(WifiConfiguration config)60     public WifiConfiguration put(WifiConfiguration config) {
61         final WifiConfiguration current = mPerID.put(config.networkId, config);
62         if (config.shared || mWifiPermissionsUtil
63                 .doesUidBelongToCurrentUserOrDeviceOwner(config.creatorUid)) {
64             mPerIDForCurrentUser.put(config.networkId, config);
65             // TODO (b/142035508): Add a more generic fix. This cache should only hold saved
66             // networks.
67             if (!config.fromWifiNetworkSpecifier && !config.fromWifiNetworkSuggestion
68                     && !config.isPasspoint()) {
69                 mScanResultMatchInfoMapForCurrentUser.put(
70                         ScanResultMatchInfo.fromWifiConfiguration(config), config);
71             }
72         }
73         return current;
74     }
75 
remove(int netID)76     public WifiConfiguration remove(int netID) {
77         WifiConfiguration config = mPerID.remove(netID);
78         if (config == null) {
79             return null;
80         }
81 
82         mPerIDForCurrentUser.remove(netID);
83 
84         Iterator<Map.Entry<ScanResultMatchInfo, WifiConfiguration>> scanResultMatchInfoEntries =
85                 mScanResultMatchInfoMapForCurrentUser.entrySet().iterator();
86         while (scanResultMatchInfoEntries.hasNext()) {
87             if (scanResultMatchInfoEntries.next().getValue().networkId == netID) {
88                 scanResultMatchInfoEntries.remove();
89                 break;
90             }
91         }
92         return config;
93     }
94 
clear()95     public void clear() {
96         mPerID.clear();
97         mPerIDForCurrentUser.clear();
98         mScanResultMatchInfoMapForCurrentUser.clear();
99     }
100 
101     /**
102      * Sets the new foreground user ID.
103      *
104      * @param userId the id of the new foreground user
105      */
setNewUser(int userId)106     public void setNewUser(int userId) {
107         mCurrentUserId = userId;
108     }
109 
110     // RO methods:
getForAllUsers(int netid)111     public WifiConfiguration getForAllUsers(int netid) {
112         return mPerID.get(netid);
113     }
114 
getForCurrentUser(int netid)115     public WifiConfiguration getForCurrentUser(int netid) {
116         return mPerIDForCurrentUser.get(netid);
117     }
118 
sizeForAllUsers()119     public int sizeForAllUsers() {
120         return mPerID.size();
121     }
122 
sizeForCurrentUser()123     public int sizeForCurrentUser() {
124         return mPerIDForCurrentUser.size();
125     }
126 
getByConfigKeyForCurrentUser(String key)127     public WifiConfiguration getByConfigKeyForCurrentUser(String key) {
128         if (key == null) {
129             return null;
130         }
131         for (WifiConfiguration config : mPerIDForCurrentUser.values()) {
132             if (TextUtils.equals(config.getProfileKey(), key)) {
133                 return config;
134             }
135         }
136         return null;
137     }
138 
139     /**
140      * Retrieves the |WifiConfiguration| object matching the provided |scanResult| from the internal
141      * map.
142      * Essentially checks if network config and scan result have the same SSID and encryption type.
143      */
getByScanResultForCurrentUser(ScanResult scanResult)144     public WifiConfiguration getByScanResultForCurrentUser(ScanResult scanResult) {
145         return mScanResultMatchInfoMapForCurrentUser.get(
146                 ScanResultMatchInfo.fromScanResult(scanResult));
147     }
148 
valuesForAllUsers()149     public Collection<WifiConfiguration> valuesForAllUsers() {
150         return mPerID.values();
151     }
152 
valuesForCurrentUser()153     public Collection<WifiConfiguration> valuesForCurrentUser() {
154         return mPerIDForCurrentUser.values();
155     }
156 }
157